Android ListView freezes while loading data - java

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();

Related

Update ProgressDialog with ProgressBar after rotation

My application processes some images in a thread and meanwhile it shows a dialog with a progressbar.
progressDialog = new ProgressDialog(Activity.this);
progressDialog.setProgressStyle(size);
progressDialog.show();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < size; i++{
//process images
runOnUiThread(new Runnable() {
#Override
public void run() {
progressDialog.setProgress(i);
}
});
}
}
});
thread.start();
Now, if a rotation occurs I do
#Override
protected void onDestroy() {
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
super.onDestroy();
}
and in onCreate I recreate the dialog. But the thread don't changes the progressbar of this new dialog.
After rotation the Activity (or the Fragment) in which this dialog is shown is discarded and a new one is created.
You re-create the dialog in the new Activity, but the thread you started updates the dialog in the old one (the fact that this thread has a reference to the old dialog also constitutes a memory leak).
I'd suggest that you do the following:
Implement some ImageProcessor class and put an instance of it in Application object.
Make ImageProcessor class observable and notify the listeners about the progress.
Get a reference to this object in Activity and subscribe to notifications in onStart() (and unsubscribe in onStop()).
When status update notifications arrive - update the progress indication
Using this approach you'll have the processing logic encapsulate in a special object that survives rotation, and different components can invoke its methods and subscribe to notifications from it.

Updating an adapter from a background thread

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();
}
});

How can I show a Dialog box from a thread other than the UI thread

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.

add progress spinner to app boolean

In my code i have a boolean to install information to the database via preference. It works fine but the issue is now that have alot of information to add to the app and i get a black screen while the information is being added to the sqlite (only during installation). How can i add a progress spinner so the users will know the app is in the installation process. I am afraid they will think the app is broken when they stare at the black screen.
/** Insert list into db once */
if (pref.getBoolean("isFirst", true)) {
readBLContactsfromAssetsXMLToDB("list.xml");
pref.edit().putBoolean("isFirst", false).commit();
}
addQuickActions();
}
First you may use AsyncTask for doing processes that take long time. If you are not aware of it, it allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
But if you insist not to use that, then since you are blocking the UI thread, you cannot show the dialog and do your stuff at the same time. You need to have a background thread for the lengthy process, and show the progress dialog on the UI thread.
There are lots of examples of AsyncTaks online. Just for sample:
private class OuterClass extend Activity{
//....
#Override
public void onCreate(Bundle savedInstanceState) {
new performBackgroundTask ().execute();
}
//....
private class performBackgroundTask extends AsyncTask < Void, Void, Void >
{
private ProgressDialog dia;
// This method runs in UI thread before the background process starts.
#Override
protected void onPreExecute(){
// Show dialog
dia = new ProgressDialog(OuterClass.this);
dia.setMessage("Installing...");
dia.show();
}
#Override
protected Void doInBackground(Void... params) {
// Do all the stuff here ...
addQuickActions();
}
// Ececutes in UI thread after the long background process has finished
#Override
protected void onPostExecute(Void result){
// Dismiss dialog
dia.dismiss();
}
}
}
You may see How to display progress dialog before starting an activity in Android?
Hope this helps.

Showing a progressdialog in android while a large method is executed

I have a long running method that is called during onCreate, this method populates textviews so interacts with the UI, and updates maybe 70 labels (about 3-20 seconds depending on device).
I want to display a progressdialog as this method executes.
Ideally I want to fire my method on the UI thread once the Activity has been displayed and the progress is displayed, this I cannot do, the Activity won't paint until the method has finished.
I hoped to find an event which was fired after the activity was displayed, and I found the one below, but it still leaves the screen black until the method has finished.
#Override
public void onPostCreate(Bundle savedInstanceState)
I am normally a WP7 developer, and in .NET you add an event handler for onLoadComplete which is fired after the ui is displayed, but before the user has a chance to interact withthe UI, how do I do this in Android JAVA?
Thanks
Put a ProgressBar in the View.
Then in the onCreate() or onResume() method do this:
new Thread() {
public void run() {
yourLargeMethod();
}
}.start();
Now you can do this inside your method to update the progressBar
public void yourLargeMethod() {
// doSomething
...
runOnUiThread(new Runnable() {
public void run() {
// update the progress from the thread
progressBar.setProgress(x); // x is your progress, 0 <= x <= progressBar.getMax()
}
});
}

Categories

Resources