Autore Topic: Activity con Panel ed un Thread  (Letto 395 volte)

Offline Corrado

  • Nuovo arrivato
  • *
  • Post: 4
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows XP
Activity con Panel ed un Thread
« il: 01 Aprile 2011, 16:22:37 CEST »
0
Nell'applicazione che sto sviluppando ho creato un'activity sopra la quale ho disegnato un panel ereditato da SurfaceView e implementando SurfaceHolder.Callback, in modo da poter gestire un Thread per aggiornare il pannello. Infatti su di esso disegno dei rettangoli. Cliccando/premendo all'interno dei rettangoli parte un'altra Activity dove vengono richieste alcune informazioni. Quando ritorno indietro al pannello non mi ridisegna più i rettangoli che avevo disegnato prima nonostante il codice venga eseguito.
Qualcuno può darmi un'aiuto?
Grazie.

Il codice in questione è il seguente :

Questa è la classe che ospita il Panel
Codice (Java): [Seleziona]
public class Draw extends Activity {
    private Panel panel;  
        @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);  
        Panel panel = new Panel(this);
        setContentView(panel);
    }

        public void SearchContent() {
        Intent intent = new Intent().setClass(this, SearchContent.class);
        startActivity(intent);
               
        }

}

Questa è la classe del pannello dove disegno, in maniera primitiva, i rettangoli
Codice (Java): [Seleziona]
class Panel extends SurfaceView implements SurfaceHolder.Callback {
        public DrawThread _thread;    
        private RectF _rect;
    private RectF[] TabRect;
    public int indLine = 0;
    private ScaleGestureDetector mScaleDetector;
    private Context c;

   
    public Panel(Context context) {
        super(context);
        getHolder().addCallback(this);
        if (_thread == null) _thread = new DrawThread(getHolder(), this);        
        setFocusable(true);
        _rect = null;
        TabRect = new RectF[99];        
        c = context;
    }


