2012-06-21 16 views
103

Jestem nowy na Androida i próbuję użyć wątku UI, więc napisałem proste działanie testowe. Ale myślę, że coś źle zrozumiany, bo na kliknięcie przycisku - aplikacja nie reaguje jużJak korzystać z runOnUiThread w systemie Android?

public class TestActivity extends Activity { 

    Button btn; 
    int i = 0; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     btn = (Button)findViewById(R.id.btn); 
     btn.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       runThread(); 
      } 
     }); 
    } 

    private void runThread(){ 
     runOnUiThread (new Thread(new Runnable() { 
      public void run() { 
       while(i++ < 1000){ 
        btn.setText("#"+i); 
        try { 
         Thread.sleep(300); 
        } 
        catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 
     })); 
    } 
} 

Odpowiedz

165

Poniżej znajduje się poprawiona funkcja Snippet of runThread.

private void runThread() { 

    new Thread() { 
     public void run() { 
      while (i++ < 1000) { 
       try { 
        runOnUiThread(new Runnable() { 

         @Override 
         public void run() { 
          btn.setText("#" + i); 
         } 
        }); 
        Thread.sleep(300); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }.start(); 
} 
+0

Czy to nie było śmieci zebrane prawie natychmiast? Prawdopodobnie musisz zachować pewne odniesienie do wątku() – Nick

+9

@Nick: śmieciarz obserwuje również stos, tj. Gdy wątek jest uruchomiony, nie otrzyma GC. –

+0

@Vipul, miałem pytanie dotyczące rotacji telefonu: chcę, aby raz obracałem telefon, aby ten wątek działał i nie został utworzony nowy wątek. Czy możesz podać wskazówki, jak zapobiec tworzeniu nowego wątku po obróceniu telefonu? – user1836957

23

mieć go z powrotem do przodu. Kliknięcie przycisku powoduje wywołanie runOnUiThread(), ale nie jest to konieczne, ponieważ moduł obsługi kliknięć działa już w wątku interfejsu użytkownika. Następnie Twój kod w runOnUiThread() uruchamia nowy wątek w tle, w którym próbujesz wykonywać operacje interfejsu użytkownika, które następnie kończą się niepowodzeniem.

Zamiast tego wystarczy uruchomić wątek tła bezpośrednio z obsługi kliknięcia. Następnie zawiń połączenia pod numer btn.setText() w rozmowie z numerem runOnUiThread().

+0

Dziękuję, mam go teraz – user1049280

+1

Dobre wyjaśnienie – Blaasd

+0

Chociaż prawdą jest, że procedura obsługi kliknięcia jest już w wątku UI, wywołanie 'runOnUiThread()' jest niepotrzebne, ale powinno być nieszkodliwe. Javadoc dla tej metody mówi: "Uruchamia określoną akcję w wątku UI.Jeśli bieżący wątek jest wątkiem UI , akcja jest natychmiast wykonywana.Jeśli bieżący wątek jest , a nie wątek interfejsu użytkownika, akcja jest wysyłana do kolejki zdarzeń wątku UI. " – k2col

61

Po prostu zapakuj go jako funkcję, a następnie wywołaj tę funkcję z wątku tła.

public void debugMsg(String msg) { 
    final String str = msg; 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      mInfo.setText(str); 
     } 
    }); 
} 
+2

upvote dla znacznie mniej skomplikowanego kodu –

10
runOnUiThread(new Runnable() { 
       public void run() { 
       //Do something on UiThread 
      } 
     }); 
0

Można używać z tej próbki:

W poniższym przykładzie mamy zamiar korzystać z tego do publicznej wiadomości wyniki z wyszukiwania synonimów, który został przetworzony przez wątek tła.

Aby osiągnąć cel podczas wywołania działania OnCreate, skonfigurujemy onClickListener, aby uruchomić właściwość searchTask w utworzonym wątku.

Gdy użytkownik kliknie na przycisk Szukaj, będziemy tworzyć Runnable anonimowy klasę, która wyszukuje słowa wpisane w R.id.wordEt EditText i rozpoczyna wątek wykonać Runnable.

Po zakończeniu wyszukiwania utworzymy wystąpienie Runnable SetSynonymResult , aby opublikować wynik w synonimie TextView przez wątek interfejsu użytkownika.

Ta technika jest czasami nienajlepsza, szczególnie, gdy nie mamy dostępu do instancji Activity; dlatego w kolejnych rozdziałach omówimy prostsze i bardziej przejrzyste techniki aktualizowania interfejsu użytkownika z zadania obliczeniowego w tle .

public class MainActivity extends AppCompatActivity { 

    class SetSynonymResult implements Runnable { 
     String synonym; 

     SetSynonymResult(String synonym) { 
      this.synonym = synonym; 
     } 

     public void run() { 
      Log.d("AsyncAndroid", String.format("Sending synonym result %s on %d", 
        synonym, Thread.currentThread().getId()) + " !"); 
      TextView tv = (TextView) findViewById(R.id.synonymTv); 
      tv.setText(this.synonym); 
     } 
    } 

    ; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     Button search = (Button) findViewById(R.id.searchBut); 
     final EditText word = (EditText) findViewById(R.id.wordEt); 
     search.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       Runnable searchTask = new Runnable() { 
        @Override 
        public void run() { 
         String result = searchSynomim(word.getText().toString()); 
         Log.d("AsyncAndroid", String.format("Searching for synonym for %s on %s", 
           word.getText(), Thread.currentThread().getName())); 
         runOnUiThread(new SetSynonymResult(result)); 
        } 
       }; 
       Thread thread = new Thread(searchTask); 
       thread.start(); 
      } 
     }); 

    } 

    static int i = 0; 

    String searchSynomim(String word) { 
     return ++i % 2 == 0 ? "fake" : "mock"; 
    } 
} 

