android - 如何在Java中正确、安全地启动及关闭Thread?
高洛峰
高洛峰 2017-04-17 17:56:07
0
4
713

当我启动或关闭Thread的时候几乎每次都会出现闪退现象,感觉就是看运气,这次只是加了个判断thread是否为null就完全呵呵了。没有系统地去学习过thread(唉,真是)。

下面是一些相关代码:(线程是pitch_detector_thread_)
SheetPage.java

package com.fyp.flipfreely;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.widget.ViewFlipper;

import com.example.AndroidTuner.PitchDetector;
import com.fyp.fileIO.mXMLReader;
import com.fyp.midi.MidiDriver;
import com.fyp.midi.SimpleAnalysis;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import jm.music.data.Score;


/**
 * A simple {@link Fragment} subclass.
 *
 */
public class SheetPage extends Activity implements OnGestureListener,OnClickListener,
MidiDriver.OnMidiStartListener {

    protected MidiDriver midi;
    protected MediaPlayer player;

    /*SimpleOnGestureListener可以用来只复写自己想要的手势,从而避免垃圾代码*/
    private ViewFlipper sheetFlipper;
    private GestureDetector detector;
    private String title="";

    //three tab, each button for each tab
      private LinearLayout mTabSearch;
      private LinearLayout mTabCollection;
      private LinearLayout mTabSetting;
      private LinearLayout mTabCollect;
      private LinearLayout mTabPlay;
    private Button mTabStart;

      private SearchPage searchF;
    private SettingPage settingF;
    private CollectionPage collectionF;

    private Score s=new Score();
    private String directoryName="SmartSheet";
    private String dirRoot = Environment.getExternalStorageDirectory().getAbsolutePath()
            + File.separator+directoryName+File.separator;
    private String temptitle="";

    int[] pitches=null;
    int[] tmp=null;/*store the pitch from the real-time sound*/
    int correctHit=0;
    int counter=0;
    int totalHits=0;
    private static final int advance=4;/*提前四个音翻页*/
    private static double accuracy=0.999;
    private static int speed=50;
    private static boolean auto=true;

    Thread pitch_detector_thread_;


//    private String[] collectionArray;//用来获取arrays中的数据之后进行数据的添加

    public SheetPage() {
        // Required empty public constructor
    }
    private void init() throws IOException {
        mXMLReader xmlReader=new mXMLReader();
        Map<String,String> map=new HashMap<String,String>();
        map=xmlReader.getSystemInitInfo();
        accuracy=Double.valueOf(map.get("accuracy"));
        speed=Integer.valueOf(map.get("speed"));
        auto=Boolean.valueOf(map.get("automation"));
    }

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sheet_page);

        try {
            init();
        } catch (IOException e) {
            e.printStackTrace();
        }

//        Toast.makeText(SheetPage.this,"zsdd", Toast.LENGTH_SHORT).show();

        Intent intent= getIntent();
        Bundle b = intent.getExtras();

        if(b!=null)
        {
            title =(String) b.get("title");
        }

        // 初始化控件和声明事件
        mTabSearch = (LinearLayout) findViewById(R.id.searchTab);
        mTabCollection = (LinearLayout) findViewById(R.id.collectionTab);
        mTabSetting = (LinearLayout) findViewById(R.id.settingTab);
        mTabCollect = (LinearLayout) findViewById(R.id.collectBtn);
        mTabPlay = (LinearLayout) findViewById(R.id.playBtn);
        mTabStart = (Button) findViewById(R.id.startBtn);

        mTabSearch.setOnClickListener(this);
        mTabCollection.setOnClickListener(this);
        mTabSetting.setOnClickListener(this);
        mTabCollect.setOnClickListener(this);
        mTabPlay.setOnClickListener(this);
        mTabStart.setOnClickListener(this);

        if(auto){
            mTabStart.setEnabled(true);
        }else{

            mTabStart.setEnabled(false);
        }

        detector = new GestureDetector(this);
        sheetFlipper = (ViewFlipper) this.findViewById(R.id.sheetFlipper);

        /*initialize the title of the midi file to be found*/
        //TODO unfinished function here. Only two pages can be added here.
        temptitle=title.toLowerCase();
        temptitle=temptitle.replaceAll(" ","_");
        sheetFlipper.addView(addImageView(getResourceId(temptitle,"drawable")));/*change to pages, rather than one page*/
        sheetFlipper.addView(addImageView(getResourceId("finish","drawable")));

        /*获取Accuracy的阈值*/
