Autore Topic: Problema con CustomView  (Letto 572 volte)

Offline tinezridan

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    Windows 7
Problema con CustomView
« il: 07 Marzo 2012, 11:25:06 CET »
0
Salve a tutti, sono nuovo di questo forum e spero di aver postato nella sezione giusta... vi spiego il mio problema.
Ho realizzato una custom view all'interno della quale faccio muovere un cerchio che rimbalza da un lato all'altro.
È possibile con un tasto stoppare/riavviare il thread che fa muovere il cerchio
Il programma funziona e vi posto il codice:
Codice (Java): [Seleziona]
public class BiliardoActivity extends Activity {
    /** Called when the activity is first created. */
        CustomView cv;
        Handler updateCvHandler;
        Timer myTimer;
        Button b;

        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                cv=(CustomView)findViewById(R.id.customView);
                cv.setBackgroundColor(Color.BLUE);
                b=(Button)findViewById(R.id.Button01);
                b.setOnClickListener(new OnClickListener() {                  
                        public void onClick(View v) {                          
                                if(b.getText().toString().equals("Start")){
                                        myTimer = new Timer();
                                        myTimer.schedule(new TimerTask() {
                                                @Override
                                                public void run() {
                                                        TimerMethod();
                                                }
                                        }, 0, 10);
                                        b.setText("Stop");
                                }
                                else{
                                        myTimer.cancel();
                                       
                                        b.setText("Start");
                                }
                        }
                });
        }
       
        private void TimerMethod(){
                this.runOnUiThread(Timer_Tick);
        }

        private Runnable Timer_Tick = new Runnable() {
                public void run() {
                        cv.updatePosition();
                }
        };
}

e la custom view
Codice (Java): [Seleziona]
public class CustomView extends View {

        Paint mPaint;
        Random mRand;
        Canvas cv;
        boolean direction=false; //false=destra, true=sinistra
        int w,h;
        int px=-1,py=-1;
        public CustomView(Context context, AttributeSet attrs) {
                super(context, attrs);
                mRand=new Random();
                mPaint=new Paint(); // pennello
                mPaint.setColor(Color.GREEN);//destra
                mPaint.setAntiAlias(true);
        }

        @Override
        protected void onDraw(Canvas canvas) {
                cv=canvas;
                super.onDraw(cv);
                if(px==-1 && py==-1){
                        px=w/2;
                        py=h/2;
                }
                Log.i("draw","px: "+px+", py: "+ py+", w: "+w+", h: "+h);
                cv.drawCircle(px, py, 50, mPaint);
        }

        public void updatePosition(){    
                //for(int i=0; i>=0; i++); // fatto apposta per creare un ciclo infinito
                if((px>=0 & px<=w)&(py>=0 & py<=h)){
                        if(direction){ // stai andando a sinistra
                                px=px-1;
                                py=py-1;
                        }
                        else{   //stai andando a destra
                                px=px+1;
                                py=py+1;
                        }
                }
                else if(px<0 | py<0){
                        direction=false; //vai a destra
                        mPaint.setColor(Color.GREEN);
                        px=(px+mRand.nextInt(50));
                        py=(py+mRand.nextInt(50));
                }
                else if(px>w | py>h){
                        direction=true; //vai a sinistra
                        mPaint.setColor(Color.YELLOW);
                        px=(px-mRand.nextInt(50));
                        py=(py-mRand.nextInt(50));
                }
                else
                        Log.i("update", "sto in una condizione non considerata");
                Log.i("update","px: "+px+", py: "+ py+", w: "+w+", h: "+h);
                invalidate();
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                w=MeasureSpec.getSize(widthMeasureSpec);
                h=MeasureSpec.getSize(heightMeasureSpec);
                setMeasuredDimension(w,h);
        }
}

e questo è il main.xml
Codice (XML): [Seleziona]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:background="#FF00FF">

        <Button
               android:text="Start"
               android:id="@+id/Button01"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content">
        </Button>

        <com.tinezridan.biliardo.CustomView
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"
               android:id="@+id/customView" />

</LinearLayout>
Ora mi è stato chiesto, a scopo di esercizio, di inserire un ciclo infinito nella logica di update del cerchio (prima istruzione commentata del metodo updatePosition della classe CustomView) e mi è stato detto che in tal caso il bottone start/stop non si debba bloccare come invece accade col codice che ho postato.
Secondo le direttive che ho ricevuto, la logica di update dovrebbe andare in un thread secondario di modo che se in essa ci fosse qualcosa che non va (la riga di codice messa apposta), l'UI non dovrebbe bloccarsi.
Siccome io sono abbastanza alle prime armi con java (lato threading) ma soprattutto con android, qualcuno di voi mi potrebbe dire come fare ciò?
Grazie in anticipo
« Ultima modifica: 07 Marzo 2012, 12:17:25 CET da tinezridan »

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:Problema con CustomView
« Risposta #1 il: 08 Marzo 2012, 08:00:26 CET »
0
Non è facile rispondere in poche righe, in quanto occorrerebbe stravolgere un po' il codice e soprattutto spiegare un bel po' di concetti.