Źródło:

asynchronous android programming Helder Vasconcelos

0

To jak go używać:

runOnUiThread(new Runnable() { 
       @Override 
       public void run() { 
       //Do something on UiThread 
      } 
     }); 
2

Istnieje kilka technik Wykorzystanie runOnUiThread(), pozwala zobaczyć wszystkie

To jest mój główny wątek (wątek UI) cal Doprowadziło AndroidBasicThreadActivity i mam zamiar zaktualizować go z wątku pracowników na różne sposoby -

public class AndroidBasicThreadActivity extends AppCompatActivity 
{ 
    public static TextView textView; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) 
    { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_android_basic_thread); 

     textView = (TextView) findViewById(R.id.textview); 

     MyAndroidThread myTask = new MyAndroidThread(AndroidBasicThreadActivity.this); 
     Thread t1 = new Thread(myTask, "Bajrang"); 
     t1.start(); 
    } 
} 

1.) Przekazując instancji czy działalność jest jako argument na wątku roboczego

class MyAndroidThread implements Runnable 
{ 
    Activity activity; 
    public MyAndroidThread(Activity activity) 
    { 
     this.activity = activity; 
    } 
    @Override 
    public void run() 
    { 

     //perform heavy task here and finally update the UI with result this way - 
     activity.runOnUiThread(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread."); 
      } 
     }); 
    } 
} 

2.) Korzystając z metody Post w widoku (Runnable runnable) w wątku roboczym:

class MyAndroidThread implements Runnable 
{ 
    Activity activity; 
    public MyAndroidThread(Activity activity) 
    { 
     this.activity = activity; 
    } 
    @Override 
    public void run() 
    { 
    //perform heavy task here and finally update the UI with result this way - 
     AndroidBasicThreadActivity.textView.post(new Runnable() 
     { 
     @Override 
     public void run() 
     { 
      AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread."); 
     } 
    }); 

    } 
} 

3.) Używając klasy Handler z pakietu android.os Jeśli nie mamy kontekstu (this/getApplicationContext()) lub instancji Activity (AndroidBasicThreadActivity.this), to musimy użyć klasy Handler jak poniżej -

class MyAndroidThread implements Runnable 
{ 
    Activity activity; 
    public MyAndroidThread(Activity activity) 
    { 
     this.activity = activity; 
    } 
    @Override 
    public void run() 
    { 
    //perform heavy task here and finally update the UI with result this way - 
    new Handler(Looper.getMainLooper()).post(new Runnable() { 
     public void run() { 
      AndroidBasicThreadActivity.textView.setText("Hello!! Android Team :-) From child thread."); 
     } 
    }); 
    } 
} 
+0

niektóre wyjaśnienia mogły pomóc ... – eRaisedToX

0

thy to:

@UiThread 
    public void logMsg(final String msg) { 
     new Handler(Looper.getMainLooper()).post(new Runnable() { 
      @Override 
      public void run() { 
       Log.d("UI thread", "I am the UI thread"); 


      } 
     }); 
    } 
0
@Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     gifImageView = (GifImageView) findViewById(R.id.GifImageView); 
     gifImageView.setGifImageResource(R.drawable.success1); 

     new Thread(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        //dummy delay for 2 second 
        Thread.sleep(8000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 

       //update ui on UI thread 
       runOnUiThread(new Runnable() { 
        @Override 
        public void run() { 
         gifImageView.setGifImageResource(R.drawable.success); 
        } 
       }); 

      } 
     }).start(); 

    } 
Powiązane problemy