@VidarWahlberg your answer is good but let's say you have FragmentActivity
where you run the task and you open new FragmentActivity
that opens before async is over or your app is running on background(example: you clicked home). I suggest you create BaseActivity
where you extend FragmentActivity
and all your activities should extend it.
What is important?
In BaseActivity
you need to have static FragmentManager fm;
, as @VidarWahlberg mentioned in his answer, and use it in the child activity to show the DialogFragment
.
What is the difference?
Instead of initializing fm = getSupportFragmentManager();
in onStart()
method you need to do it in onResume()
. It is needed because when you start the thread runing activity it's creating new instance of it and when starting the next activity it creates new instance of the BaseActivity
where FragmenManager
will be initialized and when you come back to the thread starting activity fm
object be with the second activity(which is paused) instance. The application will crash because you will try showing dialog in already paused activity's view. You cannot change view of paused activity so you need to initialize whenever onResume()
is called. onResume()
is called also when activity starts so it's safe to initialize the FragmentManager
there!
What elese we need to worry about?
You might think everything is ok but it's not. You may not realize it at first time but if your app is not at foreground(but at background) all of your activities are paused but the thread is already started and it's running. This is a problem because thread will continue and will try to show the DialogFragmernt
(or let's say to change view of activity that is not on focus). So the solution is to track if app is on foreground or no. This can be done with PackageManager
but it will require new permission in the manifest file(which users don't like and they may not want to install your app). The solution is to have static boolean isOnBackground = false;
field that you change on every activity onResume()
with isOnBackground = false;
and in onPause()
with isOnBackground = true;
. This is not big change because BaseActivity
is where we can do that. This is safe because every start of new activity creates new instance of the BaseActivity
class but since the field is static
it's created just once and is same for all instances. We need to check the state of isOnBackground
before we start the body code of thread post method.
You may say that there can be problem because of delay between onPause()
and onResume()
but your app need to be designed in the way to start activity fast and not do long taking work on ui thread(need to be done on background thread). So if your app is designed good you will not have problems :)
You can use recursive call of the thread running method whenever app is not on foreground. This is safe and will not cause loop because when app's state are reseted(in need of memory) or app is stopped by user or android itself loop will be stopped because all app's instances will be freed from memory!
NOTE: Use the android support library!
Here goes the code:
BaseActivity.java
.......................
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
.......................
public class BaseActivity extends FragmentActivity {
public static FragmentManager fm;
public static boolean isOnBackground;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected void onResume() {
super.onResume();
BaseActivity.isOnBackground = false;
BaseActivity.fm = getSupportFragmentManager();
}
@Override
protected void onPause() {
super.onPause();
BaseActivity.isOnBackground = true;
}
}
MainActivity.java
.....................
import android.support.v4.app.DialogFragment;
.....................
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//This is just to call some second activity
Button startNewActivity = (Button) findViewById(R.id.helloWorld);
startNewActivity.setOnClickListener( new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,
SecondActivity.class);
startActivity(intent);
}
});
showEditDialog();
}
private void showEditDialog() {
(new Handler()).postDelayed(new Runnable() {
@Override
public void run() {
if(!BaseActivity.isOnBackground) {
DialogFragment myFragmentDialog = new DialogFragment();
myFragmentDialog.show(BaseActivity.fm,
"fragment_my_dialog");
} else {
//this is optional
showEditDialog();
}
}
}, 15000);
}
}