Android - Display progress bar when certain operation is done by another thread - android

How to block UI thread from doing anything and just displaying a progress bar until certain condition is met.
For example I have a list initialized to null, Lets call it list. I start another thread in UI to initialize its value which is going to take around 10 seconds. How can I block UI thread displaying progress dialog until the list is initialized.
// Initially
List list = null;
// Display progress bar until certain condition is met
while(list == null){
// Display progress dialog
}
I think AsyncTask will work if we ask that AsyncTask to update the list etc, what about another thread doing it. I have tried to simplify the problem.

you need to create a public method in mainActivity, named for examble yourcallback()
instead of instantiating all the objects in the OnCreate mainActivity, you can instantiate all objects in addition to quell ic you need for the progressbar in the callback method
yourcallback()
your callback
now you need to create an extenction of AsyncTask where you declare a base method constructor
like this
privte Activity mainObj;
public TestAsyncTask(Context context, Activity mainact ) throws Exception {
mainObj=mainact
your code
}
when the task naturally terminate the class AsyncTask call onPostExecute method
protected void onPostExecute(Long result) {
mainObj.yourcallback();
}
hope this help!

Related

Check if asynctask with Progress Dialog is finished in non activity class

I have a created non activity java class for doing same calculation from different activities. This class has asynctask with progress Dialog in it. In most cases calculation is not the last operation of activity and everything goes fine, but when it is my Progress Dialog goes lost.
Example:
myJavaClass doCalculations= new myJavaClass (SomeActivity.this);
doCalculations.Do(); //<------ method Do has asysctask with Progress Dialog
finish();
result:
java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView{2bbf820e V.E..... R......D 0,0-1026,483} not attached to window manager
How can I wait for asynctask to finish and then finish activity?
Additional question: Is using asynctask in non activity class is a bad practice ?
If you want to keep your activity active until the AsyncTask has finished its job, you can define a callback method in the activity that gets called when the task has finished and can react appropriately:
In the Activity:
private boolean finishAfterCurrentTask = false;
public void onTaskFinished() {
if (finishAfterCurrentTask) { // set this to true when running the last task
finish();
}
}
In the AsyncTask:
protected void onPostExecute(Object result) {
progressDialog.dismiss();
activity.onTaskFinished();
}
I'm assuming that you're keeping a reference to the activity in myJavaClass. In case that you're calling the AsyncTask from a non-UI thread, you should probably run the callback (and also all methods involving the dialog) via Activity.runOnUiThread().
As for the second question - if you use an AsyncTask in a class which methods can be called from a thread other than the UI thread, it's necessary to use runOnUiThread() to perform any operations on the UI, such as changing the contents of a view or showing/hiding a dialog, beause onPreExecute() and onPostExecute() are called from the same thread as execute().
On the other hand, if you start the task inside one of the UI callbacks, which are guaranteed to run on the UI thread, you don't need to worry about that.
The AsyncTask has a onPostExecute method you can finish the activity from there
protected void onPostExecute(Long result) {
progressDialog.dismiss();
finish(); // you'll probably have to call finish() with a callback function
}
The onPostExecute method is called when the doInBackground method is finished, on that method you can finish the activity and close the progressdialog

Make operation only when activity is running

