I have a separate thread running to get data from the internet. After that, I would like to update the ListView in the main thread by calling adapter.notifyDataSetChanged().
The trick here is the position where you put the
mAdapter.notifyDataSetChanged();
Here a simple example :
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_view);
mAdapter = new myAdapter(......);
mAdapter.notifyDataSetChanged();
mRecyclerView.setAdapter(mAdapter);
this work for me perfectly.
Assume
yourActivity
is the activity that your widget has been placed into it,
yourView
is The widget and
adapter
is The widget's adapter:
yourActivity.runOnUiThread(new Runnable() {
public void run() {
try{
adapter.notifyDataSetChanged();
}
catch{}
}
}
Or, post a message to the listview's message queue (which would execute on the UI thread):
list.post(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
}
});
Use AsyncTask ( http://developer.android.com/reference/android/os/AsyncTask.html ).
Invoke adapter.notifyDataSetChanged() in onPostExecute(...) method.
For more details, please read this: http://android-developers.blogspot.com/2009/05/painless-threading.html
Overall good advice is http://android-developers.blogspot.com/2009/05/painless-threading.html
Personally I use my custom thread (a class extending Thread ) but send response to the UI thread through a Message. So in the thread's run() function there is:
Message msg;
msg = Message.obtain();
msg.what = MSG_IMG_SET;
mExtHandler.sendMessage(msg);
The UI thread defines a message handler.
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);
}
};
This is actually easier than AsyncTask.
You can use a combination of RxJava and Retrofit for this purpose.
Here's how you can do it. I will be using the GitHub API for the example.
Create a Java interface for your HTTP API.
public interface GitHubService {
@GET("users/{user}/repos")
Observable<List<Repo>> listRepos(@Path("user") String user);
}
Using Observable will convert the response into a stream. Every event being a List of repos.
Use Retrofit class to generate an implementation of the GitHubService interface. You may or may or may not provide a custom HTTP Client.
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);
Now comes the Rx part. You have to add a subscriber to listen to the responses sent back by the server. In other words, react to it.
service.listRepos("octocat")
.subscribeOn(Schedulers.io()) // 1
.observeOn(AndroidSchedulers.mainThread()) // 2
.flatMap(Observable::from) // 3
.subscribe(repoList -> { // 4
// Update the list view
// notifyDataSetChanged
});
Here's what the lines commented with numbers are doing -
1 - It tells the OS which thread to be used to make the call. We are choosing the IO thread for that.
2 - It tells the OS which thread to be used to listen for the response. We do that on the main thread, and update the UI on receiving a response.
3 - This line demonstrates the true magic of Rx. This simple little line converts a list of responses to single objects. Hence we will be reacting to every object instead of the whole list altogether. You can read more about it here.
4 - This line actually defines what kind of 'reaction' will be shown to the event. You can update the adapter here.
A more elaborate subscriber looks like this -
new Subscriber<Repo>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Repo repo) {
}
}
P.S. - I have used lambdas in the examples above. You can add that through here.