//        String acc=SettingPage.defaultAccuracy;
//        if(acc.equals("Low")){
//            accuracy=10.0;
//        }else if(acc.equals("Medium")){
//            accuracy=8.0;
//        }else if(acc.equals("High")){
//            accuracy=5.0;
//        }

        try {
            /*Create directory if there doesn't exist one*/
            createDir(dirRoot);
            String fileName=temptitle+".mid";
            String filePath=dirRoot+fileName;
            /*Create midi file refers to filePath*/
            File midiFile=new File(filePath);
            InputStream input = this.getAssets().open(fileName);//打开这个midi的stream。
            /*Convert InputStream to File*/
            inputstreamtofile(input,midiFile);


            StringBuffer resultStringBuffer = new StringBuffer();
            String lineToRead = "";
            int exitValue = 0;
            Process proc = Runtime.getRuntime().exec("perl midi2chord.pl -v -s120,5,5 "+fileName);
            InputStream inputStream = proc.getInputStream();
            BufferedReader bufferedRreader = new BufferedReader(new InputStreamReader(inputStream));

            // save first line
            if ((lineToRead = bufferedRreader.readLine()) != null) {
                resultStringBuffer.append(lineToRead);
            }

            // save next lines
            while ((lineToRead = bufferedRreader.readLine()) != null) {
                resultStringBuffer.append("\r\n");
                resultStringBuffer.append(lineToRead);
            }

            // Always reading STDOUT first, then STDERR, exitValue last
            proc.waitFor(); // wait for reading STDOUT and STDERR over
            exitValue = proc.exitValue();
            System.out.print(resultStringBuffer);



            /*Analysis midi file and get pitches*/
            SimpleAnalysis sa;
            sa=new SimpleAnalysis(filePath);
            s=sa.getScore();
            totalHits=sa.getPitches().length;
            /*initialize the pitch array*/
            pitches=new int[totalHits];
            pitches=sa.getPitches();
//            for (int i=0;i<totalHits;i++){
//                System.out.println(pitches[i]);
//            }
            /*initialize the tmp array*/
            tmp=new int[totalHits];

            pitch_detector_thread_ = new Thread(new PitchDetector(this, new Handler()));
            
            /*get track information*/
//            /*Create MidiFile*/
//            MidiFile midi = new MidiFile(midiFile);
//            
//            // Create a new MidiProcessor:
//            MidiProcessor processor = new MidiProcessor(midi);
//            
//            // Register for the events you're interested in:
//            EventPrinter ep2 = new EventPrinter("Inpidual Listener");
//            processor.registerEventListener(ep2, NoteOn.class);
//            
//            // Start the processor:
//            processor.start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public int  getResourceId(String resName,String docName){
        /*get resource's id*/
        Context ctx=getBaseContext();
        int resId = getResources().getIdentifier(resName, docName , ctx.getPackageName());
        return resId;
    }

    private View addImageView(int id) {
        ImageView iv = new ImageView(this);
        iv.setImageResource(id);
        return iv;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // TODO Auto-generated method stub
        return this.detector.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        if (e1.getX() - e2.getX() > 90) {
            this.sheetFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in));
            this.sheetFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out));
            this.sheetFlipper.showNext();
            return true;
        } else if (e1.getX() - e2.getX() < -90) {
            this.sheetFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_out));
            this.sheetFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_right_in));
            this.sheetFlipper.showPrevious();
            return true;
        }

        return false;
    }


    @Override
    public void onLongPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {
        // TODO Auto-generated method stub

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void onClick(View v) {
        // Obtain FragmentManager object
        FragmentManager fm = getFragmentManager();
        // Start Fragment event
        FragmentTransaction transaction = fm.beginTransaction();
        Intent intent = new Intent();

        switch (v.getId())
        {
            case R.id.startBtn:
                //when music is on, close the music first.
                if (player != null)
                {
                    player.stop();
                    player.release();
                    player=null;
                }


                if(!pitch_detector_thread_.isAlive()) {
                    pitch_detector_thread_.start();
                }else if(pitch_detector_thread_.isInterrupted()){
                    pitch_detector_thread_.run();
                }

                break;
            case R.id.searchTab:
                if (searchF == null)
                {
                    searchF = new SearchPage();
                }
                intent.putExtra("tab", "search");
                intent.setClass(this, MainActivity.class);
                startActivity(intent);
                finish();/*finish the sheetPage activity*/
                break;
            case R.id.collectionTab:
                if (collectionF == null)
                {
                    collectionF = new CollectionPage();
                }
                intent.putExtra("tab", "collection");
                intent.setClass(this, MainActivity.class);
                startActivity(intent);
                finish();
                break;
            case R.id.settingTab:
                if (settingF == null)
                {
                    settingF = new SettingPage();
                }
                intent.putExtra("tab", "setting");
                intent.setClass(this, MainActivity.class);
                startActivity(intent);
                finish();
                break;
            case R.id.playBtn:
                if (player != null)
                {
                    player.stop();
                    player.release();
                    player=null;
                }else{
                //A MediaPlayer element can play midi by using a method MediaPlayer.create(Activity,midi Id);
                    if(pitch_detector_thread_.isAlive()){
                        pitch_detector_thread_.interrupt();
                    }
                    /*play the midi file*/
                    player = MediaPlayer.create(this, getResourceId(temptitle,"raw"));
                    player.start();
                    //Play.midi(s);
                }
                break;
            case R.id.collectBtn:break;
        }

        // transaction.addToBackStack();
        // ??????
        transaction.commit();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
    }

/*Real-time Thread*/

    @Override
    public void onStop() {
        super.onStop();
        //sometimes work
        if(pitch_detector_thread_!=null) {
            if (pitch_detector_thread_.isAlive()) {
                pitch_detector_thread_.interrupt();
                pitch_detector_thread_ = null;
            }
        }
    }
/*Midi Player Stuffs*/
    // On resume

    @Override
    protected void onResume()
    {
        super.onResume();

        // Start midi

        if (midi != null)
            midi.start();
    }

    // On pause

    @Override
    protected void onPause()
    {
        super.onPause();

        // Stop midi

        if (midi != null)
            midi.stop();

        // Stop player

        if (player != null)
            player.stop();


        //sometimes work
        if(pitch_detector_thread_!=null) {
            if (pitch_detector_thread_.isAlive()) {
                pitch_detector_thread_.interrupt();
                pitch_detector_thread_ = null;
            }
        }
    }

    @Override
    public void onMidiStart() {
        sendMidi(0xc0, 6);
    }

    // Send a midi message

    protected void sendMidi(int m, int p)
    {
    byte msg[] = new byte[2];

    msg[0] = (byte) m;
    msg[1] = (byte) p;

    midi.write(msg);
    }

    // Send a midi message

    protected void sendMidi(int m, int n, int v)
    {
    byte msg[] = new byte[3];

    msg[0] = (byte) m;
    msg[1] = (byte) n;
    msg[2] = (byte) v;

    midi.write(msg);
    }


    public void inputstreamtofile(InputStream ins,File file) throws IOException{

        OutputStream os = new FileOutputStream(file);
        int bytesRead = 0;
        byte[] buffer = new byte[8192];
        while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
    }

    public static boolean createDir(String destDirName) {
        File dir = new File(destDirName);
        if (dir.exists()) {
//            System.out.println("Create directory " + destDirName + " Failed, directory already exists");
            return false;
        }
        if (!destDirName.endsWith(File.separator)) {
            destDirName = destDirName + File.separator;
        }
        //??????
        if (dir.mkdirs()) {
//            System.out.println("Create directory " + destDirName + " Successfully");
            return true;
        } else {
//            System.out.println("Create directory " + destDirName + " Failed");
            return false;
        }
    }
 
    public void ShowPitchDetectionResult(double pitch)
    {
        double frequency=Math.round(pitch * 10) / 10.0;
        int p=0;
        if(frequency>120){
            p=FrequencyToPitch(frequency);
            Toast.makeText(SheetPage.this,p+"", Toast.LENGTH_SHORT).show();
            if(counter<totalHits){
                tmp[counter]=p;
                counter++;
            }else{
                double sim=0;
                sim=getCosineSimilarity(pitches, tmp);
                if(sim>=accuracy){
                    this.sheetFlipper.setOutAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_out));
                    this.sheetFlipper.setInAnimation(AnimationUtils.loadAnimation(this, R.anim.push_left_in));
                    this.sheetFlipper.showNext();
                    Toast.makeText(SheetPage.this,"Finish Playing, Sim="+sim, Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(SheetPage.this,"Fail to flipped, Sim="+sim, Toast.LENGTH_SHORT).show();
                }
                tmp=null;
                tmp=new int[totalHits];
                counter=0;

                if(pitch_detector_thread_.isAlive()) {
                    pitch_detector_thread_.interrupt();
                }
            }
        }
    }

    public int FrequencyToPitch(double frenquence){
        int pitch=0;
        pitch=(int)Math.round((69+12*Math.log(frenquence/440)/Math.log((double)2)));
        return pitch;
    }

    /**
     * 两个向量可以为任意维度,但必须保持维度相同,表示n维度中的两点,获取欧几里德距离
     * @param s1
     * @param s2
     * @return 两点间距离
     * */
    public double getEuclideanDistance(int[] s1, int[] s2) {
        double distance = 0;
        if (s1.length == s2.length) {
            for (int i = 0; i < s1.length; i++) {
                double temp = Math.pow((s1[i] - s2[i]), 2);
                distance += temp;
            }
            distance = Math.sqrt(distance);
        }
        return distance;
    }

    public double getCosineSimilarity(int[] s1,int[] s2){
        double similarity=0;
        double topNum=0;
        double bottomA=0;
        double bottomB=0;
        if(s1.length==s2.length){
            for(int i=0;i<s1.length;i++){
                topNum+=s1[i]*s2[i];

                bottomA+=Math.pow(s1[i],2);

                bottomB+=Math.pow(s2[i],2);
            }
            similarity=topNum/(Math.sqrt(bottomA)*Math.sqrt(bottomB));
        }
        return similarity;
    }
}