I have a loading activity which makes few requests to server and converts data.
And layout of this activity is just simple logo image and progressBar.
All my operations were made in onCreate() and according to received request from server I start different activities:
if (request == 1) { start activity A}
else { start activity B}
The problem is loading takes 2-3 sec and operations are made even before onResume(), before activity's view come to UI.
So its just blank activity which does some work.
How can I ensure that those operations are made only after activity complete its creation?
If i clearly understand you you want to start activity 0 in which onCreate function is doing internet requests and after getting feedback from it you decide to call activity A or B. Is that correct? If yes you need to do network request in backgroud so your user interface thread doesnt freez. You can use AsyncTask for example and on it's onPostExecute method decide to fire acitivty A or B
EDIT
private class YourAsyncTask extends AsyncTask<String, Long, String> {
protected Long doInBackground(String... params) {
//here is background thread work calling net API request, hard working etc... but you can't touch UserInterface thread, since we are in background
//here call your API and parse answear
String ret = flag
return flag;
}
protected void onProgressUpdate(Long... progress) {
}
protected void onPostExecute(String result) { //here you are getting your flag from doInBackground as a result parameter
// this is executed after doInBackground, fired automatically and run on User interface thread here you can for example modify layout so you can run activity A OR B
}
}
and if you have your logic in AsyncTask you can run it from onCreate for example it doesn't matter.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
new YourAsyncTask().execute();
}
So you layot will be displayed and after executed your onPostExecute will be called
You need to move that server call off the main ui thread. Use an IntentService or something similar.
What I understand from this question, you must be using AsyncTask or Service to connect to server. You put the main thread in while loop and AsyncTask or Service is doing the required operation for you. After operation is complete, it will break out of while loop and then use if/else loop and decide which activity to start next.
Something like this:
public void onCreate(Bundle savedInstanceState)
{
boolean isDone = false;
// initialization code here
// start AsyncTask
BackgroundThread.execute(params);
while(!isDone)
{
Thread.sleep(1000); // 1 sec
}
}
doInBackground()
{
// your code
isDone = true;
}
onPostExecute() is executed on main thread, not on background thread.

Understanding the UI thread

I am a beginner to Android and I have some confusions regarding Android UI Thread. Now, I know that no thread apart from the one that created the UI can modify it.
Great.
Here is the Activity from my first Android app which slightly confuses me.
public class NasaDailyImage extends Activity{
public ProgressDialog modalDialog = null;
//------------------------------------------------------------------------------
#Override
protected void onCreate(Bundle savedInstanceState){
//Instantiate progress dialog, skipping details.
Button b = //get reference to button
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
modalDialog.show(); // show modal
Toast.makeText(getApplicationContext(), "Getting feeds", 500).show();
new AsyncRetriever().execute(new IotdHandler()); // Get the feeds !!
}
});
}
//------------------------------------------------------------------------------
public synchronized void resetDisplay(boolean parseErrorOccured,
boolean imageErrorOccured,
IotdHandler newFeeds){
if(parseErrorOccured || imageErrorOccured){
// make a Toast
// do not update display
}else{
// make a Toast
// update display
// based on new feed
}
}
//------------------------------------------------------------------------------
class AsyncRetriever extends AsyncTask<IotdHandler,Void,IotdHandler>{
#Override
protected IotdHandler doInBackground(IotdHandler... arg0) {
IotdHandler handler = arg0[0];
handler.processFeed(); // get the RSS feed data !
return handler;
}
//------------------------------------------------------------------------------
#Override
protected void onPostExecute(IotdHandler fromInBackground){
resetDisplay( // call to update the display
fromInBackground.errorOccured,
fromInBackground.imageError,
fromInBackground);
}
//------------------------------------------------------------------------------
}
1. onCreate is on the UI thread so I can do whatever I want but onClick is not. Why can I make a ProgressDialog and a Toast in that method? Why no error there?
2. The AsyncTask is subclass of the the NasaDailyImage. This means it can access all the methods of NasaDailyImage including resetDisplay() which updates the display. resetDisplay() is called in the onPostExecute which runs on a different thread from UI. So, why can I update the display there and yet get no errors ?
onClick() is indeed on the UI thread. Most of what happens in an Activity happens on the UI thread.
onPostExecte() (and its counterpart onPreExecute()) runs on the UI thread as well. The AsyncTask.onPostExecte() documentation clearly states this. AsyncTask was deliberately designed such that developers could update the UI before and after they do background work.
In general, your code will be running on the UI thread unless you explicitly tell it otherwise. Once you create AsyncTasks, Runnables, or Threads, you need to ensure you understand where your code is executing. In an Activity, it is typically safe to assume you are on the UI thread.
You are extending AsyncTask class , where async task class is calling its sequential method automatically. First onPreExecute then doBackground and finally onPost. If you want to change any ui change you can use onProgressUpdate method.
To use your activity class simple call activityclass.this.resetDisplay(). Because inner class scope sometimes failed to integrate except global varible.
Thanks

