如何在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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你的PitchDetector的实现是怎样的?报错日志分析是哪里、是什么异常都知道了吗?你得把问题关键点描述的更清楚一点。
用线程池来吧
用异步任务就不会这么麻烦了
线程的run方法执行完毕后,线程就会自动停止
如果线程的run方法中是个定时循环,那么需要通过调用方法设置标志信息,例如canstop,但是设置完这个标志信息后,线程不会马上停止,等下一次循环到来时先check这个标志位是否满足线程退出条件,如果OK,那么线程就可以安全退出