2015-05-26 6 views
6

Stavo cercando di creare un'applicazione con alcuni thread di utilizzo. Durante il lavoro ho trovato un comportamento imprevedibile mentre stavo cercando di accedere a un TextView dal thread. So che Android ci impedisce di accedere alle viste direttamente da un altro thread. So anche come accedere alle viste del thread principale da un altro thread usando AsyncTask, Handler, Activity.runOnUiThread (Runnable), View.post (Runnable), View.postDelayed (Runnable) , lungo), eccComportamento imprevedibile quando si accede a View da un'altra thread

Ecco il mio frammento di codice -

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     final TextView tv = (TextView) findViewById(R.id.tv); 
     Thread t = new Thread(new Runnable() { 

      @Override 
      public void run() { 
       /*try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       }*/ 

       /*for(int i= 0 ; i<10000000 ;i++){ 
        Log.i("logger"," i ="+i); 
        tv.setText("i = "+i); 
       }*/ 

       tv.setText("This is the new text"); 
      } 
     }); 
     t.start(); 
    } 

Quando sto facendo funzionare questo codice, nessun crash verificarsi, ma non appena ho uncomment Thread.sleep() o per una parte del ciclo, incidente si verificano. Qualcuno può spiegare questo comportamento, perché succede in questo modo e perché l'arresto anomalo non si verifica con un determinato codice. Si prega di non pubblicare risposte che spieghino come farlo.

Grazie in anticipo.

Questo è il log crash quando ho uncomment Thread.sleep() sezione di codice -

05-26 21:11:47.244: E/AndroidRuntime(14310): FATAL EXCEPTION: Thread-13346 
05-26 21:11:47.244: E/AndroidRuntime(14310): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:5225) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1062) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:292) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.view.View.requestLayout(View.java:15316) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.checkForRelayout(TextView.java:6659) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3670) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3528) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at android.widget.TextView.setText(TextView.java:3503) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at com.example.sampleproject.MainActivity$1.run(MainActivity.java:33) 
05-26 21:11:47.244: E/AndroidRuntime(14310): at java.lang.Thread.run(Thread.java:864) 
05-26 21:11:47.284: D/memalloc(14310): ion: Mapped buffer base:0x5432a000 size:2088960 offset:0 fd:66 
+2

mostra errore logcat. –

risposta

4

A causa di una condizione di competizione.

In sostanza, l'arresto si verifica quando la vista tenta di invalidare se stessa in un thread errato. setText() non invalida la visualizzazione a meno che la vista non sia stata misurata almeno una volta e lo TextView abbia un valore non nullo mLayout.

Quando si crea una nuova gerarchia di viste con setContentView(), il messaggio che misura le viste viene pubblicato sulla coda del thread dell'interfaccia utente, ma è probabile che il thread venga eseguito prima che il passaggio di misura abbia creato un layout per la visualizzazione del testo.

Per ulteriori dettagli, consultare source.

0

Non è possibile aggiornare UI da un altro thread, utilizzare questo invece

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    final TextView tv = (TextView) findViewById(R.id.tv); 
    Thread t = new Thread(new Runnable() { 

     @Override 
     public void run() { 

      runOnUiThread(new Runnable() { 

        @Override 
        public void run() { 
         tv.setText("This is the new text"); 
        } 
       }); 
     } 
    }); 
    t.start(); 
} 

Se vuoi sapere di più qui un buon articolo:

http://android-developers.blogspot.co.uk/2009/05/painless-threading.html

+1

Androidster ha già detto: "So anche come accedere alle viste del thread principale da un altro thread utilizzando AsyncTask, Handler, Activity.runOnUiThread (Runnable), View.post (Runnable), View.postDelayed (Runnable, long) ecc.". Ma vuole sapere perché il codice funziona senza dormire e non con esso. – userv

0

Prova exe cuting qualsiasi codice che interagisce con l'interfaccia utente in questo modo

runOnUiThread(new Runnable() { 
    @Override 
    public void run() { 
     // Put your UI interactions here 
    } 
}); 
0

sottostante Codice lavorando bene per me:

public class MainActivity extends Activity { 

     Handler handler = new Handler() { 
      @Override 
      public void handleMessage(Message msg) { 
       super.handleMessage(msg); 
       Bundle data = msg.getData(); 
       String result=data.getString("key"); 
       textview.setText(result); 
      } 
     }; 

     @Override 
     protected void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 

      final TextView tv = (TextView) findViewById(R.id.tv); 
      Thread t = new Thread(new Runnable() { 

       @Override 
       public void run() { 

        Bundle bundle=new Bundle(); 
        bundle.putString("key","you data"); 
        Message message=new Message(); 
        message.setData(bundle); 
        handler.sendMessage(message); 

       } 
      }); 
      t.start(); 

     } 
    }