PitchDetection代码:

/** Copyright (C) 2009 by Aleksey Surkov.
 **
 ** Permission to use, copy, modify, and distribute this software and its
 ** documentation for any purpose and without fee is hereby granted, provided
 ** that the above copyright notice appear in all copies and that both that
 ** copyright notice and this permission notice appear in supporting
 ** documentation.  This software is provided "as is" without express or
 ** implied warranty.
 */

package com.example.AndroidTuner;

import android.app.AlertDialog;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder.AudioSource;
import android.os.Handler;
import android.util.Log;

import com.fyp.flipfreely.SheetPage;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class PitchDetector implements Runnable {
    private static String LOG_TAG = "PitchDetector";

    // Currently, only this combination of rate, encoding and channel mode
    // actually works.
    private final static int RATE = 8000;
    private final static int CHANNEL_MODE = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    private final static int ENCODING = AudioFormat.ENCODING_PCM_16BIT;

    private final static int BUFFER_SIZE_IN_MS = 3000;
    private final static int CHUNK_SIZE_IN_SAMPLES = 4096; // = 2 ^
                                                            // CHUNK_SIZE_IN_SAMPLES_POW2
    private final static int CHUNK_SIZE_IN_MS = 1000 * CHUNK_SIZE_IN_SAMPLES
            / RATE;
    private final static int BUFFER_SIZE_IN_BYTES = RATE * BUFFER_SIZE_IN_MS
            / 1000 * 2;
    private final static int CHUNK_SIZE_IN_BYTES = RATE * CHUNK_SIZE_IN_MS
            / 1000 * 2;

    private final static int MIN_FREQUENCY = 49; // 49.0 HZ of G1 - lowest note
                                                    // for crazy Russian choir.
    private final static int MAX_FREQUENCY = 1568; // 1567.98 HZ of G6 - highest
                                                    // demanded note in the
                                                    // classical repertoire

    private final static int DRAW_FREQUENCY_STEP = 5;

    public native void DoFFT(double[] data, int size); // an NDK library
                                                        // 'fft-jni'

    public PitchDetector(SheetPage parent, Handler handler) {

        parent_ = parent;
        handler_ = handler;
        System.loadLibrary("fft-jni");
    }

    private static class FreqResult {
        public HashMap<Double, Double> frequencies;
        public double best_frequency;
    }

    public static class FrequencyCluster {
        public double average_frequency = 0;
        public double total_amplitude = 0;
        
        public void add(double freq, double amplitude) {
            double new_total_amp = total_amplitude + amplitude;
            average_frequency = (total_amplitude * average_frequency + freq * amplitude) / new_total_amp;
            total_amplitude = new_total_amp;
        }
        
        public boolean isNear(double freq) {
            if (Math.abs(1 - (average_frequency / freq)) < 0.05) {
                // only 5% difference
                return true;
            } else {
                return false;
            }
        }
        
        public boolean isHarmonic(double freq) {
            double harmonic_factor = freq / average_frequency;
            double distance_from_int = Math.abs(Math.round(harmonic_factor) - harmonic_factor);
            if (distance_from_int < 0.05) {
                // only 5% distance
                return true;
            } else {
                return false;
            }            
        }

        public void addHarmony(double freq, double amp) {
            total_amplitude += amp;
        }
        
        @Override public String toString() {
            return "(" + average_frequency + ", " + total_amplitude + ")";
        }
    }

    
    public FreqResult AnalyzeFrequencies(short[] audio_data) {
        FreqResult fr = new FreqResult();

        double[] data = new double[CHUNK_SIZE_IN_SAMPLES * 2];
        final int min_frequency_fft = Math.round(MIN_FREQUENCY
                * CHUNK_SIZE_IN_SAMPLES / RATE);
        final int max_frequency_fft = Math.round(MAX_FREQUENCY
                * CHUNK_SIZE_IN_SAMPLES / RATE);

        for (int i = 0; i < CHUNK_SIZE_IN_SAMPLES; i++) {
            data[i * 2] = audio_data[i];
            data[i * 2 + 1] = 0;
        }
        DoFFT(data, CHUNK_SIZE_IN_SAMPLES);

        double best_frequency = min_frequency_fft;
        HashMap<Double, Double> frequencies = new HashMap<Double, Double>();

        //best_frequency = min_frequency_fft;
        //fr.frequencies = new HashMap<Double, Double>();

        double best_amplitude = 0;
        final double draw_frequency_step = 1.0 * RATE / CHUNK_SIZE_IN_SAMPLES;
        
        List<Double> best_frequencies = new ArrayList<Double>();
        List<Double> best_amps = new ArrayList<Double>();
        
        for (int i = min_frequency_fft; i <= max_frequency_fft; i++) {

            final double current_frequency = i * 1.0 * RATE
                    / CHUNK_SIZE_IN_SAMPLES;
            final double draw_frequency = Math
                    .round((current_frequency - MIN_FREQUENCY)
                            / DRAW_FREQUENCY_STEP)
                    * DRAW_FREQUENCY_STEP + MIN_FREQUENCY;

            final double current_amplitude = Math.pow(data[i * 2], 2)
                    + Math.pow(data[i * 2 + 1], 2);
            
            final double normalized_amplitude = current_amplitude
                    * Math.pow(MIN_FREQUENCY * MAX_FREQUENCY, 0.5)
                    / current_frequency;

            Double current_sum_for_this_slot = frequencies.get(draw_frequency);
            if (current_sum_for_this_slot == null) {
                current_sum_for_this_slot = 0.0;
            }

            frequencies.put(draw_frequency, Math.pow(current_amplitude, 0.5)
                    / draw_frequency_step + current_sum_for_this_slot);
            
            if (normalized_amplitude > best_amplitude) {
                best_frequency = current_frequency;
                best_amplitude = normalized_amplitude;
                
                best_frequencies.add(current_frequency);
                best_amps.add(best_amplitude);
            }
            // test for harmonics
            // e.g. 220 is a harmonic of 110, so the harmonic factor is 2.0
            // and thus the decimal part is 0.0.
            //        230 isn't a harmonic of 110, the harmonic_factor would be 
            //        2.09 and 0.09 > 0.05
            //double harmonic_factor = current_frequency / best_frequency;
            //if ((best_amplitude == 0) || (harmonic_factor - Math.floor(harmonic_factor) > 0.05)) {
        }

        List<FrequencyCluster> clusters = new ArrayList<FrequencyCluster>();
        FrequencyCluster currentCluster = new FrequencyCluster();
        clusters.add(currentCluster);
        FrequencyCluster bestCluster = currentCluster;
        
        
        if (best_frequencies.size() > 0)
        {
            currentCluster.add(best_frequencies.get(0), best_amps.get(0));
        }
        
        // join clusters
        for(int i = 1; i < best_frequencies.size(); i++)
        {
            double freq = best_frequencies.get(i);
            double amp = best_amps.get(i);
            
            if (currentCluster.isNear(freq)) {
                currentCluster.add(freq, amp);
                continue;
            }
            
            // this isn't near, and isn't harmonic, it's a different one.
            // NOTE: assuming harmonies are consecutive (no unharmonics in between harmonies)
            currentCluster = new FrequencyCluster();
            clusters.add(currentCluster);
            currentCluster.add(freq, amp);
        }
        
        // join harmonies
        FrequencyCluster nextCluster;
        for(int i = 1; i < clusters.size(); i ++) {
            currentCluster = clusters.get(i - 1);
            nextCluster = clusters.get(i);
            if (currentCluster.isHarmonic(nextCluster.average_frequency)) {
                currentCluster.total_amplitude += nextCluster.total_amplitude;
            }
        }
        
        
        best_amplitude = 0;
        best_frequency = 0;
        for(int i = 0; i < clusters.size(); i ++) {
            FrequencyCluster clu = clusters.get(i); 
            if (best_amplitude < clu.total_amplitude) {
                best_amplitude = clu.total_amplitude;
                best_frequency = clu.average_frequency;
            }
        }

        fr.best_frequency = best_frequency;
        fr.frequencies = frequencies;
        
        return fr;
    }

    public void run() {
        Log.e(LOG_TAG, "starting to detect pitch");

        android.os.Process
                .setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
        recorder_ = new AudioRecord(AudioSource.MIC, RATE, CHANNEL_MODE,
                ENCODING, 6144);
        if (recorder_.getState() != AudioRecord.STATE_INITIALIZED) {
            ShowError("Can't initialize AudioRecord");
            return;
        }

        recorder_.startRecording();
        while (!Thread.interrupted()) {
            try{
                short[] audio_data = new short[BUFFER_SIZE_IN_BYTES / 2];
                recorder_.read(audio_data, 0, CHUNK_SIZE_IN_BYTES / 2);
                FreqResult fr = AnalyzeFrequencies(audio_data);
                PostToUI(fr.frequencies, fr.best_frequency);
                Thread.sleep(100);//阻塞过程捕获中断异常来退出,解决了too much output to process问题
            }catch(InterruptedException e){
                e.printStackTrace();
                break;//捕获到异常之后,执行break跳出循环。
            }
        }
        recorder_.stop();
    }

    private void PostToUI(final HashMap<Double, Double> frequencies,
            final double pitch) {
        handler_.post(new Runnable() {
            public void run() {
                /*here is how the pitch transmits to SheetPage*/
//                parent_.ShowPitchDetectionResult(frequencies, pitch);
                parent_.ShowPitchDetectionResult(pitch);
            }
        });
    }

    private void ShowError(final String msg) {
        handler_.post(new Runnable() {
            public void run() {
                new AlertDialog.Builder(parent_).setTitle("GuitarTuner")
                        .setMessage(msg).show();
            }
        });
    }

    private SheetPage parent_;
    private AudioRecord recorder_;
    private Handler handler_;
}

