AsyncTask not locking main thread? - android

I'm using following code to fill a custom ListPreference dialog. Since the fill procedure takes a lot of time i want to show a progress dialog during the fill procedure.
My problem is that filler.execute() does not block onPrepareDialogBuilder and functions goes till the end before values are filled causing an exception... Any idea?
#Override
protected void onPrepareDialogBuilder(Builder builder) {
// Load data
if (this.getEntries()==null) {
FillerTask filler = new FillerTask();
filler.execute();
}
Log.d(TAG, "Filler finished");
super.onPrepareDialogBuilder(builder);
}
Here is Filltertask code, basically he looks for every activity with a MAIN Intent filling a list:
private class FillerTask extends AsyncTask<Void, Void, String[][]> {
private ProgressDialog dialog;
#Override
protected void onPreExecute() {
Log.d(TAG, "Dismiss dialog");
dialog = ProgressDialog.show(MyListPreference.this.getContext(), "", "Doing stuff...", true);
}
#Override
protected String[][] doInBackground(Void... params) {
return fill();
}
public String[][] fill() {
Log.d(TAG, "Fill started");
CREATE LISTS...
// Done
Log.d(TAG, "Fill done");
String[][] result = new String[][] {entryNames, entryValues};
return result;
}
#Override
protected void onPostExecute(String[][] result) {
Log.d(TAG, "Post execute");
MyListPreference.this.setEntries(result[0]);
MyListPreference.this.setEntryValues(result[1]);
dialog.dismiss();
}
}

My problem is that filler.execute() does not block onPrepareDialogBuilder and functions goes till the end before values are filled causing an exception... Any idea?
That is the entire point behind an AsyncTask. The "Async" in AsyncTask means asynchronous.
Use your AsyncTask to get your data. Then, in onPostExecute(), display the dialog.

Found the solution, best way to do this is override the onClick method and let the AsyncTask postExecute call the "super()", so click is not passed until content is loaded and during load progress bar is correctly displayed.

asyntask doesn't lock main thread, it just drops a message to message queue of main thread

Related

Waiting until user actually sees something on the screen

