Обновление ListView в главном потоке из другого потока - PullRequest
12 голосов
/ 27 мая 2010

У меня запущен отдельный поток для получения данных из интернета. После этого я хотел бы обновить ListView в основном потоке, вызвав адаптер.notifyDataSetChanged (). Но это не работает. Любой обходной путь для этого? Спасибо.

Ответы [ 6 ]

13 голосов
/ 27 мая 2010

Использовать AsyncTask (http://developer.android.com/reference/android/os/AsyncTask.html).

Invoke adapter.notifyDataSetChanged () in onPostExecute (...) метод.

Для более подробной информации, пожалуйста, прочитайте это: http://android -developers.blogspot.com / 2009/05 / painless-threading.html

12 голосов
/ 13 февраля 2011

В целом хороший совет http://android -developers.blogspot.com / 2009/05 / безболезненным-threading.html

Лично я использую свой собственный поток (поток, расширяющий класс), но отправляю ответ в поток пользовательского интерфейса через Сообщение. Так что в функции потока () потока есть:

Message msg;
msg = Message.obtain();
msg.what = MSG_IMG_SET;                     
mExtHandler.sendMessage(msg);

Поток пользовательского интерфейса определяет обработчик сообщений.

private Handler mImagesProgressHandler;

public void onCreate(Bundle bundle) {

    mImagesProgressHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {             
            case LoadImagesThread.MSG_IMG_SET:
                mArrayAdapter.setBitmapList(mImagesList);
                mArrayAdapter.notifyDataSetChanged();
                break;
            case LoadImagesThread.MSG_ERROR:
                break;
            }
            super.handleMessage(msg);
        }
    };                 

На самом деле это проще, чем AsyncTask.

9 голосов
/ 09 января 2013

Или отправьте сообщение в очередь сообщений списка (которая будет выполняться в потоке пользовательского интерфейса):

list.post(new Runnable() {                  
    @Override
    public void run() {
       adapter.notifyDataSetChanged();

    }
}); 
3 голосов
/ 19 мая 2016

Вы можете использовать комбинацию RxJava и Retrofit для этой цели.

Вот как вы можете это сделать. Я буду использовать GitHub API для примера.

Создайте интерфейс Java для вашего HTTP API.

public interface GitHubService {
    @GET("users/{user}/repos")
    Observable<List<Repo>> listRepos(@Path("user") String user);
}

Использование Observable преобразует ответ в поток. Каждое событие - это список репо.

Используйте класс Retrofit для генерации реализации интерфейса GitHubService. Вы можете предоставлять или не предоставлять пользовательский HTTP-клиент.

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .client(okHttpClient) // OkHttp Client
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
            .build();

GitHubService service = retrofit.create(GitHubService.class);

Теперь идет часть Rx. Вы должны добавить подписчика для прослушивания ответов, отправленных обратно сервером. Другими словами, реагирует на него.

service.listRepos("octocat")
.subscribeOn(Schedulers.io()) // 1
.observeOn(AndroidSchedulers.mainThread()) // 2
.flatMap(Observable::from) // 3
.subscribe(repoList -> { // 4
    // Update the list view
    // notifyDataSetChanged
});

Вот что делают строки, прокомментированные числами -

1 - сообщает операционной системе, какой поток будет использоваться для вызова. Для этого мы выбираем поток ввода-вывода.

2 - Сообщает ОС, какой поток будет использоваться для прослушивания ответа. Мы делаем это в основном потоке и обновляем пользовательский интерфейс при получении ответа.

3 - Эта линия демонстрирует истинную магию Rx. Эта простая маленькая строка преобразует список ответов в отдельные объекты. Следовательно, мы будем реагировать на каждый объект, а не на весь список. Подробнее об этом можно прочитать здесь .

4 - Эта строка фактически определяет, какая «реакция» будет показана на событие. Вы можете обновить адаптер здесь.

Более сложный подписчик выглядит так -

new Subscriber<Repo>() {
    @Override
    public void onCompleted() {

    }

    @Override
    public void onError(Throwable e) {

    }

    @Override
    public void onNext(Repo repo) {

    }
}

P.S. - Я использовал лямбды в приведенных выше примерах. Вы можете добавить это через здесь .

2 голосов
/ 15 июля 2015

Предположим, yourActivity - это активность, в которую был помещен ваш виджет, yourView - это виджет и adapter - это адаптер виджета:

yourActivity.runOnUiThread(new Runnable() {
 public void run() {    
         try{
                adapter.notifyDataSetChanged();
         }
         catch{}
 }
}
0 голосов
/ 04 октября 2016

Хитрость здесь в том, что вы положили

mAdapter.notifyDataSetChanged ();

Вот простой пример:

mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
mAdapter = new myAdapter(......);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);

эта работа для меня отлично.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...