        @Override
    public void onDraw(Canvas canvas) {
        Rect rect = new Rect();
        rect.top = 2;
        rect.left = 2;
        rect.right = 598;
        rect.bottom = 888;            
        Paint paint = new Paint();
        paint.setColor(Color.WHITE);
        canvas.drawRect(rect, paint);
        Paint paintLine = new Paint();
        paintLine.setColor(Color.RED);
//      paintLine.setARGB(255, 255, 0, 0);
        paintLine.setAntiAlias(true);
        paintLine.setStyle(Style.STROKE);
        paintLine.setStrokeWidth(6);           
                Paint innerPaint = new Paint();
                innerPaint.setARGB(225, 255, 255, 255);
        for(int ii=0;ii<indLine;ii++) {
                if (TabRect[ii].bottom != 0) {
                        RectF drawRect = new RectF();
                        drawRect.set(TabRect[ii].top,TabRect[ii].left, TabRect[ii].bottom, TabRect[ii].right);
                        canvas.drawRoundRect(drawRect, 5, 5, innerPaint);
                        canvas.drawRoundRect(drawRect, 5, 5, paintLine);                       
                       
/*                     
                        canvas.drawRect(TabRect[ii], innerPaint );
                        canvas.drawRoundRect(TabRect[ii], 5, 5, innerPaint);
                        canvas.drawRoundRect(TabRect[ii], 5, 5, paintLine);                    
*/

                }
        }
    }

       
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                        int arg3) {
                // TODO Auto-generated method stub
               
        }

    public void surfaceCreated(SurfaceHolder arg0) {
        if (_thread.getRunning() == false) {
            Log.d("DEBUG", "surfaceCreated");                  
            _thread.setRunning(true);
           if (_thread.isStarted == false) _thread.start(); else {
               _thread.unPause();
                   _thread.run();
           }
            _thread.isStarted = true;
            }
        }

    public void surfaceDestroyed(SurfaceHolder arg0) {
            // simply copied from sample application LunarLander:
            // we have to tell thread to shut down & wait for it to finish, or else
            // it might touch the Surface after we return and explode
            boolean retry = true;
                        _thread.setRunning(false);
            Log.d("DEBUG", "surfaceDestroyed");                        
                        while (retry) {
                                try {
                                        _thread.join();
                                        retry = false;
                                } catch (InterruptedException e) {
                                        // we will try it again and again...
                                }
                        }
        }
   
        public boolean onTouchEvent(MotionEvent ev) {
        final int action = ev.getAction();
        // Let the ScaleGestureDetector inspect all events.
        mScaleDetector.onTouchEvent(ev);

        switch (action) {
        case MotionEvent.ACTION_DOWN: {
            final int x = (int) ev.getX();
            final int y = (int) ev.getY();
           
            break;
        }
           
        case MotionEvent.ACTION_UP: {
            final int x = (int) ev.getX();
            final int y = (int) ev.getY();
// determina se dentro un rettangolo
            boolean insideRect = false;
            for(int ii=0;ii<indLine;ii++) {
                if (TabRect[ii].top == 0) break;
                if (( x >= TabRect[ii].top && x <= TabRect[ii].bottom ) &&
                   ( y >= TabRect[ii].left && y <= TabRect[ii].right )) {
                        insideRect = true;
                        break;
                }
            }
            if (insideRect == true) {
                // apre view per ricerca fonte
                _thread.pause();
                _thread.interrupt();
                Draw draw;
                draw = (Draw) c;
                draw.SearchContent();
                break;
            }
               
                if (_rect == null) {
                        _rect = new RectF();   
                // Remember where we started
                _rect.top = (int) x;
                _rect.left = (int) y;
               
                } else    {
/*                     
                if ( x >= y ) {
                        _rect.bottom = (int) x;
                    _rect.right = _rect.left;                  
                } else {
                        _rect.bottom = _rect.top;
                    _rect.right = (int) y;                                             
                }
*/
                                    
                _rect.bottom = (int) x;
                _rect.right = (int) y;
                TabRect[indLine] = _rect;
                indLine = indLine + 1;
                _rect = null;
                }
            break;
        }

        }
        return true;
    }


}

Questo è il thread
Codice (Java): [Seleziona]
public class DrawThread extends Thread {

    private SurfaceHolder _surfaceHolder;
    private Panel _panel;
    private boolean _run = false;
    boolean isPaused = false;
    boolean isStarted = false;
   
        public DrawThread(SurfaceHolder surfaceHolder, Panel panel) {
        _surfaceHolder = surfaceHolder;
        _panel = panel;
        isStarted = false;
    }
 
    public void setRunning(boolean run) {
        _run = run;
    }
 
    public boolean getRunning() {
        return _run;
    }
 
    @Override
    public void run() {
        Canvas c;
            Log.d("DEBUG", "run-pre while");  
        while (_run && !isPaused ) {
            Log.d("DEBUG", "run");  
            c = null;
            try {
                c = _surfaceHolder.lockCanvas(null);
                synchronized (_surfaceHolder) {
                    _panel.onDraw(c);
                }
            } 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);
                }
            }
        }
    }

        public void pause() {
        synchronized (_surfaceHolder) {
          isPaused = true;
        }
        }

        public void unPause() {
        synchronized (_surfaceHolder) {
          isPaused = false;
        }              
        }
}
Questa è la classe chiamata dal click/tap all'interno del rettangolo

Codice (Java): [Seleziona]
public class SearchContent extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
        setContentView(R.layout.searchcontent);        
        }


}

Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/LinearLayout01"
        android:layout_width="fill_parent" android:layout_height="fill_parent"
        xmlns:android="http://schemas.android.com/apk/res/android">

        <TableLayout android:id="@+id/TableLayout01"
                     android:layout_width="wrap_content" android:layout_height="wrap_content">
                <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"
                        android:layout_height="wrap_content" android:layout_weight="1">
                        <EditText android:id="@+id/EditText01"
                                android:layout_width="400dp" android:layout_height="wrap_content" />
                        <Button android:id="@+id/Button01" android:text="@string/btn_search"
                                android:layout_width="100dp" android:layout_height="wrap_content" />
                </TableRow>
                <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"
                        android:layout_height="wrap_content">
                       
                </TableRow>
                <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"
                        android:layout_height="wrap_content">
                        <ImageButton android:id="@+id/ImageButton02"
                                android:layout_width="wrap_content" android:layout_height="wrap_content"></ImageButton>
                </TableRow>
        </TableLayout>


