首页 > 如何在Java中正确、安全地启动及关闭Thread?

如何在Java中正确、安全地启动及关闭Thread?

当我启动或关闭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("Individual 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


用线程池来吧


线程的run方法执行完毕后,线程就会自动停止
如果线程的run方法中是个定时循环,那么需要通过调用方法设置标志信息,例如canstop,但是设置完这个标志信息后,线程不会马上停止,等下一次循环到来时先check这个标志位是否满足线程退出条件,如果OK,那么线程就可以安全退出


你的PitchDetector的实现是怎样的?报错日志分析是哪里、是什么异常都知道了吗?你得把问题关键点描述的更清楚一点。


用异步任务就不会这么麻烦了

【热门文章】
【热门文章】