Android - 如何在其他活动期间暂停线程?

时间:2012-02-03 10:49:31

标签: android multithreading android-activity draw

我有一个线程"reader",它读取文件并更新列表A.另一个线程"drawer"读取变量a中的内容,执行某些操作,调用ondraw然后睡眠500ms(在此期间)这次读者填写A)。

如果我按下菜单按钮,我还会启动首选项活动。

问题是如果我在阅读器线程没有完成时按下按钮来读取他的文件我在logcat中出错了。(见下文)

我已经看到问题是正在运行的读者线程,而它向我显示偏好菜单,事实上,如果我等到读者结束并且我点击偏好它一切顺利,但如果我点击而它的运行igot错误。

当我重新启动时,我如何处理仍在运行的线程?我"pause"他们怎么样?想要阅读我的文件可能很长,所以我不能等待读者线程结束。

感谢

编辑:更确切地说,如果我按下菜单按钮,preferenceActivity会启动,我会看到正确的视图(带单选按钮等),但问题是当我点击一个随机点时屏幕,它给我错误。如果我等待读取结束(我从logcat看到它)然后我点击一个随机点,它会非常顺利......

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");
        }}



}

}

3 个答案:

答案 0 :(得分:1)

您也不应该在UI线程中进行任何长期处理,因为它可能会阻止它并为您提供ANR异常。由于无法从其他线程更新UI,因此通常使用HandlerThreadAsyncTask在后​​台运行长期流程并更新UI线程。

只需查看painless threading进行一些解释,然后在android performance查看有关此问题的优秀教程。

答案 1 :(得分:0)

要调用onDraw我猜你是在你的UI线程中,但它也说你正在这个线程中睡觉。这对响应性非常不利。您的UI线程似乎已被锁定并超时。确保在UI线程以外的线程上进行任何处理/休眠。

您无法准确暂停线程,但可以使用wait / notify条件暂停线程,直到满足条件。

Here是一个关于wait / notify的快速教程,可以给你一个想法。

答案 2 :(得分:0)

我不会使用两个单独的线程。实际上,只需要在文件中发生更改时重新绘制,因此您可以从后台线程调用postInvalidate(),然后在UI线程上调用draw()