2014-12-24 2 views
1

У меня есть приложение, имеющее фрагмент с ListView. Я ping IP-адреса в сети, и когда я получаю ответ, я добавляю IP-адрес в список. Как только я закончил pinging IP-адреса, я поместил этот список IP-адресов, которые ответили на мой пинг в ListView.Как обновить пользовательский интерфейс из фонового потока во фрагменте

Что я хочу сделать, это обновить этот ListView, поскольку я пингую, а не после того, как я пинговал все IP-адреса. Для ping IP-адресов я использую AsyncTask, который затем вызывает Runnable Thread. Как сообщить Фрагменту об обновлении пользовательского интерфейса из этого класса Runnable, когда я нахожу IP-адрес?

Грубая раскладка моих классов ниже.

public class FinderFragment extends ListFragment { 

    private void CallFind(){ 
     new Find().execute(); 
    } 

    private class Find extends AsyncTask<Void, Void, Void> { 

     @Override 
     protected Void doInBackground(Void... voids) { 
      SearchNetwork searchNetwork = new SearchNetwork(ipAddress); 
      try { 
       searchNetwork.StartFind(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

     @Override 
     protected void onPostExecute(Void aVoid) { 
      super.onPostExecute(aVoid); 
      UpdateDeviceList(); 
     } 
    } 
} 

public class SearchNetwork { 

    public void StartFind() throws InterruptedException { 
     Thread t[] = new Thread[20]; 
     for(int i=0; i<02; i++){ 
      t[i] = new Thread(new FindDevices(i*5)); 
      t[i].start(); 
     } 
     for(Thread thread : t){ 
      thread.join(); 
     } 
    } 

    class FindDevices implements Runnable{ 

     @Override 
     public void run() { 
      //Ping the IP addresses here 
      //I want to update UI from here 
     } 
    } 
+0

вы пробовали 'getActivity(). RunOnUiThread'? –

+0

используйте обработчик вместо него, пожалуйста, обратитесь к описанию threadSample google sample.https: //developer.android.com/training/multiple-threads/communicate-ui.html – mcd

ответ

0

использование Handler, runOnUiThread или View.post

android.os.Handler handler = new android.os.Handler(); 
     handler.post(new Runnable() { 
      @Override 
      public void run() { 
       //update here 
      } 
     }); 
+0

Извините, я только что начал изучать темы и AsyncTasks и до сих пор не полностью их понимают. Будет ли этот обработчик включен в мой класс FinderFragment? – user2144072

+1

Да, он доступен из любой темы. – SorryForMyEnglish

1

Вы должны использовать AsyncTask вместо сырых нитей! Существует метод onPostExecute(), который работает по основному потоку пользовательского интерфейса, и это тот момент, когда вы можете обновить свой интерфейс ...

Но вы должны иметь в виду, что вам нужно отменить AsyncTask (потоки также), если фрагмент будет уничтожен, в противном случае ваша задача продолжит работу и попытается изменить пользовательский интерфейс фрагмента, но фрагмент больше не существует, что приведет к исключениям, например IllegalStateException: Fragment not attached to Activity или View Not Attached Exceptions

+0

Я делаю это в данный момент. Я использую onPostExecute(), но обновляет ListView после завершения doInBackground.Я хочу обновить ListView во время выполнения doInBackground. – user2144072

+1

wtf? Очевидно, что вы делаете в 'doInBackground()', вы выполняете свою работу и обновляете список в 'onPostExecute()'. Я не уверен, что вы имеете в виду с «обновлением ListView после doInBackground()» ... Вы можете запустить 20 AsyncTasks, и каждый из них загружает данные в 'doInBackground()' и обновляет ListView впоследствии в 'onPostExecute()' или вы может написать один AsyncTask, который будет запускать 20 раз findDevices и использовать AsyncTasks 'onProgressUpdate()', который позволяет частично обновлять пользовательский интерфейс (работает на основном потоке пользовательского интерфейса) из doInBackground(), где 'onPostExecute()' вызывается только один раз после все – sockeqwe

1

Попробуйте это ....

getActivity().runOnUiThread(new Runnable(){ 
      @Override 
      public void run(){ 
       // Do whatever you want 
       } 
      }); 
+0

Использование класса Handler - хорошая практика –

1

Мы можем использовать Handler, runOnUiThread, postDelayed и AsyncTask.
AsyncTask - хороший вариант, отличный от остальных, поскольку он расширяет класс обработчика.
Когда вы должны кода в потоке использовать метод doInBackground() как это:

class myAsyncTask extends AsyncTask(Void,Void,Void){ 
    public doInBackground(){ 
     // do your code here 
    } 
} 

И называют его в потоке пользовательского интерфейса, как это:

new MyAsyncTask().execute(); 
0

если вы хотите автоматического обновления каждые х сек вам можно использовать это:

Runnable runnable = new Runnable() { 
     @Override 
     public void run() { 
      while(refreshing){ 
       handler.post(new Runnable() { 
        @Override 
        public void run() { 
         //do your stuff here 
        } 
       }); 
       try{ 
        Thread.sleep(30000); 
       }catch(InterruptedException e){ 
        e.printStackTrace(); 
       } 
      } 
     } 
    }; 
    new Thread(runnable).start(); 
0

Попробуйте

publishProgress()

и поймать его в overidden методе

@Override 
protected void onProgressUpdate(Void... values) { 
    super.onProgressUpdate(values); 
} 
Смежные вопросы