Però questa problematica è affrontata in questa serie di tutorial: Playing with graphics in Android – Part II on Android Development

Secondo me già leggendoli ti fai un'idea di come deve essere impostato il codice.
NON rispondo a domande nei messaggi privati
Bradipao @ Play Store

Offline tinezridan

  • Nuovo arrivato
  • *
  • Post: 3
  • Respect: 0
    • Mostra profilo
  • Dispositivo Android:
    Samsung Galaxy S2
  • Sistema operativo:
    Windows 7
Re:Problema con CustomView
« Risposta #2 il: 08 Marzo 2012, 15:45:06 CET »
0
Ciao bradipao, grazie per la risposta. In effetti qualcosina da quella lettura l'ho intuita.
La chiave stava nel separare la logica di update della posizione dall'invalidate. Per fare questo ho creato un thread a parte.

La CustomView è sostanzialmente la stessa... ho solo tolto il metodo invalidate alla fine del metodo updatePosition
Codice (Java): [Seleziona]
public class CustomView extends View {

        Paint mPaint;
        Random mRand;
        boolean direction=false; //false=destra, true=sinistra
        int w,h;
        int px=-1,py=-1;
        public CustomView(Context context, AttributeSet attrs) {
                super(context, attrs);
                mRand=new Random();
                mPaint=new Paint(); // pennello
                mPaint.setColor(Color.GREEN);//destra
                mPaint.setAntiAlias(true);
        }

        @Override
        protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                if(px==-1 && py==-1){
                        px=w/2; //metà della larghezza view
                        py=h/2; //metà dell'altezza view
                }
                Log.i("draw","px: "+px+", py: "+ py+", w: "+w+", h: "+h);
                canvas.drawCircle(px, py, 50, mPaint);
        }


        public void updatePosition(){    
                for(int i=0;i>=0;i++); //messo apposta per verificare se il tasto Start/Stop funziona
                if((px>=0 & px<=w)&(py>=0 & py<=h)){
                        if(direction){ // stai andando a sinistra
                                px=px-1;
                                py=py-1;
                        }
                        else{   //stai andando a destra
                                px=px+1;
                                py=py+1;
                        }
                }
                else if(px<0 | py<0){
                        direction=false; //vai a destra
                        mPaint.setColor(Color.GREEN);
                        px=(px+mRand.nextInt(50));
                        py=(py+mRand.nextInt(50));
                }
                else if(px>w | py>h){
                        direction=true; //vai a sinistra
                        mPaint.setColor(Color.YELLOW);
                        px=(px-mRand.nextInt(50));
                        py=(py-mRand.nextInt(50));
                }
                else
                        Log.i("update", "sto in una condizione non considerata");
                Log.i("update","px: "+px+", py: "+ py+", w: "+w+", h: "+h);
        }
       
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                w=MeasureSpec.getSize(widthMeasureSpec);
                h=MeasureSpec.getSize(heightMeasureSpec);
                setMeasuredDimension(w,h);
        }
}

l'activity
Codice (Java): [Seleziona]
public class BiliardoActivity extends Activity {
    /** Called when the activity is first created. */
        CustomView cv;
        ThreadUpdate t1;
        Button b;

        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.main);
                cv=(CustomView)findViewById(R.id.customView);
                cv.setBackgroundColor(Color.BLUE);
                b=(Button)findViewById(R.id.Button01);
                t1=new ThreadUpdate(cv,this);
                t1.start();
                b.setOnClickListener(new OnClickListener() {                  
                        public void onClick(View v) {                          
                                if(b.getText().toString().equals("Start")){
                                        b.setText("Stop");
                                        if(t1.isStopped()){
                                                t1.ReStartUpdate();
                                        }
                                }
                                else{
                                        b.setText("Start");
                                        t1.stopUpdate();
                                        if(!t1.isStopped()){
                                                t1.stopUpdate();
                                        }
                                }
                        }
                });
        }
}

e il thread
Codice (Java): [Seleziona]
public class ThreadUpdate extends Thread implements Runnable{
        volatile boolean finished = false; //me lo fa morire
        volatile boolean blocked= true; //me lo blocca
        private CustomView _cv;
        private Activity _activity;
       
        public ThreadUpdate(CustomView cv, Activity activity){
                _cv=cv;
                _activity=activity;
        }
        public void stopUpdate(){
                blocked = true;
        }
       
        public boolean isStopped(){
                return blocked;
        }
       
        public void ReStartUpdate(){
                blocked=false;
        }
       
        public void run(){
                while (!finished){
                        while(!blocked){
                                _cv.updatePosition();
                                _activity.runOnUiThread(new Runnable(){
                                        public void run() {
                                                _cv.invalidate();
                                        }
                                });
                                try {
                                        this.sleep(10);
                                } catch (InterruptedException e) {
                                        Log.i("thread", e.getMessage());
                                }
                        }
                }
        }
}

Ho postato per completezza il codice con cui ritengo di aver risolto il problema, nel caso in cui qualcuno si trovi ad avere la stessa situazione da affrontare.
Saluti