A few of my users (maybe 50) are getting crashes with the following error:
java.lang.IllegalStateException: The content of the adapter has
changed but ListView did not receive a notification. Make sure the
content of your adapter is not modified from a background thread, but
only from the UI thread.
If I understand correctly, it's caused by calling adapter.clear(); and adapter.addAll(list); in an AsyncTask's doInBackground() method, and I need to move it in the onPostExecute().
The problem is I can't reproduce that error, so I can't be sure if it's fixed. Some similar questions on StackOverflow seem to indicate that simply moving the updating the adapter to the onPostExecute() method doesn't solve the problem.
Does anyone know how I can make this error happen every time on my device to make sure the fix worked? I don't get it why it would work in most cases but only sometimes cause a crash.
Simple answer: you are forgetting to call adapter.notifyDatasetChanged().
Notifies the attached observers that the underlying data has been
changed and any View reflecting the data set should refresh itself.
Get your data in background and update your adapter in onPostExecute() because you should never change a content of the adapter from background thread. Both onPreExecute() and onPostExecute() are executed on the UI thread.
To reproduce the issue, try sleeping after making changes to your adapter in doInBackground().
For example:
#Override
protected Void doInBackground(Void... params) {
adapter.clear();
try
{
Thread.sleep(5000);
}
catch(InterruptedException e){}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter.notifyDatasetChanged();
}
You shouldn't call any UI things in doInBackground(..) method.
just call them in onPostExecute(..) as well as onPreExecute(..)
for example
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter.clear();
}
According to the AsyncTask documentation, in the "The 4 steps" paragraph.
onPostExecute(Result), invoked on the UI thread after the background
computation finishes. The result of the background computation is
passed to this step as a parameter.
Try this..
runOnUiThread(new Runnable() {
#Override
public void run() {
adapter.notifyDatasetChanged();
}
});
Related
I have tasks completed by AsyncTask in background. At some point I need to issue a Toast that something is completed.
I've tried and I failed because
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
How can I do that?
onPostExecute - executes on UI thread
or
publishProgress(); in your doinbackground and
protected void onProgressUpdate(Integer... progress) {
}
http://developer.android.com/reference/android/os/AsyncTask.html
you can Toast inside doInBackground
add this code where you want to Toast appear
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(<your class name>.this, "Cool Ha?", Toast.LENGTH_SHORT).show();
}
});
You can also use runOnUiThread method to manipulate your UI from background threads.
If you want to use Toast
You should use this method : onProgressUpdate()
protected Integer doInBackground(Void...Params) {
int check_point = 1;
publishProgress(check_point);
return check_point;
}
protected void onProgressUpdate(Integer integers) {
if(integers == 1) {
Toast.makeText(classname.this, "Text", 0).show();
}
If you want to display the Toast from the background thread you'll have to call runOnUiThread from doInBackground. I don't believe there's another way.
Edit: I take that back. I think you can implement onProgressUpdate, which runs on the UI thread, to show the Toast and make calls to publishProgress from doInBackground.
If you want to display the Toast in doInBackground, you can use it in the OnPostExecute method of AsyncTask.
protected void onPostExecute(String file_url) {
Toast.makeText(getApplicationContext(),"Your Message", Toast.LENGTH_LONG).show();
pDialog.dismiss();//dismiss the progress dialouge
}
I have an Android application with an AsyncTask which is responsible for downloading a file from the internet. This AsyncTask is executed when clicking on an item in a Listview. So I have a custom adapter and in the OnItemClickListener of the Listview, I start the download and execute the AsyncTask.
Now, my adapter contains the following code to start the AsyncTask named FileDownloader:
#Override
public void onClick(View view) {
try {
FileDownloader fd = new FileDownloader(activity);
// some irrelevant code here
String filepath = fd.execute("http://myurl.com/img.png", PDFFileName, GameHistoryAdapter.this.gameInfo.toString()).get();
}
catch(Exception e) { e.printStackTrace(); }
}
Activity is a private field that is passed to the adapter in the constructor of the adapter:
public GameHistoryAdapter(Activity a, int selectedIndex) {
this.activity = a;
}
The FileDownloader class contains an OnPreExecute method where I want to show the progress dialog on the activity:
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new ProgressDialog(activity);
dialog.setMessage("Downloading...");
dialog.setIndeterminate(true);
dialog.setCancelable(true);
dialog.show();
}
But whatever I try, the dialog does not appear. When I create an alert dialog in the OnPostExecute method of the AsyncTask, the dialog will show.
#Override
protected void onPostExecute(String res)
{
super.onPostExecute(res);
dialog.hide();
new AlertDialog.Builder(activity)
.setTitle(activity.getString(R.string.save_pdf_title_text))
.setMessage(activity.getString(R.string.save_pdf_text) + PDFFileName)
.setPositiveButton(activity.getString(R.string.close_text), null)
.setIcon(android.R.drawable.ic_dialog_info)
.show();
}
Does anyone know why the dialog is not appearing on my activity?
Does anyone know why the dialog is not appearing on my activity?
Yes, the following line of code...
String filepath = fd.execute("http://myurl.com/img.png", PDFFileName, GameHistoryAdapter.this.gameInfo.toString()).get();
Don't EVER use the get() method of AsyncTask. It will block the main / UI thread and makes the whole point of an AsyncTask redundant. In other words get() turns it into a synchronous process instead of an asynchronous one.
The fact you can show a dialog in onPostExecute(...) is simply because it will be called after the blocking call to get() has returned. This means the main / UI thread will no longer be frozen (blocked) and UI updates can be made once again.
Remove get() from your call to execute(...) and instead just use...
fd.execute("http://myurl.com/img.png", PDFFileName, GameHistoryAdapter.this.gameInfo.toString());
...then in your onPostExecute(...) method set you filepath variable to what it should be.
I don't know who added the get() method to AsyncTask but if I ever find them I'll have some serious words to say. It has little or no use and causes a lot of people a lot of confusion.
My app requires gps reading, so on the main thread I start a Thread that reads the GPS but I'm having trouble showing a dialog that says "Please wait". I tied also using a Handler, but that didn't work either. What's the best to control the "Please wait" dialog from the 2nd Thread? Thanks!
public void showWaitDialog() {
prgDialog = new ProgressDialog(context);
prgDialog.setTitle("Please wait.");
prgDialog.setMessage("Please wait.");
prgDialog.setCancelable(false);
prgDialog.show();
}
You can:
Define an Handler in your UI Thread (e.g. in the Activity) and then pass it to your thread. Now from the thread you call handler.post(runnable) to enqueue code to be executed on the UIThread.
Define a BroadcastReceiver in your Activity and from you thread send an Intent with the necessary information in the Bundle
Use an AsyncTask and the methods publishProgress(), onProgressUpdate() or onPostExecute() to inform the Activity of the progress or when the taask has finished
Use runOnUiThread.
It depends on your needs. For short-running asynchronous operations, AsyncTask is a good choice.
Why not use an AsyncTask. You can tell the Task on onPreExecute() to show the Please wait dialog, and then onPostExecute(Result result) you can remove the dialog. Those two methods are working on the UI thread while doInBackground(Params... params) is occurring in a background thread.
Example:
private class GetGPSTask extends AsyncTask<null, null, null>{
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
showWaitDialog(); <-Show your dialog
}
#Override
protected void doInBackground(null) {
//your code to get your GPS Data
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
HideDialogbox(); <-Code to hide the dialog box
}
}
Just remember to change the template types if you need to. Where it says AsynTask , the first value is passed to doInBackground, 2nd value is for progress value, 3rd value is a return value from doInBackground to onPostExecute.
As other answers have rightly suggested, you can preferably use AsyncTask. Here is an exampleof how to use it for your purpose: AsyncTask Android example. Otherwise you may use runOnUiThread method as well. From inside your second thread to make the changes on UI thread ( eg: Dialogs and Toasts). According to its documentation, it says:
It runs the specified action on the UI thread. If the current thread is the UI thread, then the action is executed immediately. If the current thread is not the UI thread, the action is posted to the event queue of the UI thread.
For eg;
Your_Activity_Name.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// your stuff to update the UI
showWaitDialog();
}
});
See display progressdialog in non-activity class and Loading Dialog with runOnUiThread for update view on Android.
hope this helps.
I want to show an progresscircle while a chat is loading. So I put some progressbar in, visibility set to invisible. Now I set in onPreExecute() the visibility to visible and in onPostExecute() to invisible.
The circle is shown, but just when the chat already did load AND it doesnt disappear. Can someone tell me my mistake? :o
#Override
public void onPreExecute() {
MainActivity.pbReadChat.setVisibility(ProgressBar.VISIBLE);
}
#Override
public Map<String, ArrayList<String>> doInBackground(String... strings) {
//...
return result;
}
public void onPostExecute(Map<String, ArrayList<String>> result) {
super.onPostExecute(result);
MainActivity.pbReadChat.setVisibility(ProgressBar.INVISIBLE);
}
Edit: Now it disappears but it gets just shown after chat already did load in doInBackground()
That are the important things of my Async class I think, hope someone can help me
Your onPostExecute() is not being called because doInBackground() does not return. It can happen because of one of the reasons below:
Infinite loop.
Infinite wait for an input.
Unchecked exception.
cancel() being called on AsyncTask. In this case, onCancelled() is called instead of onPostExecute()
i am using a custom listview with images in my app
and loading all data from a json url.
i have created a onscrollistener()
which automatically add data below the current data when user scrolls to the bottom of the listview.
But when my data is loading whole listview freezes for 2-3 sec.
I dont know whats wrong??
here is my code for AsyncTask
private class BackgroundLoadMore extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
// Showing progress dialog before sending http request
}
protected Void doInBackground(Void... unused) {
runOnUiThread(new Runnable() {
public void run() {
LoadData();
list.setOnScrollListener(new EndlessScrollListener());
}
});
return (null);
}
protected void onPostExecute(Void unused) {
// On completing background task
// closing progress dialog etc,.
}
You must be fetching the json data from url in main UI thread. This blocks the UI from being updated by system, and hence the freeze. Use AsyncTask to do such network tasks in background.
LoadData() should be called in a background thread, which is asynctask's doInBackground(). Your call runOnUIThread puts it back on the UI thread, and that you dont want. remove the runOnUIThread call from asynctask.
protected Void doInBackground(Void... unused) {
LoadData();
return (null);
}
protected void onPostExecute(Void unused) {
// On completing background task
// closing progress dialog etc,.
list.setOnScrollListener(new EndlessScrollListener());
}
Move LoadData(); out of
runOnUiThread(new Runnable() {
public void run() {}
};
doInBackground is performing in the worker thread, but in it you use runOnUiThread wich start a UI therad operations.
You have to load all the data from net in background thread and then in postExecute update your listview
You are probably loading your data inside the UI thread.
Since operations such as loading JSON data from the internet are slow (from 0.5-10 seconds is typical) then if you do that inside the main thread of your app, the user interface will stop responding for this time. You should use a Thread or AsyncTask to load the JSON data asynchronously and so keep the UI thread free to respond to user input (such as scrolling the list).
My suggestion is that you use an AsyncTask to load the data.
Here are some links:
AsyncTask documentation
AsyncTask example
See the accepted answer for this question to see an implementation
Edit
Put list.setOnScrollListener(new EndlessScrollListener()); and list.notifyDatasetChanged(); inside onPostExcecute();