how to call a dialog from another dialog

I have a class on which I have a map object. I send this map object to a custom Dialog. After that I want to call another dialog from this dialog, but the second dialog is not showing. I don't know where i m doing wrong.
Activity :
dlgi = new MyCommunityServicesDialog(AppCentral.this, myValues, mapView);
dlgi.listDialog().show();
Custom Dialog :
Community_List_Dialog dialog = new Community_List_Dialog(context, getAllCommunityNames(selectedOpt).get(0), getAllCommunityNames(selectedOpt).get(1), mapView)
dialog.showDialog();
NOTE : This method (getAllCommunityNames(selectedOpt).get(0)/(1)) returns String[].
Custom Dialog Second :
public Dialog showDialog()
{
Log.i("listDialog calling...", "calling...");
final Dialog community_dialog = new Dialog(context);
community_dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
community_dialog.setContentView(R.layout.community_list);
ListView community_list = (ListView)community_dialog.findViewById(R.id.community_list);
adapter = new Community_List_Adapter(context,names);
community_list.setAdapter(adapter);
return community_dialog;
}
The solution to this problem was making use of the class
android.os.AsyncTask<Params, Progress, Result>
Description is given in die JavaDoc:
"AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers."
By using the methods onPreExecute() you can manipulate View on the UI Thread.
After finishing this method, doInBackground() is invoked and here you can start your background operations. This method is not working on the UI Thread, so it is not blocking your application.
After this onPostExecute() is invoked and you can use your computeted results.
My problem was to correctly show a progress indicator while the background oeprations are made. This can be done by making use of the onProgressUpdate() method, which is working ob the UI Thread, while the background computations are made.

Android How To Properly Notify Data Set Changed for ListView

I am trying to update my list and display the updated list in my activity. Every time I do so I get the following error
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.
Here is my code, I am using an AsyncTask to achieve this task. I call notifyDataSetChanged() on my adapter but it does not seem to work. What am I doing wrong?
class MyTask extends AsyncTask<Context, Integer, String> {
#Override
protected String doInBackground(Context... params) {
GregorianCalendar currentDateclone = (GregorianCalendar) currentDate.clone();
ListPopulater2.listPopulate(currentDateclone, 7, items, Id);
//method to update list info
}
// -- gets called just before thread begins
#Override
protected void onPreExecute() {
progressdialog = ProgressDialog.show(SectionListExampleActivity.this, "", "Loading..."); //display progress bar
super.onPreExecute();
}
// -- called as soon as doInBackground method completes
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.d("postExecute", "here");
adapter.notifyDataSetChanged();
progressdialog.cancel();
}
}
Try moving:
ListPopulater2.listPopulate(currentDateclone, 7, items, Id);
to your onPostExecute.
The reason that this worked is because you need to update the list after you've completed all your background activity, not while you are doing it. You can use the onProgressUpdate, but that is for your progress dialog. Updating you list view should be done after you have all you data, otherwise, you will get the error you did because the UI runs on the main thread, and you are trying to update it with the background thread.
As for the progress dialog, there is a purpose. If you are doing something that is going to take awhile to complete, the dialog will tell the user how close you are to completing the background task.
Hope that makes sense.
When Ever you want to do something which deal with the UI you have to do that task in UI thread.
So for this you can use 2 approach:
use runOnUi() method
Use OnPostExecute() method
And you have to use notifyDatasetchanged() at that place where you are setting adapter in listView.

Categories

Resources