以下是报错内容:

05-19 06:14:36.946 23613-23613/com.fyp.flipfreely E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NullPointerException
                                                            at com.fyp.flipfreely.SheetPage.onClick(SheetPage.java:373)
                                                            at android.view.View.performClick(View.java:4204)
                                                            at android.view.View$PerformClick.run(View.java:17355)
                                                            at android.os.Handler.handleCallback(Handler.java:725)
                                                            at android.os.Handler.dispatchMessage(Handler.java:92)
                                                            at android.os.Looper.loop(Looper.java:137)
                                                            at android.app.ActivityThread.main(ActivityThread.java:5041)
                                                            at java.lang.reflect.Method.invokeNative(Native Method)
                                                            at java.lang.reflect.Method.invoke(Method.java:511)
                                                            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
                                                            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
                                                            at dalvik.system.NativeStart.main(Native Method)

[已解决]多谢chuyao的解答。把解决方法放这给有需要的同志们~
对于thread的操作可以间接地使用一个boolean来判断是否要执行run()里面的代码。
http://stackoverflow.com/questions/10961714/how-to-properly-stop-the-thread-in-java

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

reply all(4)
左手右手慢动作

What is your implementation of PitchDetector? Do you know where the error log analysis is and what the exception is? You need to describe the key points of the problem more clearly.

Peter_Zhu

Use thread pool

洪涛

Using asynchronous tasks will not be so troublesome

左手右手慢动作

After the thread's run method is executed, the thread will automatically stop
If the thread's run method is a timed loop, then you need to set the flag information by calling the method, such as canstop, but after setting this flag information, the thread will not stop immediately , when the next cycle comes, first check whether this flag meets the thread exit condition. If OK, then the thread can exit safely

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template