Alertdialog isShowing always returns false - android

public class myActivity extends Activity
{
private static AlertDialog somedialog = null;
protected void onCreate(Bundle savedInstanceState)
{
somedialog = new AlertDialog.Builder(ctx).create();
innerclass = new innerclass();
innerclass.start();
}
private class innerClass extends Thread
{
if (!somedialog.isShowing())
{
runOnUiThread(new Runnable()
{
somedialog.setMessage("test");
somedialog.show();
}
}
}
}
I have this code where I have a dialog which needs to show only if the dialog is not already there. The dialog is only shown by the innerClass. There is no other method which invokes this somedialog object.
I expect the dialog to appear for the first time and to reappear only if the previous dialog has been closed, however I find there are multiple dialogs stacked on.
For some reason the isShowing method is returning false even if the dialog is open.
Any ideas as to why this is happening?
However when this code is executed somedialog.isShowing() is always returning false and hence I get multiple dialogs on top of each other.

You are creating a new instance of AlertDialog every time
new AlertDialog.Builder(ctx).create();
and checking isShowing() before it showing. As a result it always return false.

It's possible there are some issues introduced by your multi-threading, and the value of isShowing() being cached as it is read between threads. I can't see the purpose of innerClass from your example, and would simply remove it. This would also be akin to:
private class innerClass extends Thread {
runOnUiThread(new Runnable() {
if(!someDialog.isShowing()) {
somedialog.setMessage("test");
somedialog.show();
}
}
}
Also, you shouldn't keep a static reference to your AlertDialog - there's no need, it wont play nicely with the lifecycle of your Activity, and it's a memory leak waiting to happen.

Thanks for everyone who tried to help me out in this query. It finally turns out to be silly coding error # midnight. I have multiple runOnUiThreads inside the innerclass thread, in one of them the alert object was being re-created.

Related

OnSaveInstanceState/ RestCalls

I am relatively new to Android development, and I have a question about onSaveInstanceState(). I am currently working on a login Activity for an app. To check to see if the user can login to their account, I perform a rest call to a server and, based on the response-code, see if I should grant access to the user. The root of my question is based on the fact that I am trying to avoid passing the Activity's Context to my rest-call class. To do this, I create a boolean field in my login Activity representing whether or not the rest-call was successful and a runnable that updates said boolean that I pass to the rest-call class. I know this goes against the idea of an AsyncTask, but I can't find any alternative to simply putting up a dialog box telling the user to wait while this happens. My questions are below.
1) If I use savedInstanceState() in the onCreate method, how do I instantiate this boolean field for the first time barring null checking an Object boolean? What I mean by this is that after the Activity is destroyed for whatever reason (such as orientation change, etc...) I will use the boolean value stored in my overriden onSaveInstanceState method; however, when it is created for the first time, it has no reference to a boolean value so it has to create one.
2) Does this Runnable even help? I did it so that I wouldn't have to pass the context, but if the Activity is going to be deleted before the RestCall(AsyncTask) is complete, does it really matter whether you pass the context or a Runnable affecting a field of the Activity? The more I think about this, the more I believe it is not going to make much of a difference as it will still result in it pointing to a non-existent object. I am trying to avoid using a Singleton design as I have gathered it is not optimal, but because of the potential lag in time with an AsyncTask, I am beginning to think that it may not be avoidable.
I know onSaveInstanceState() is a topic that has been brought up a lot on StackOverflow, however, I could not find an answer to these questions. I apologize if there has already been a thread for this, but any help or guidance on this would be greatly appreciated! Thank You!
Login Activities' setup:
public class LoginActivity extends Activity implements View.OnClickListener {
private EditText username_et;
private EditText password_et;
private Button login_b;
private boolean login_success = true;
private Runnable run;
/**
* Instances created when app starts
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view_login);
// login_success = false;
login_success = savedInstanceState.getBoolean("login_success");
username_et = (EditText) findViewById(R.id.username_text);
username_et.setOnClickListener(LoginActivity.this);
password_et = (EditText) findViewById(R.id.password_text);
password_et.setOnClickListener(LoginActivity.this);
login_b = (Button) findViewById(R.id.login_button);
login_b.setOnClickListener(LoginActivity.this);
run = new Runnable() {
#Override
public void run() {
login_success = true;
}
};
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState){
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putBoolean("login_success", login_success);
}
Congratulations. You just discovered Android's dirty little secret.
AsyncTask has an inherent design flaw. It doesn't deal well with configuration changes that happen during background task execution because of exactly the problem you mentioned. It needs to hold a reference to the activity, but there's no guarantee that the reference will still be valid by the time the background task completes.
Here are two ways to overcome this problem:
I refer you to Alex Lockwood's excellent blog post on using hidden fragments with setRetainInstance(true) to span activity destruction and recreation. This is a more involved solution than the next one, but this solution has the advantage that you can still report progress with callbacks. If you were intending to call publishProgress() in your AsyncTask, then this is the method you should use.
Use a Loader. Loaders were designed around database data retrieval in the background, but the fact is that they can also be used to handle remote server access in the background as well. I use a Loader for the majority of my remote server tasks.
Here's an example:
public static class ResetPasswordLoader extends AsyncTaskLoader<Pair<CharSequence, Exception>> {
private static final String TAG = "ResetPasswordLoader ";
private String mEmail;
public ResetPasswordLoader(Context context, String email) {
super(context);
mEmail = email;
// set the content-changed flag
onContentChanged();
}
#Override
protected void onStartLoading() {
// only start the load if the content-changed flag is set
// takeContentChanged() returns the value of the flag before it is cleared
if (takeContentChanged()) {
forceLoad();
}
}
#Override
public Pair<CharSequence, Exception> loadInBackground() {
CharSequence result = null;
Exception exc = null;
try {
result = Service.getInstance().resetPassword(mEmail);
} catch (RemoteServiceException e) {
exc = e;
Log.e(TAG, "loadInBackground(), email = " + mEmail, e);
}
return new Pair<>(result, exc);
}
}
Also, in my onLoadFinished() override I make sure to call loaderManager.destroyLoader() on the loader's id.
Again, Alex Lockwood's blog has some great articles on loaders as well.
For the UI, something I do frequently is put up a indeterminate progress bar over the UI upon calling loaderManager.initLoader(). I also set a boolean like mProgressShown. This boolean gets saved in onSaveInstanceState, so when the activity/fragment is created again, I restore the boolean value which tells me to show the progress bar immediately. Some time later onLoadFinished will be called and I clear mProgressShown and hide the progress bar.

Generic asyncTask with callback (for web services)

I've already developed many Android apps that make web service requests, always with the following approach:
In every activity that need to make a web service request, I define an inner AsyncTask that shows a ProgressDialog in onPreExecute(), makes the web service call in doInBackground, and dismisses the progressDialog and updates the results in the UI from onPostExecute().
My concern is: Is there a better (shorter) way to do it? Does it make sense to repeat all that code in every activity? I've been googling a lot, but I've found nothing.
My question is: Couldn't I define a Callback interface? for example this one:
public interface RequestCallback {
public void onSuccess(Whatever whatever);
public void onError(ErrorCode errorCode, String message);
}
... and then define an external class, for example AsyncRequest, that wraps the AsyncTask definition and the ProgressDialog show() and dismiss() statements. So, all activities would just need to instantiate that class, and pass in the following parameters:
1) The method of the web service to run
2) A Bundle with all the parameters of that method of the web service
3) A RequestCallback instance (that could be an anonymous inline instance, where I could update the UI from onSuccess())
4) The context of the Activity (necessary to show the ProgressDialog(), so I would still need a way to prevent configuration change exceptions and so...),
Do you find this a good design? It could save hundreds of lines of code...
Your approach is what I did on my project. And it saved a lot of code as you said, I don't have any complaint about it. But here is some issues that I want to tell you:
You should create new instance of AsyncTask every time you do a background thread to avoid to pile callback.
For the progress dialog, I use it as Singleton, because you don't show many dialogs at the same time. The dialog will be showed when you call the background job, and will be dismiss in the callback. Here is what I did:
private void showProgressDialog(String strMess){
if(null == progressDialog){
progressDialog = new ProgressDialog(MainActivity.this);
}
if(!progressDialog.isShowing()){
progressDialog.setMessage(strMess);
progressDialog.show();
}
}
private void hideProgressDialog(){
if(null != progressDialog && progressDialog.isShowing()){
progressDialog.dismiss();
}
}
void someMethod(){
showProgressDialog("Loading...");
doBackgroundJob(param, new RequestCallBack() {
public void onRequestCompleted(String message, boolean isSuccess) {
hideProgressDialog();
if(isSuccess){
}else{
//do something on error
}
}
});
}
It is an optional, I defined an interface to notify instead of specific class, for each response I use one class, so in base class, I don't care what the response is. Here is it:
public interface OnRequestCompleted<TResponse> {
void requestCompleted(TResponse response);
}
public abstract class BaseRequest<TResponse> implements IRequest{
protected OnRequestCompleted<TResponse> delegate;
protected Class<TResponse> responseClass;
#Override
public void send() {
new HttpTask().execute();
}
private class HttpTask extends AsyncTask<Void, Void, String> {
//...
#Override
protected void onPostExecute(String result) {
if (null != response && null != delegate) {
delegate.requestCompleted(response);
}
}
}
// the response example
public class GroupResponse {
public static class Clip {
public int clipId;
public String detail;
}
public static class Movie {
public int movieId;
public String detail;
}
}
In the subclass of BaseRequest, I will tell it exactly what the response class is (Movie, Clip...)
Hope this help.
If you use it already and it works for you, then yes it makes sense to make it generic and save the time (and bugs) of reimplementing the same thing dozens of times. If you ever find yourself copy-pasting large sections of code with few to no differences you should turn it into a library function or class of some sort. Otherwise if you find a problem later you'll have to fix it in a dozen places. It doesn't even matter if you think of a better way to do things later- its still easier to change it in one place than a dozen.
The only real issue I'd have with your solution is I wouldn't add the progress bar to it- I'd handle it in the calling code and the onSuccess/onError implementations. That way you could also reuse it for a background call that doesn't need to put up a UI. I try to keep my UI decisions as far away from data grabbing code as possible, MVC patterns are good.

Managing activity from DialogFragment

How can I call finish() and other non static methods from a DialogFragment in the activity that created it? I have tried passing messages from the OnClickLisener in the DialogFragment, to no avail.
I have a really simple app, conssting of a MainActivity and DialogFragment:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity);
showDialog();
}
public void showDialog() {
DialogFragment newFragment = new ConfirmDialog();
newFragment.show(getFragmentManager(), "dialog");
}
}
And the Dialog is again very simple:
public class ConfirmDialog extends DialogFragment {
#Override
public AlertDialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Confirm you want to continue?")
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//finish() MainActvity
}
})
.setNegativeButton("No.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//Do nothing in MainActity
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
There are many options. One of them is define an interface with a single method inside.
Have the dialog caller implement that interface.
Keep a global variable pointing to the caller.
Set the variable in the onAttach(Activity activity) method.
Null that variable in the onDetach() method.
Call the variable (interface member) method in the onClick.
Example:
public class MainActivity extends Activity implements MyInterface {
// ...
#Override
public void onChoose() { finish(); }
}
And inside ConfirmDialog:
public static interface MyInterface {
public void onChoose();
}
private MyInterface mListener;
#Override
public void onAttach(Activity activity) {
mListener = (MyInterface) activity;
super.onAttach(activity);
}
#Override
public void onDetach() {
mListener = null;
super.onDetach();
}
And then call mListener.onChoose() anywhere inside your class.
I know this has been marked as accepted, but I figured I could provide more feedback to the discussion.
A note about using or not interfaces. Andy's answer works just as right as mine, hence why I said "There are many options. One of them is...".
However, the reason why I prefer interfaces for this particular problem is because most of the times you're going to extend and reuse simple/common confirmation dialogs like that. hey are too generic to be "wasted" (or worse: duplicated if different event actions arise).
Unless you are deadly sure that you are going to use that only once, for one purpose (finishing), you generally should avoid hardwiring (and simplifying) the implementation details of the Activity in your dialog class. Flexibility, abstraction and efficiency. Less code to maintain.
And yes, there is a telltale that you may need that: the public keyword that you're using, especially if it's in a self-contained class file, which begs for reuse (too). Otherwise, you should be hiding that class inside your main Activity, since the implementation details (would) relate only to that one. Also, you would be removing the public keyword.
Yes, you could use for more than one Activity, but you'd be limited to finish()ing. The interface will give you flexibility to do whatever you want in each Activity. In other words, it's up to the implementer to define how it should itself behave for that event. You self-contain implementation details.
As a sidenote, what I do is create a package with all dialogs I may need for my application. For confirmation dialogs like that, I reuse for different messages and buttons. I provide defaults, but also allow for change using setArguments. And I keep the interfaces related so I don't need to create one interface for each dialog. The implementer responds according to which dialog triggered the "dialogs callback". Flexibility, abstraction and efficiency, all while avoiding things humorously called Hydra and Royal Family. So. In the end, like I said, many options. Don't over-engineer, but don't simplify too much too early (leave room for graceful expansion).
It's more important to understand advantages and pitfalls than choosing this or the other answer.
Even though the amount of work involved to make the interface is small, I don't see why you need to call finish() from the Activity that created it. Calling finish() from within the DialogFragment itself will suffice. If you need to send info back with it as well for some reason, you could always call getActivity() and chain a method that exists in the Activity. Ultimately no matter where you call finish, it will detach the Fragment and destroy it.
Just to clarify how to call a method from your Activity in your Fragment
((YourActivity)getActivity()).someMethod(param);
You MUST caste it because Java doesn't know that Activity has whatever method you wanna call. Which ever way you decide to go with, good luck :)
cheers
EDIT
I appreciate your clarification David. In general you are correct. But to be honest in this instance, you are incorrect because of the nature of Fragments and their relationships with the Activity. Again, you will essentially be creating a listener in order to be called by a Fragment that already has an extremely close relationship with the Activity class it is being held by. Any benefits provided by not hardwiring anything through listeners is lost in this case. You will still be rewriting custom code for every Dialog. While in my method you can write a method in the Activity class in such a general way that you only ever have to write it once.
There are only two reasons I see a need to use a Listener:
1. If you are writing code that other people will be using. So you provide an easy way to give info while maintaining a certain structure (like Androids DatePickerDialog).
2. If there is no connection between two parts you are trying to maintain connected (like GUI's in Java).
So I am not trying to say that David is wrong in saying this, and I am grateful he is bringing it up because it is important for people to understand when to use them. But again, in this case the benefits he mentions are non-existent due to the connection between Fragments and the Activity class. Just wanted to clarify why I believe listeners are not necessary here.
Instead of:
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//finish() MainActvity
}
})
Use:
.setPositiveButton("Yes.", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// this gets the current activity.
Activity currentActivity = getActivity();
// this finish() method ends the current activity.
currentActivity.finish();
}
})

Android How to reconnect to AsyncTask after onDestroy() and relaunch onCreate()?

I have tested the statement that AsyncTasks are not destroyed along with their launching activity. And it is true.
I made the AsyncTask just publish a Log.i() message every 3 seconds for 1 minute. And I put Log.i() messsage in the onDestroy() method of the activity.
I see the activity is destroyed, but the AsyncTask keeps running until it finishes all 20 Log.i() messages.
And I am confused.
What if the AsyncTask had publishProgress() into the destroyed UI?
I guess some sort of exception would occurr, right?
What if the AsyncTask stores data in a global variable of class Application?
No idea here, NullPointer exception?
What if the app is restarted?
It will probably launch a new AsyncTask. Can it reconnect with the still running AsyncTask?
Is the AsyncTask immortal after the mother app is destroyed?
Maybe yes, how do all LogCat apps keep logging messages while the UI application is not visible anymore, maybe destroyed? And when you reopen them they show you the messsages that were generated while it was 'dead'.
All this seems like a discussion, but the question is in the title. I have this orphan AsyncTask, which I would like very much to reconnect to when the app is relaunched, but I don't know how to do it.
I forgot to tell why this is very important. The app gets destroyed when an orientation change occurs. And I don't want to loose the data produced by the AsyncTask, I don't want to stop it and restart it. I just want it to keep going and reconnect after the orientation changes are done.
I hope I've got this right as it's from some old code I no longer use (I now use an IntentService to do what this used to do).
This is what I originally had when I downloaded files in my main Activity...
public class MyMainActivity extends Activity {
FileDownloader fdl = null;
...
// This is an inner class of my main Activity
private class FileDownloader extends AsyncTask<String, String, Boolean> {
private MyMainActivity parentActivity = null;
protected void setParentActivity(MyMainActivity parentActivity) {
this.parentActivity = parentActivity;
}
public FileDownloader(MyMainActivity parentActivity) {
this.parentActivity = parentActivity;
}
// Rest of normal AsyncTask methods here
}
}
The key is to use onRetainNonConfigurationInstance() to 'save' the AsyncTask.
Override
public Object onRetainNonConfigurationInstance() {
// If it exists then we MUST set the parent Activity to null
// before returning it as once the orientation re-creates the
// Activity, the original Context will be invalid
if (fdl != null)
fdl.setParentActivity(null);
return(fdl);
}
I then have a method called doDownload() which is called from onResume() if a Boolean indicating downloadComplete is true. The Boolean is set in the onPostExecute(...) method of FileDownloader.
private void doDownload() {
// Retrieve the FileDownloader instance if previousy retained
fdl = (FileDownloader)getLastNonConfigurationInstance();
// If it's not null, set the Context to use for progress updates and
// to manipulate any UI elements in onPostExecute(...)
if (fdl != null)
fdl.setParentActivity(this);
else {
// If we got here fdl is null so an instance hasn't been retained
String[] downloadFileList = this.getResources().getStringArray(R.array.full_download_file_list);
fdl = new FileDownloader(this);
fdl.execute(downloadFileList);
}
}

Background task, progress dialog, orientation change - is there any 100% working solution?

I download some data from internet in background thread (I use AsyncTask) and display a progress dialog while downloading. Orientation changes, Activity is restarted and then my AsyncTask is completed - I want to dismiss the progess dialog and start a new Activity. But calling dismissDialog sometimes throws an exception (probably because the Activity was destroyed and new Activity hasn't been started yet).
What is the best way to handle this kind of problem (updating UI from background thread that works even if user changes orientation)? Did someone from Google provide some "official solution"?
Step #1: Make your AsyncTask a static nested class, or an entirely separate class, just not an inner (non-static nested) class.
Step #2: Have the AsyncTask hold onto the Activity via a data member, set via the constructor and a setter.
Step #3: When creating the AsyncTask, supply the current Activity to the constructor.
Step #4: In onRetainNonConfigurationInstance(), return the AsyncTask, after detaching it from the original, now-going-away activity.
Step #5: In onCreate(), if getLastNonConfigurationInstance() is not null, cast it to your AsyncTask class and call your setter to associate your new activity with the task.
Step #6: Do not refer to the activity data member from doInBackground().
If you follow the above recipe, it will all work. onProgressUpdate() and onPostExecute() are suspended between the start of onRetainNonConfigurationInstance() and the end of the subsequent onCreate().
Here is a sample project demonstrating the technique.
Another approach is to ditch the AsyncTask and move your work into an IntentService. This is particularly useful if the work to be done may be long and should go on regardless of what the user does in terms of activities (e.g., downloading a large file). You can use an ordered broadcast Intent to either have the activity respond to the work being done (if it is still in the foreground) or raise a Notification to let the user know if the work has been done. Here is a blog post with more on this pattern.
The accepted answer was very helpful, but it doesn't have a progress dialog.
Fortunately for you, reader, I have created an extremely comprehensive and working example of an AsyncTask with a progress dialog!
Rotation works, and the dialog survives.
You can cancel the task and dialog by pressing the back button (if you want this behaviour).
It uses fragments.
The layout of the fragment underneath the activity changes properly when the device rotates.
I've toiled for a week to find a solution to this dilemma without resorting to editing the manifest file. The assumptions for this solution are:
You always need to use a progress dialog
Only one task is performed at a time
You need the task to persist when the phone is rotated and the progress dialog to be automatically dismisses.
Implementation
You will need to copy the two files found at the bottom of this post into your workspace. Just make sure that:
All your Activitys should extend BaseActivity
In onCreate(), super.onCreate() should be called after you initialize any members that need to be accessed by your ASyncTasks. Also, override getContentViewId() to provide the form layout id.
Override onCreateDialog() like usual to create dialogs managed by the activity.
See code below for a sample static inner class to make your AsyncTasks. You can store your result in mResult to access later.
final static class MyTask extends SuperAsyncTask<Void, Void, Void> {
public OpenDatabaseTask(BaseActivity activity) {
super(activity, MY_DIALOG_ID); // change your dialog ID here...
// and your dialog will be managed automatically!
}
#Override
protected Void doInBackground(Void... params) {
// your task code
return null;
}
#Override
public boolean onAfterExecute() {
// your after execute code
}
}
And finally, to launch your new task:
mCurrentTask = new MyTask(this);
((MyTask) mCurrentTask).execute();
That's it! I hope this robust solution will help someone.
BaseActivity.java (organize imports yourself)
protected abstract int getContentViewId();
public abstract class BaseActivity extends Activity {
protected SuperAsyncTask<?, ?, ?> mCurrentTask;
public HashMap<Integer, Boolean> mDialogMap = new HashMap<Integer, Boolean>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getContentViewId());
mCurrentTask = (SuperAsyncTask<?, ?, ?>) getLastNonConfigurationInstance();
if (mCurrentTask != null) {
mCurrentTask.attach(this);
if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
&& mDialogMap.get((Integer) mCurrentTask.dialogId)) {
mCurrentTask.postExecution();
}
}
}
#Override
protected void onPrepareDialog(int id, Dialog dialog) {
super.onPrepareDialog(id, dialog);
mDialogMap.put(id, true);
}
#Override
public Object onRetainNonConfigurationInstance() {
if (mCurrentTask != null) {
mCurrentTask.detach();
if (mDialogMap.get((Integer) mCurrentTask.dialogId) != null
&& mDialogMap.get((Integer) mCurrentTask.dialogId)) {
return mCurrentTask;
}
}
return super.onRetainNonConfigurationInstance();
}
public void cleanupTask() {
if (mCurrentTask != null) {
mCurrentTask = null;
System.gc();
}
}
}
SuperAsyncTask.java
public abstract class SuperAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {
protected BaseActivity mActivity = null;
protected Result mResult;
public int dialogId = -1;
protected abstract void onAfterExecute();
public SuperAsyncTask(BaseActivity activity, int dialogId) {
super();
this.dialogId = dialogId;
attach(activity);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
mActivity.showDialog(dialogId); // go polymorphism!
}
protected void onPostExecute(Result result) {
super.onPostExecute(result);
mResult = result;
if (mActivity != null &&
mActivity.mDialogMap.get((Integer) dialogId) != null
&& mActivity.mDialogMap.get((Integer) dialogId)) {
postExecution();
}
};
public void attach(BaseActivity activity) {
this.mActivity = activity;
}
public void detach() {
this.mActivity = null;
}
public synchronized boolean postExecution() {
Boolean dialogExists = mActivity.mDialogMap.get((Integer) dialogId);
if (dialogExists != null || dialogExists) {
onAfterExecute();
cleanUp();
}
public boolean cleanUp() {
mActivity.removeDialog(dialogId);
mActivity.mDialogMap.remove((Integer) dialogId);
mActivity.cleanupTask();
detach();
return true;
}
}
Did someone from Google provide some "official solution"?
Yes.
The solution is more of an application architecture proposal rather that just some code.
They proposed 3 design patterns that allows an application to work in-sync with a server, regardless of the application state (it will work even if the user finishes the app, the user changes screen, the app gets terminated, every other possible state where a background data operation could be interrumpted, this covers it)
The proposal is explained in the Android REST client applications speech during Google I/O 2010 by Virgil Dobjanschi. It is 1 hour long, but it is extremely worth watching.
The basis of it is abstracting network operations to a Service that works independently to any Activity in the application. If you're working with databases, the use of ContentResolver and Cursor would give you an out-of-the-box Observer pattern that is convenient to update UI without any aditional logic, once you updated your local database with the fetched remote data. Any other after-operation code would be run via a callback passed to the Service (I use a ResultReceiver subclass for this).
Anyway, my explanation is actually pretty vague, you should definititely watch the speech.
While Mark's (CommonsWare) answer does indeed work for orientation changes, it fails if the Activity is destroyed directly (like in the case of a phone call).
You can handle the orientation changes AND the rare destroyed Activity events by using an Application object to reference your ASyncTask.
There's an excellent explanation of the problem and the solution here:
Credit goes completely to Ryan for figuring this one out.
After 4 years Google solved the problem just calling setRetainInstance(true) in Activity onCreate. It will preserve your activity instance during device rotation. I have also a simple solution for older Android.
you should call all activity actions using activity handler. So if you are in some thread you should create a Runnable and posted using Activitie's Handler. Otherwise your app will crash sometimes with fatal exception.
This is my solution: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
Basically the steps are:
I use onSaveInstanceState to save the task if it is still
processing.
In onCreate I get the task if it was saved.
In onPause I discard the ProgressDialog if it is shown.
In onResume I show the ProgressDialog if the task is still
processing.

Categories

Resources