Android - Как приостановить темы во время другого действия? - PullRequest
1 голос
/ 03 февраля 2012

У меня есть поток "reader", который читает файл и обновляет список A. Другой поток "drawer" читает то, что есть в переменной a, что-то делает, вызывает ondraw и затем спит в течение 500 мс (в течение этого времени читатель заполняется 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 ]

1 голос
/ 03 февраля 2012

Вы также не должны выполнять какую-либо долгосрочную обработку в потоке пользовательского интерфейса, так как это может заблокировать его и дать вам исключение ANR. поскольку нет способа обновить пользовательский интерфейс из другого потока, обычно используется Handler с Thread или AsyncTask для запуска долгосрочных процессов в фоновом режиме и обновления потока пользовательского интерфейса.

просто посмотрите на безболезненное продвижение для некоторого объяснения и производительность Android для превосходного учебника по этому вопросу.

0 голосов
/ 04 февраля 2012

Я бы не использовал два отдельных потока. На самом деле вам нужно перерисовывать только когда что-то меняется в файле, так что вы можете вызвать postInvalidate() из фонового потока, и в свою очередь это вызовет draw() в потоке пользовательского интерфейса

0 голосов
/ 03 февраля 2012

Чтобы вызвать onDraw, я предполагаю, что вы находитесь в вашем потоке пользовательского интерфейса, но он также говорит, что вы спите в этом потоке. Это очень плохо для отзывчивости. Похоже, что ваш поток пользовательского интерфейса заблокирован и время ожидания истекло. Убедитесь, что вы выполняете какую-либо обработку / спящие потоки, кроме потока вашего пользовательского интерфейса.

Вы не можете точно приостановить поток, но вы можете использовать условие ожидания / уведомления, чтобы остановить поток, пока не будет выполнено ваше условие.

Здесь - это краткое руководство по ожиданию / уведомлению, чтобы дать вам идею.

...