I've got a main Activity, an extra class for my fragment, and inside this fragment is an AsyncTask, which gathers data from various android library (Wifi SSID, BSSID, etc). When I start my app the app shows a blank screen, without any UI. Then after about 2 seconds, the whole data is being shown. I actually want to display my TextViews as "Not connected to a wifi network" in the background, while showing a ProgressDialog until the data is being displayed. I've got the ProgressDialog in my MainActivity, and calling it in my AsyncTask onProgressUpdate
MainActivity.progressDialog = ProgressDialog.show(MainActivity.c,
"ProgressDialog Title",
"ProgressDialog Body");
I'm updating my TextViews in the doInBackground methode (via another methode outside the Fragment)
((Activity) getActivity()).runOnUiThread(new Runnable() {
Would be too big a comment so i'll just put it here.
Sounds like you are using both fragment and AsyncTask in an incorrect way. You should never do anything UI relevant in doInBackground.
Here is an example of what you could do.
I assume the following scenario:
You have a main activity
You have a fragment containing TextViews
You wish to populate the TextViews after loading some data using AsyncTask with a progressDialog
The approach would be to:
Add the fragment in onCreate of your activity (if the fragment is not defined in the layout, then it will automatically be added).
Create the AsyncTask in your fragment like this:
private class LoadData extends AsyncTask<Void, Void, List<String>> {
ProgressDialog progressDialog;
//declare other objects as per your need
#Override
protected void onPreExecute()
{
// getActivity() is available in fragments and returns the activity to which it is attached
progressDialog= new ProgressDialog(getActivity());
progressDialog.setTitle("ProgressDialog Title");
progressDialog.setMessage("ProgressDialog Body");
progressDialog.setIndeterminate(true)
progressDialog.setCancelable(false)
progressDialog.show();
//do initialization of required objects objects here
};
#Override
protected Void doInBackground(Void... params)
{
List<String> results = new ArrayList<String>();
//do loading operation here
//add each of the texts you want to show in results
return results;
}
// onPostExecute runs on UI thread
#Override
protected void onPostExecute(List<String> results )
{
progressDialog.dismiss();
// iterate results and add the text to your TextViews
super.onPostExecute(result);
};
}
Start the AsyncTask in onCreate of your fragment:
#Override
public void onCreate(Bundle savedInstanceState) {
new LoadData().execute();
super.onCreate(savedInstanceState);
}
This way you avoid calling directly back to your activity, which really should not be necessary in your scenario (unless I have misunderstood).
Otherwise please post all the relevant code and layouts.
This line:
I'm updating my TextViews in the doInBackground methode
points to your problem. You need to use the AsyncTask method onProgressUpdate() to publish to the UI thread. You do not call onProgressUpdate() directly, instead you call publishProgress().
Interestingly, I answered a similar question yesterday here: android AsyncTask in foreach
and it includes an example.
Here's what you need to do.
(1) From the place you run the code that gathers data, you should first display the progress dialog. Something like this:
busy = new ProgressDialog (this);
busy.setMessage (getString (R.string.busy));
busy.setIndeterminate (true);
busy.setCancelable (false);
busy.show();
(2) Then you start your data gathering. This must be done in a separate thread (or Runnable). Do something like this:
Thread thread = new Thread ()
{
#Override
public void run()
{
try
{
... gather data ...
Message msg = handler.obtainMessage();
msg.what = LOADING_COMPLETE;
msg.obj = null;
handler.sendMessage (msg);
}
catch (Exception e)
{
Message msg = handler.obtainMessage();
msg.what = LOADING_FAILED;
msg.obj = e.getMessage(); // maybe pass this along to show to the user
handler.sendMessage (msg);
}
// get rid of the progress dialog
busy.dismiss();
busy = null;
}
}
(3) Add a handler to the activity to receive notification when data gathering is complete:
Handler handler = new Handler()
{
#Override
public void handleMessage (Message msg)
{
if (msg.what == LOADING_COMPLETE)
loadingComplete ();
else if (msg.what == LOADING_FAILED)
loadingFailed ((String)msg.obj);
}
};
(4) Implement the handlers:
private void loadingComplete ()
{
...
}
private void loadingFailed (String errorMessage)
{
...
}
That's the essentials.

How to know when my Activity is fully created?

I've an Activity that contains a lot of data and elements.
When it has too information, the activity wait in white for be shown, that is not I want, I actually want to show a activity while it's loading the data.
So, How can I to know when my activity it's fully created?
My intention is to launch in a second thread the activity across the waiting activity.
You should load that data asynchronously, in another thread if it takes that much time to load. Launch another thread (by using an AsyncTask for example of plain Java Threads), load the data and show some loading-View on the Activity that notifies the user that something is happening in the background.
You can use AsyncTask and can show progress dialog till the data is loaded.
private class FetchRSSFeeds extends AsyncTask<String, Void, Boolean> {
private ProgressDialog dialog = new ProgressDialog(HomeActivity.this);
protected void onPreExecute() {
this.dialog.setMessage(getResources().getString(
R.string.Loading_String));
this.dialog.show();
}
protected Boolean doInBackground(final String... args) {
try {
// Fetch the data from URL
// do background process
return true;
} catch (Exception e) {
Log.e("tag", "error", e);
return false;
}
}
#Override
protected void onPostExecute(final Boolean success) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (success) {
// Setting data to list adaptar
setListData();
}
}
This method called after on create in activity
#Override
public void onStart() {
super.onStart();
}

How to show ProgressDialog across launching a new Activity?

Goal: Have a ProgressDialog which shows "Loading..." until next Activity is completely loaded and shown on screen.
Tried with ProgressDialog context and activity set to originating Activity. Also tried with getApplicationContext() and getParentContext(). Exceptions on the last two approaches. Need to do this as destination Activity is slow to render due to non-simple Layout file. (Cannot fix that right now due to organizational issues.) Turns out the destination Activity takes 1-2 seconds to OnCreate and then screen goes black for up to 5+ seconds then it paints. The rendering is just slow. Did review with Hierarchy Viewer and see lots of red balls but can't fix now.
Read up on some related but haven't found a fix. E.g. What's the difference between the various methods to get a Context?
E.g. both of these crash. Using the "this" of source Activity doesn't work either.
// Context parentContext = this.getParent().getBaseContext();
Context parentContext = this.getApplicationContext();
ProgressDialogMenuable theProgressDialog = new ProgressDialogMenuable(parentContext,this);
theProgressDialog.setTitle("yeeha");
theProgressDialog.setMessage("weewah");
theProgressDialog.setIndeterminate(true);
theProgressDialog.setCancelable(true);
theProgressDialog.show();
Also, oddly, nothing happens when I do this:
theProgressDialog.show();
ActivityHelper.changeActivity(this, v, InsMyHoldingsActivity.class, extraMap, -1, -1);
User clicks button to show next activity but the ProgressDialog conflicts with the Activity launch and nothing actually happens other than the button becoming yellow ontouch. Button below works. removing ProgressDialog creation and it works. No console messages logged. A little offputting to the developer for sure.
You can show a progress dialog like this -
Define this
private ProgressDialog pd = null;
in your activity class
Put this in your onCreate (Dont setContentView directly here)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.pd = ProgressDialog.show(this, "Fancy App",
"Loading...Please wait...", true, false);
// Start a new thread that will download all the data
new IAmABackgroundTask().execute();
}
// Background heavy lifting
class IAmABackgroundTask extends
AsyncTask<String, Integer, Boolean> {
#Override
protected void onPreExecute() {
// showDialog(AUTHORIZING_DIALOG);
}
#Override
protected void onPostExecute(Boolean result) {
// Pass the result data back to the main activity
ActivityName.this.data = result;
if (ActivityName.this.pd != null) {
ActivityName.this.pd.dismiss();
}
setContentView(R.layout.main);
}
#Override
protected Boolean doInBackground(String... params) {
//Do all your slow tasks here but dont set anything on UI
//ALL ui activities on the main thread
return true;
}
}
Also go through this :http://developer.android.com/training/improving-layouts/index.html for optimizing layout performance.
Also Use Traceview to look for bottlenecks
There is two ways to
First approach To use Async Task
If you are doing heavy tasks eg loading data from server or parsing xml in that case use AsynTask<> If you want to call ActivityB from ActivityA then
*step-1*create a AsyncTask class. write all background tasks inside doBackground() method and after completion of task you want to call an activity that code write inside onPostExecute() post execute method
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.view.View;
public class LoadingDataFromServer extends AsyncTask {
Context currentContext = null;
boolean isCancelled = false;
public LoadingDataFromServer(Context context) {
currentContext = context;
}
#Override
protected void onPreExecute() {
if (DashboardActivity.progressBarLayout != null) {
DashboardActivity.progressBarLayout.setVisibility(View.VISIBLE);
// Log.i(TAG,".....Now make progress bar visible.....");
}
super.onPreExecute();
}
#Override
protected Object doInBackground(Object... params) {
// do background processing
try {
// do background tasks eg sever communication
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Object result) {
// TODO Auto-generated method stub
// progressDialog.dismiss();
// call second Activity
Intent i = new Intent(currentContext, com.ActvityB.class);
super.onPostExecute(result);
}
#Override
protected void onCancelled() {
// TODO Auto-generated method stub
isCancelled = true;
super.onCancelled();
}
}
step-2 In the activity fro where you want to jump to new activity (eg in ActivityA) call the execute() of AsynTask
new LoadingDataFromServer(context).execute(null);
Second approach
First show progress dialog.
create a thread to do all background tasks. when the thread completes the task then cancel the progress dialog and call the next activity
or
when thread complets the task then call next activity pass this object (progress dialog) and inside that new activity dismiss this dialog.
Here is my code that can help.
In this, I'm only posting the first method of AsyncTask i.e onPreExecute.
User_AsyncTask extends AsyncTask:
public class User_AsyncTask extends AsyncTask<String, String, String>
{
String response = "";
#Override
protected void onPreExecute()
{
try
{
if (progressDialog != null)
progressDialog.cancel();
}
catch (Exception e)
{
}
progressDialog = ProgressDialog.show(DisplayDetails.this, "", "Please wait...", true, true);
progressDialog.setCancelable(false);
progressDialog.show();
}

ProgressDialog communicate with AsyncTask in android

Tips or ideas on how ProgressDialog can communicate with asyncTask.
For example when I click the button, the program will validate the input to internet, This is should not be interupted. so I use ProgressDialog.
After progressDialog.dismiss(), I need to refresh the view by calling the asyncTask.
I have tried some ways but it's failed, for example
* I execute asynTask after progressdialog.dismiss().
* put execution asynctask inside dialogbox after progressdialog thread.
in other word, is there any way to tell asynctask that progressdialog has been dismissed. Or is there communication such as message between threads ?
here is the example of my code:
btnPost.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
stockProgressDialog = ProgressDialog.show(PostActivity.this,
"Please wait...", "Check the post");
new Thread() {
public void run() {
try{
/* Connect to Internet API */
stockProgressDialog.dismiss();
} catch (Exception e) { }
// Dismiss the Dialog
}
}.start();
new LookUpTask().execute();
}
});
Yes, there is a way to tell asyncTask that progressDialog has been dismissed. you can use one onDismissListener
#Override
public Dialog onCreateDialog(int id){
if(id==DIALOG_PROGRESS_DIALOG){
stockProgressDialog = new ProgressDialog(Main.this);
stockProgressDialog.setTitle("Please wait...");
stockProgressDialog.setMessage("Check the post");
stockProgressDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
#Override
public void onDismiss(DialogInterface dialog) {
textView.setText("Waiting the 5 secs...");
myAsyncTask.execute("start it");
//Or myAsyncTask.cancel(true); if you want to interrupt your asyncTask
}
});
return stockProgressDialog;
} else return super.onCreateDialog(id);
}
You can cancel an AsyncTask by calling AsyncTask.cancel(..) and then start up a new AsyncTask. You are not supposed to run the AsyncTask as a parallel activity - it is supposed to be able to run and finish without outside intervention.
Extend async and look into returning a result from doInBackground. onProgress update can dismiss your Progress dialog under control of the async task. Handle the result from doInBackground in onPostExecute.
//create the task
theBackground = new Background();
theBackground.execute("");
--------
private class Background extends AsyncTask<String, String, String>{
protected String doInBackground(String...str ) {
publishProgress("##0");
//do a bunch of stuff
publishProgress(#001);
return("true");
}
protected void onProgressUpdate(String... str ) {
//do stuff based on the progress string and eventually
myProgressDialog.dismiss();
}
protected void onPostExecute(String result) {
}
}
I'm not sure why you're using a thread in one case, but an AsyncTask in another when you could just use two AsyncTasks... Actually, unless I'm missing something, in your case the most straightforward way is to combine the two bits of work into one AsyncTask and simply create and destroy the dialog in the AsyncTask callbacks. In pseudo-code:
onPreExecute
show dialog
doInBackground
do internet stuff
onPostExecute
update views
close dialog
Is there a reason why you're trying to update the views in its own AsyncTask? If you're updating views, you probably need to do the work in the UI thread anyway...

Show a progress bar when an Activity is loading

I have a ListActivity which launches another Activity based on the list selection. This second Activity needs to load a fair bit of data from the internet and as such there is a noticeable delay between when the user clicks on an item and when the Activity displays.
This is a problem because I currently have no way to indicate to the user that their click is being processed (even just changing the colour of the selected list item would be sufficient but I can't find a good way to do that). Ideally I'd be able to display an indeterminate ProgressDialog while the second Activity is loading.
I've tried a few different approaches for this but nothing seems to work as desired.
I've tried the following:
Retrieving the serializable data (not all of it but some part) in an AsyncTask in the first Activity and passing it as an extra to the second. This didn't really work well as a ProgressDialog I created in onPreExecute() didn't display immediately (it seems delayed by the processing done in doInBackground() for some reason.)
Here is the code for that:
AsyncTask<String, Void, String> read = new AsyncTask<String, Void, String>() {
Dialog progress;
#Override
protected void onPreExecute() {
progress = ProgressDialog.show(SearchActivity.this,
"Loading data", "Please wait...");
super.onPreExecute();
}
#Override
protected String doInBackground(String... params) {
DatasetReader reader = new DatasetReader();
reader.setFundID(params[0]);
reader.addDatsets(FundProfile.datasets);
reader.populate();
return reader.toString();
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progress.dismiss();
}
};
read.execute(selectedItem.getUniqueID());
try {
action = new Intent(SearchActivity.this, FundProfile.class);
action.putExtra("data", read.get());
} catch(Exception ex) {
ex.printStackTrace();
}
In the second Activity's onCreate() method (this does not work at all):
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarVisibility(true);
Here is the onCreate() method for the second approach:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setTitleColor(Color.WHITE);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarVisibility(true);
try {
setContentView(R.layout.fund_profile);
// init some data
setProgressBarVisibility(false);
} catch(Exception ex) {
FundProfile.this.finish();
}
}
If you have long operations you should not be doing them in onCreate in any case as this will freeze the UI (whether or not the activity is displayed). The UI set by onCreate will not appear and the UI will be unresponsive until after the onCreate call finishes.
It seems you can start your second activity and display a progress bar (or requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);), then start an ASyncTask which will be responsible for updating your UI once data has been retrieved.
Adam,
It sounds like you are looking for the Indeterminate Progress bar: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/view/ProgressBar2.html
You can display this while you are loading your second Activity then set the visibility to false once the second Activity has loaded its data.
Move creating the Intent -- and really anything you need to do after the AsyncTask completes -- into onPostExecute:
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
progress.dismiss();
Intent action = new Intent(SearchActivity.this, FundProfile.class);
action.putExtra("data", result);
// ... do more here
}
The problem is that AsyncTask.get() blocks until the task is completed. So in the code above, the UI thread is blocked and the ProgressDialog is never given a chance to appear until the task completes.

Categories

Resources