</LinearLayout>

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1463
  • keep it simple
  • Respect: +259
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Tattoo / Galaxy S
  • Market Developer Name:
    Bradipao
  • Sistema operativo:
    Windows XP
Re:Activity con Panel ed un Thread
« Risposta #1 il: 01 Aprile 2011, 16:51:25 CEST »
0
Riconosco il gameloop che avevo trovato in un paio di tutorial, per cui posso provare ad avanzare delle ipotesi. Correggimi se sbaglio.

Quello che vedo è che al rilascio dopo pressione sullo schermo, di fatto fai morire il thread che ridisegna.

Codice (Java): [Seleziona]
        case MotionEvent.ACTION_UP: {
            ....
            if (insideRect == true) {
                // apre view per ricerca fonte
                _thread.pause();
                _thread.interrupt();
                Draw draw;
                draw = (Draw) c;
                draw.SearchContent();
                break;
            }

La riga dove (secondo me) lo fai morire è _thread.pause(), perchè quando lo metti in pausa il metodo run esce e il thread è ufficialmente DEAD.

Codice (Java): [Seleziona]
    public void run() {
        Canvas c;
            Log.d("DEBUG", "run-pre while");  
        while (_run && !isPaused ) {
            Log.d("DEBUG", "run");  
            c = null;
            try {
                c = _surfaceHolder.lockCanvas(null);
                synchronized (_surfaceHolder) {
                    _panel.onDraw(c);
                }
            } 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);
                }
            }
        }
    }

Se ho interpretato bene il codice, per far ripartire il ridisegno al ritorno dalla SearchContent sarebbe da ricreare il Thread.

Può darsi sia così?
Partecipa anche tu all'iniziativa per salvare logCAT, felino in via di estinzione della razza Dalvik : CLICCA QUA

Offline Corrado

  • Nuovo arrivato
  • *
  • Post: 4
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows XP
Re:Activity con Panel ed un Thread
« Risposta #2 il: 01 Aprile 2011, 17:03:32 CEST »
0
Per un certo periodo anch'io ho sospettato che il thread fosse da ricreare e infatti uso il metodo interrupt, ma il thread non viene cancellato.
Infatti seguendo la sequenza dei log quando passo all'activity SearchContent viene eseguito il metodo _thread.interrupt() che attiva il metodo surfaceDestroyed.
Quando ritorno all'activity Panel viene attivato il metodo surfaceCreated all'interno del quale evito di richiamare il metodo _thread.start perchè si pianta, eseguo quindi il metodo _thread.run in modo che riprende a loopare e ad eseguire il metodo panel.draw, che disegna il panel con sfondo bianco e i rettangoli fino a quel momento creati.
Tutto viene eseguito ma niente viene disegnato. E come se la classe panel si fosse staccata dalla classe draw dove è stata creata in origine.
Spero di essere stato chiaro.
Ciao.

Offline bradipao

  • Moderatore globale
  • Utente storico
  • *****
  • Post: 1463
  • keep it simple
  • Respect: +259
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Tattoo / Galaxy S
  • Market Developer Name:
    Bradipao
  • Sistema operativo:
    Windows XP
