Autore Topic: Activity con Panel ed un Thread  (Letto 1194 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: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
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ì?
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

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: 4043
  • keep it simple
  • Respect: +567
    • Github
    • Google+
    • bradipao
    • Mostra profilo
  • Dispositivo Android:
    Nexus 5
  • Play Store ID:
    Bradipao
  • Sistema operativo:
    W7
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.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

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