Android - 如何在另一个活动期间暂停线程?
我有一个线程"reader"
,它读取一个文件并更新列表A.另一个线程"drawer"
读取变量a中的内容,执行某些操作,调用ondraw,然后休眠500ms(在此期间,读者填充A)。Android - 如何在另一个活动期间暂停线程?
我也有一个首选活动,如果我按菜单按钮开始。
的问题是,如果我按按钮的同时读线程还没有完成阅读他的文件,我有恩于logcat的错误。(见下文)
我已经看到了这个问题的读者当它向我显示首选项菜单时正在运行的线程,事实上,如果我等到读者结束,并且我点击了一个首选项,它一切顺利,但是如果我单击它的运行igot时发生错误。
如何处理当我重新启动时仍在运行的线程?我如何"pause"
他们?成为我的文件阅读可以很长,所以我不能等待读者线程结束。
感谢
编辑:为了更精确,什么appens的是,如果我按菜单键,preferenceActivity开始,我看到正确的视图(单选按钮等),但问题是,当我点击在屏幕上的随机点上,它给我错误。如果我等那么读thred结束(我看到它的logcat),然后我点击ARANDOM点,它会everithing好...
logcat的错误:
02-03 10:18:51.196: ERROR/ActivityManager(66): ANR in it.planningpathapp.ale (it.planningpathapp.ale/.Preferences)
02-03 10:18:51.196: ERROR/ActivityManager(66): Reason: keyDispatchingTimedOut
02-03 10:18:51.196: ERROR/ActivityManager(66): Load: 0.7/0.29/0.29
02-03 10:18:51.196: ERROR/ActivityManager(66): CPU usage from 13441ms to 36ms ago:
02-03 10:18:51.196: ERROR/ActivityManager(66): ningpathapp.ale: 82% = 75% user + 7% kernel/faults: 6211 minor 1 major
02-03 10:18:51.196: ERROR/ActivityManager(66): adbd: 16% = 0% user + 15% kernel/faults: 36 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): system_server: 11% = 8% user + 3% kernel/faults: 229 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): logcat: 3% = 1% user + 2% kernel
02-03 10:18:51.196: ERROR/ActivityManager(66): m.android.phone: 0% = 0% user + 0% kernel/faults: 33 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): ronsoft.openwnn: 0% = 0% user + 0% kernel/faults: 30 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): m.android.music: 0% = 0% user + 0% kernel/faults: 52 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): id.defcontainer: 0% = 0% user + 0% kernel/faults: 14 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): com.svox.pico: 0% = 0% user + 0% kernel/faults: 15 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): ndroid.launcher: 0% = 0% user + 0% kernel/faults: 18 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): com.android.mms: 0% = 0% user + 0% kernel/faults: 22 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): m.android.email: 0% = 0% user + 0% kernel/faults: 41 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): android.protips: 0% = 0% user + 0% kernel/faults: 15 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): .quicksearchbox: 0% = 0% user + 0% kernel/faults: 34 minor
02-03 10:18:51.196: ERROR/ActivityManager(66): TOTAL: 99% = 72% user + 20% kernel + 1% irq + 6% softirq
02-03 10:18:51.216: WARN/WindowManager(66): No window to dispatch pointer action 1
public class PathPlanningApp1Activity extends Activity {
private static Object lock=new Object();
//Mie tag per il debug mediante LogCat
private static final String TAG_readFile = "READFILE_thread";
private static final String TAG_draw = "DRAW_Thread";
private static final String TAG_error = "ERROR";
private final HashMap < Integer , vertex > map = new HashMap < Integer , vertex>();
private final LinkedList <vertex> originalPath = new LinkedList <vertex>();
private final LinkedList <vertex> originale = new LinkedList <vertex>();
private final ArrayList <vertex> obstacles = new ArrayList<vertex>();
private final ArrayList <vertex> obstacles_notordered = new ArrayList<vertex>();
private int mapWidth=1;
private int mapHeight=1;
Panel panel;
Resources res;
private Bitmap mBitmap;
private Bitmap obstaclesBmp=Bitmap.createBitmap(2, 2, Bitmap.Config.ARGB_8888);
private float zoom=15;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
res= this.getResources() ;
panel=new Panel(this);
setContentView(panel);
Log.d(getLocalClassName(), "ON CREATE");
}
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
protected void onResume()
{Log.d(getLocalClassName(), "ON RESUME");
setContentView(panel);
super.onResume();
}
protected void onDestroy(){
Log.d(getLocalClassName(), "ON DESTROY");
super.onDestroy();
}
protected void onPause(){
Log.d(getLocalClassName(), "ON PAUSE");
Log.d(getLocalClassName(), "stato drawer" +panel.drawerThread.getState());
Log.d(getLocalClassName(), "stato frt" +panel.frt.getState());
super.onPause();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_launcher: Toast.makeText(this, "You pressed the icon!", Toast.LENGTH_LONG).show();
Intent settingsActivity = new Intent(this,Preferences.class);
startActivity(settingsActivity);
break;
case R.id.text: Toast.makeText(this, "You pressed the text!", Toast.LENGTH_LONG).show();
break;
case R.id.icontext: Toast.makeText(this, "You pressed the icon and text!", Toast.LENGTH_LONG).show();
break;
}
return true;
}
class Panel extends SurfaceView implements SurfaceHolder.Callback{
FileReaderThread frt=new FileReaderThread();
DrawerThread drawerThread ;
public Panel(Context context) {
super(context);
getHolder().addCallback(this);
drawerThread = new DrawerThread(getHolder() , this);
setDrawingCacheEnabled(true);
setFocusable(true);
}
public void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
try{
int i=0;
int height=canvas.getHeight();
int width=canvas.getWidth();
Paint paint = new Paint();
paint.setColor(Color.GREEN);
//Log.d(TAG_draw, " obstaclesBmp="+obstaclesBmp.getHeight());
if (obstaclesBmp != null){
synchronized(obstaclesBmp){
canvas.drawBitmap(obstaclesBmp, 0, 0, null);
}
}
}catch(OutOfMemoryError e){
Log.e(TAG_error, "ONDRAW !!Bitmap troppo grossa !dim:"+mapWidth+" "+mapHeight);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
if(frt.getState()== Thread.State.TERMINATED){
//frt = new FileReaderThread();
// frt.start();
// <-- added fix
}else {
Log.d(TAG_readFile," stato frt "+frt.getState());
frt.setRunning(true);
frt.start();
}
if(drawerThread.getState()==Thread.State.TERMINATED){
drawerThread = new DrawerThread(getHolder() , this);
drawerThread.setRunning(true);
drawerThread.start();
}
else{
drawerThread.setRunning(true);
drawerThread.start();
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
boolean retry = true;
drawerThread.setRunning(false);
while (retry) {
try {
drawerThread.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
retry = true;
frt.setRunning(false);
while (retry) {
try {
frt.join();
retry = false;
} catch (InterruptedException e) {
// we will try it again and again...
}
}
}
}
public class DrawerThread extends Thread {
private SurfaceHolder _surfaceHolder;
private Panel _panel;
private boolean _run = false;
Bitmap oldbmp=null;
Bitmap newbmp=null;
Bitmap obstaclesBmpTmp = null;
int i=0;
int lasti=0;
int oldW=-1,oldH=-1;
public DrawerThread(SurfaceHolder surfaceHolder, Panel panel) {
_surfaceHolder = surfaceHolder;
_panel = panel;
}
public void setRunning(boolean run) {
_run = run;
}
public SurfaceHolder getSurfaceHolder() {
return _surfaceHolder;
}
public void UpdateBmp(){
Log.d(TAG_draw, "Update!");
try{
int provazoom=7;
Paint paint = new Paint();
int mymapWidth=mapWidth;
int mymapHeight=mapHeight;
if(mymapWidth>oldW || mymapHeight>oldH ||oldW<0 || oldH<0){
obstaclesBmpTmp=Bitmap.createBitmap(mymapWidth*provazoom,mymapHeight*provazoom, Bitmap.Config.ARGB_4444);
lasti=0;
Log.d(TAG_draw, "Cambiate dimensioni! "+oldW+" contro "+mymapWidth+" e "+oldH+" contro"+mymapHeight);
oldW=mymapWidth;
oldH=mymapHeight;
}
else{
Log.d(TAG_draw, "Dimensioni uguali! ");
}
Log.d(TAG_draw, "parto dall'index "+lasti);
Canvas tmpCanvas=new Canvas(obstaclesBmpTmp);
//tmpCanvas.drawColor(Color.DKGRAY);
paint.setColor(Color.WHITE);
int corrx=-20;
int corry=10;
for(i=lasti;i<obstacles_notordered.size();i++){
float x=(float)( ((obstacles_notordered.get(i).x) +mymapWidth/2 )*provazoom +corrx );
float y=(float)( ((-1*obstacles_notordered.get(i).y) +mymapHeight/2 )*provazoom +corry );
//Log.d(TAG_readFile, "trasformo : "+obstacles.get(i).x+" e "+obstacles.get(i).y+" in "+x+" "+(-1*obstacles.get(i).y)+"con map w e h"+mapWidth+" "+mapHeight);
//Log.d(TAG_draw, "x e y "+x+" "+y);
tmpCanvas.drawPoint(x,y, paint);
Paint prova=new Paint();
prova.setColor(Color.WHITE);
lasti=i;
//tmpCanvas.drawCircle(x, y, (float)1, prova);
}
synchronized(obstaclesBmp){
obstaclesBmp=Bitmap.createBitmap(obstaclesBmpTmp);
}
}catch(OutOfMemoryError e){
Log.e(TAG_error, "Bitmap troppo grossa !dim:"+mapWidth+" "+mapHeight);
}
}
@Override
public void run() {
Log.d(TAG_draw, "Drawer Thread Partito");
Canvas c;
while (_run) {
c = null;
try {
c = _surfaceHolder.lockCanvas(null);
synchronized (_surfaceHolder) {
//Log.d(TAG_draw, "Drawer Thread chiama onDraw");
//Log.d(TAG_draw, "Drawer Thread ha il lock !");
UpdateBmp();
_panel.onDraw(c);
Log.d(TAG_draw, "Drawer Thread Dorme");
sleep(500);
Log.d(TAG_draw, "Drawer Thread Sveglio");
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// do this in a finally so that if an exception is thrown
// during the above, we don't leave the Surface in an
// inconsistent state
if (c != null) {
_surfaceHolder.unlockCanvasAndPost(c);
}
}
}
//Log.d(TAG_draw, "Drawer Thread termina");
}
}
public class FileReaderThread extends Thread {
private boolean _run = false;
public void setRunning(boolean run) {
_run = run;
}
public double modulo (vertex v){
return Math.sqrt(Math.pow(v.x,2)+Math.pow(v.y,2)) ;
}
public void insord(vertex dains,LinkedList<vertex> lista){
//funzione per l'inserimento ordinato in una lista
ListIterator<vertex> i2=lista.listIterator();
if(lista.size()==0){
lista.add(dains);
}
else{
while(i2.hasNext()){
vertex temp=i2.next();
//System.out.println("x da ins "+dains.x+" confrontata con "+temp.x);
//if(modulo(temp)==modulo(dains)&& temp.x==dains.x && temp.y==dains.y){ }
if(modulo(temp)>=modulo(dains)){
lista.add(i2.previousIndex(), dains);
//System.out.println("inserito in posizione "+(i2.previousIndex()));
break;
}
if(i2.hasNext()==false){
lista.addLast(dains);
//System.out.println("inserito in ultima posizione "+(i2.previousIndex()+1));
break;
}
}
}
}
public void insord_x(vertex dains,ArrayList<vertex> lista){
//inserimento ordinato rispetto alle x per gli ostacoli
ListIterator<vertex> i2=lista.listIterator();
if(lista.size()==0){
lista.add(dains);
}
else{
while(i2.hasNext()){
vertex temp=i2.next();
//System.out.println("x da ins "+dains.x+" confrontata con "+temp.x);
//if(modulo(temp)==modulo(dains)&& temp.x==dains.x && temp.y==dains.y){ }
if(temp.x>=dains.x){
lista.add(i2.previousIndex(), dains);
//System.out.println("inserito in posizione "+(i2.previousIndex()));
break;
}
if(i2.hasNext()==false){
lista.add(i2.nextIndex(),dains);
//System.out.println("inserito in ultima posizione "+(i2.previousIndex()+1));
break;
}
}
}
}
public void run(){
while (_run) {
Log.d(TAG_readFile, "Reader Thread Partito");
//istanzio un oggetto di tipo Resources per usare facilmente le mie risorse dalla cartella Res
//Resources res = this.getResources() ;
//Recupero dalla cartella res\raw il file sottoforma di stream e lo trasformo
File sdcard = Environment.getExternalStorageDirectory();
//Get the text file
File file = new File(sdcard,"provatesto.g2o");
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(file));
Log.d(TAG_readFile, "nome file "+file.getName());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
Log.d(TAG_readFile, "FILE NON TROVATOOOOOOOO");
e.printStackTrace();
}
//InputStream instream = res.openRawResource(R.raw.provatesto);
//DataInputStream dis = new DataInputStream(instream);
DataInputStream dis = new DataInputStream(in);
String line= "empty";
int vIndex = 0;
int oIndex = 0;
//leggo una linea
try {
//Log.d(TAG_readFile, "leggo il file");
while((line = dis.readLine()) != null){
//Log.d(TAG_readFile, "Reader Thread ha il lock!!");
//Log.d(TAG_readFile, "Ho letto la linea: "+line);
StringTokenizer st= new StringTokenizer(line);
//Log.d(TAG_readFile, "Ho letto la linea: "+line);
try{
String entry=st.nextToken();
//Log.d(TAG_readFile, "Token: "+entry);
if(entry.equals("VERTEX_SE2")){
Integer index = Integer.parseInt(st.nextToken());
Double x = Double.parseDouble(st.nextToken());
Double y = Double.parseDouble(st.nextToken());
Double r = Double.parseDouble(st.nextToken());
vertex newVertex=new vertex(x,y,vIndex);
synchronized(map){
map.put(vIndex, newVertex);
}
synchronized(originale){
originale.add(newVertex);
}
if(vIndex>0) map.get(vIndex-1).addEdge(map.get(vIndex));
insord(newVertex,originalPath);
//Log.d(TAG_readFile, ""+vIndex);
vIndex++;
}
else if(entry.equals("VERTEX_XY")){
Integer index = Integer.parseInt(st.nextToken());
Double x = Double.parseDouble(st.nextToken());
Double y = Double.parseDouble(st.nextToken());
//Log.d(TAG_readFile, "xy index: "+x+" "+y);
try{
vertex newVertex=obstacles.get(index);
}catch(IndexOutOfBoundsException e){
//obstacles.add(new vertex(Double.parseDouble(x),Double.parseDouble(y),Integer.parseInt(index)));
if(Math.abs(x)>mapWidth/2) mapWidth=(int)Math.ceil(Math.abs(x))*2;
if(Math.abs(y)>mapHeight/2) mapHeight=(int)Math.ceil(Math.abs(y)*2);
//Log.d(TAG_readFile, "mapWidth "+mapWidth+" mapHeight "+mapHeight);
/*
synchronized(obstacles){
insord_x(new vertex(x,y,index),obstacles);
}
*/
synchronized(obstacles){
obstacles_notordered.add((new vertex(x,y,index)));
}
}
oIndex++;
}
else {//Log.d(TAG_readFile, "edge");
}
if(oIndex%200==0){
Log.d(TAG_readFile, "Reader thread sta girando");
}
}catch(NoSuchElementException e){
}
//Log.d(TAG_readFile, "oindex "+oIndex);
}//
} catch (IOException e) {
Log.e(TAG_readFile, "Errore durante la lettura di una linea.");
line= "end";
e.printStackTrace();
}
Log.d(TAG_readFile, "Reader Thread Termina");
}}
}
}
要调用的onDraw我猜你是在你的UI线程中,但它也表示你在这个线程中睡觉。这对于响应能力非常不利。看起来你的UI线程被锁定并且超时。确保你在UI线程以外的线程上进行任何处理/休眠。
您不能完全暂停您的线程,但您可以使用等待/通知条件暂停线程,直到满足条件。
Here是等待/通知给你一个想法的快速教程。
你也不应该在你的UI线程中做任何长期的处理,因为它可能会阻止它,并给你ANR异常。由于无法从另一个线程更新UI,因此通常使用带有Thread
或AsyncTask
的Handler
在后台运行长期进程并更新UI线程。
查看painless threading的一些解释,并在android performance一个很好的教程在这一个。
谢谢! ithink我这样做是因为我的onDraw函数oly绘制一个位图。该位图是在drawer中生成的Thread在他的run()函数中执行的: \t UpdateBmp(); //更新公共bmp \t _panel.onDraw(c); \t \t sleep(500); } – Dedanan 2012-02-03 11:19:34
我不会使用两个单独的线程。事实上,当文件中的某些内容发生变化时,您只需要重新绘制,因此您可以从后台线程调用postInvalidate()
,并且这将在UI线程上调用draw()
谢谢!我试过使用等待/通知,但如果我让线程在等待条件,我开始preferenceActivity它给了我同样的错误。 为更具体我使用“lunarlander”的想法..所以我有一个扩展sufraceview和实现surface holder.callback和内部,我创建我的线程,抽屉线程调用面板的面板类。onDraw() – Dedanan 2012-02-03 11:03:24
好吧,我需要看你的代码进一步评论。添加代码 – mcnicholls 2012-02-03 11:14:03
,感谢您的帮助。 – Dedanan 2012-02-03 11:27:00