Re:Activity con Panel ed un Thread
« Risposta #3 il: 01 Aprile 2011, 17:22:05 CEST »
0
Per un certo periodo anch'io ho sospettato che il thread fosse da ricreare e infatti uso il metodo interrupt, ma il thread non viene cancellato.
Infatti seguendo la sequenza dei log quando passo all'activity SearchContent viene eseguito il metodo _thread.interrupt() che attiva il metodo surfaceDestroyed.
Quando ritorno all'activity Panel viene attivato il metodo surfaceCreated all'interno del quale evito di richiamare il metodo _thread.start perchè si pianta, eseguo quindi il metodo _thread.run in modo che riprende a loopare e ad eseguire il metodo panel.draw, che disegna il panel con sfondo bianco e i rettangoli fino a quel momento creati.
Tutto viene eseguito ma niente viene disegnato. E come se la classe panel si fosse staccata dalla classe draw dove è stata creata in origine.
Spero di essere stato chiaro.

Potrei sbagliarmi ma credo che l'errore sia proprio in quello che stai facendo.

Da quello che so io:
- Il codice che viene eseguito in un thread separato è quello all'interno di run()
- Per far partire il thread non si può chiamare run() direttamente, ma si usa start()
- Un thread può essere avviato SOLO UNA VOLTA (ecco come mai ti crasha se provi a farlo ripartire con start)
- Se richiamo run() non fai ripartire il thread, ma semplicemente esegui run() come una funzione

Puoi ovviamente controllare se il thread sta girando al ritorno dall'activity, grazie a Log.d("DEBUG", "run"); che hai messo nel loop.

Secondo me se sposti la creazione di una nuova istanza di thread, e il relativo start(), in onSurfaceCreated, dovrebbe riprendere ad andare.
Partecipa anche tu all'iniziativa per salvare logCAT, felino in via di estinzione della razza Dalvik : CLICCA QUA

Offline Corrado

  • Nuovo arrivato
  • *
  • Post: 4
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy Tab
  • Sistema operativo:
    Windows XP
Re:Activity con Panel ed un Thread
« Risposta #4 il: 01 Aprile 2011, 17:38:14 CEST »
0
L'errore era proprio in quello che stavo facendo.
In effetti mi sono intestardito a cercare di cancellare il thread e poi a ricrearlo quando effettivamente è sufficiente ricreare la classe per distruggere quella prima e farne una nuova.

Adesso funziona.
Grazie di tutto.

Offline Auron

  • Utente junior
  • **
  • Post: 104
  • Respect: +1
    • Mostra profilo
  • Dispositivo Android:
    Motorola Milestone Android 2.2.1
  • Sistema operativo:
    Windows
Re:Activity con Panel ed un Thread
« Risposta #5 il: 27 Gennaio 2012, 17:12:44 CET »
0
Scusate l'intromissione, ma volevo chiedere a Bradipao perchè allora a me funziona richiamando più volte lo start() del Thread nella onDraw:

Premetto che nel Costruttore della View creo il Thread:

Codice (Java): [Seleziona]
time_loop = new Time_Loop();
// diciamo alla variabile timer qual è la View da aggiornare
time_loop.Set_View_Da_Aggiornare(this);

Codice (Java): [Seleziona]
@Override
        protected void onDraw(Canvas canvas) {
               
                super.onDraw(canvas);

                time_loop.stop();

                }

Di seguito invece c'è la classe Thread dove viene richiamata la onDraw

Codice (Java): [Seleziona]
        @Override
        public void run()
        {
                while(running || (count < 30))
                {
                        try{
                                TimeUnit.MILLISECONDS.sleep(num_millisecondi_di_pausa);
                                view_associata.postInvalidate();
                                //Log.i("TimeLoop", "TimeLoop");
                                pause();
                                count++;
                        }
                        catch(InterruptedException ex)
                        {
                                running=false;
                        }
                }
        }
       
        // ********************************************************
        public void pause()
        {
                running=false;
        }

        // ********************************************************
        @Override
        public void start()
        {
                running=true;
                run();
        }
È stata trovata una soluzione al tuo problema?Evidenzia il post più utile premendo . È un ottimo modo per ringraziare chi ti ha aiutato ;-)