I have 3 Fragments in a Activity like splashscreen, login and register. My LoginFragment based on asynctask.
So how can I call registerfragment from onPostExecute() in the LoginFragment, after the login process has been done ?
Help me.
Code Snippet:
protected void onPostExecute(httpresponse reesponse) {
mProgressDialog.dismiss();
super.onPostExecute(response);
// here the fragment must be called but how???
}
Solved the problem that is...
mFragmentCallbacks.onFragmentFinished(fragmentname.this);
Thanks everyone
Related
I'm using navigation in MainActivity, then I start SecondActivity (for result). After finish of SecondActivity I would like to continue with navigation in MainActivity, but FragmentManager has saved his state already.
On Navigation.findNavController(view).navigate(R.id.action_next, bundle) I receive log message:
Ignoring navigate() call: FragmentManager has already saved its state
How I can continue in navigation?
You must always call super.onActivityResult() in your Activity's onActivityResult. That is what:
Unlocks Fragments so they can do fragment transactions (i.e., avoid the state is already saved errors)
Dispatches onActivityResult callbacks to Fragments that called startActivityForResult.
Finally, I fix the issue by simple calling super.onPostResume() right before navigating to restore state.
I've solved this problem this way:
#Override
public void onActivityResult() { //inside my fragment that started activity for result
model.navigateToResults = true; //set flag, that navigation should be performed
}
and then
#Override
public void onResume() { //inside fragment that started activity for result
super.onResume();
if(model.navigateToResults){
model.navigateToResults = false;
navController.navigate(R.id.action_startFragment_to_resultsFragment);
}
}
not sure, if this is not a terrible hack, but it worked for me. FramgentManager state is restored at this point (onResume) and no problems with navigation occur.
I believe above solutions should work. But my problem was different. There was a third party sdk which was launching its activity using context provided by me and it was delivering the result on a listener which I had to implement.
So there was no option for me to work with onActivityResult :(
I used below hack to solve the issue:
private var runnable: Runnable? = null // Runnable object to contain the navigation code
override fun onResume() {
super.onResume()
// run any task waiting for this fragment to be resumed
runnable?.run()
}
override fun responseListener(response: Response) { // Function in which you are getting response
if (!isResumed) {
// add navigation to runnable as fragment is not resumed
runnable = Runnable {
navController.navigate(R.id.destination_to_navigate)
}
} else {
// navigate normally as fragment is already resumed
navController.navigate(R.id.destination_to_navigate)
}
}
Let me know if there is any better solution for this. Currently I found this very simple and easy to implement :)
call super.onPostResume() before navigation....It's working
I know to pass back something from a fragment to its calling activity you can use onAttach which has the "activity" parameter. You can set the activity to variable and call an interface on it later. So passing data from the fragment back to the activity. All great.
I would like to do the same thing but this time i have a standard fragment and I want to call a DialogFragment and then have the DialogFragment call back to the original fragment but I can't use onAttach is wants a Activity.
Anyone know the best way of doing this ?
Thanks
Obviously you could just make things public in your activity and set them from your fragment. But then you have to keep references to your activity, and possibly have unwanted public variables and/or setters.
You could use EventBus and you would not need any of that.
In your activity you need to register an event
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
EventBus.getDefault().unregister(this);
super.onStop();
}
// This method will be called when a MessageEvent is posted
public void onEvent(MessageEvent event){
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
Then you can simply call your event from your fragment or anywhere you like,
EventBus.getDefault().post(new MessageEvent("Hello everyone!"));
Some more information on EventBus can be found here
And another possibly useful tutorial.
One way to contact another fragment from there is to access it in the implemented method in your Activity:
//In your Activity...
#Override
public void callbackFromFragmentA(){
FragmentB fragment = (FragmentB) getFragmentManager.findFragmentById(android.R.id.content);
if (fragment != null) {
fragment.callFragmentMethod();
}
}
I've an Activity A that contains a Login Fragment and an Activity B that contains a Home Fragment.
I've to start B from Login Fragment after a succesfully login request (async).
I've a callback listener inside the login fragment:
onSuccess(result) {
startActivity(B);
}
Today I met this nice bug: getting exception "IllegalStateException: Can not perform this action after onSaveInstanceState".
I think that's not properly a bug, anyway I don't know how to workaround that. This blog post suggests to avoid transaction inside async callback methods, yeah but how? commitAllowingStateLoss() should be used as a last resort: in case, should I use it inside Home Fragment transaction in Activity B creation method?
Basically, what should I do to start another activity after async callback?
You should use onPostExecute(result) in the AsyncTask:
private class LoginTask extends AsyncTask<parameters,...> {
...
protected void onPostExecute(Long result) {
//if result successful start ActivityB
}
}
Onpost fires after the asynctask is complete.
It runs on the UI thread so that should solve your problem.
Put this in your main activity:
public void run(){
//code you would normally have after task completes
}
Then put this in your onSuccess:
mainactivity.runUIonthread()
Scenario: I have a dialog fragment. Onclick of an image it launches an activity which does the process in an asynctask. When I get back the result the activity finishes and goes back to the dialog fragment.On getting back the image must be changed.
Problem:The image remains the same and only when you close the dialogfragment and reopen it does it change.
Sorry I havnt posted the code, Just wanted some suggestions on how to update the view from the activitys async task.
If I understood you correctly, try use invalidate() method for your ImageView in onPostExecute() of your AsyncTask.
If you start your AsyncTask in launched Activity, as I suppose, you can start custom Activity in Dialog Fragment and pass your ImageView pointer to constructor. Something like this.
public class AsyncTaskActivity extends Activity{
private ImageView yourImage;
public AsyncTaskActivity(ImageView yourImage){
this.yourImage = yourImage;
}
....
//your AsyncTask should be like this
new AsyncTask<Void, Void, Void>(){
//here your backround process
...
//here we invalidate ImageView
#Override
protected void onPostExecute(Void result) {
//update image Bitmap or something else
...
yourImage.invalidate();
}
}.execute();
}
With best regards.
I would suggest the following:
Start the activity (B) by using startActivityForResult from your dialog.
Override OnActivityResult in your original activity (A, the one that host the dialog).
call super.OnAcitivityResult in it, so that the dialog can receive the call back.
Your dialogfragment should override OnActivityResult and change the image based on the result.
Need your code to see what you are actually trying to do.
I'm trying to understand under what circumstances can getActivity() return null in a fragment AFTER onAttach. I typically start an async task in onCreate or onCreateView inside my fragments but I'm getting error reports indicating sometimes getActivity() is null when the async task finishes. Error reports are coming in via crashlytics but can't reproduce them.
The async tasks are "blocking" - I display a modal non-dismissable progress bar. Also rotation is prevented by calling setRequestedOrientation.
I'm using v4 support Fragment and FragmentActivity. Fragments are set to retain state.
What am I missing? Are there other config changes that may cause the fragment to be detached?
I tried temporarily enabling rotation and the dev option to destroy activity after leaving it but still can't reproduce this...
Here's some of the relevant code inside one of my fragments, in this case it would sometimes break with an NPE at activity.dismissSpinner:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
checkIfLoggedIn();
}
public void checkIfLoggedIn() {
LoginActivity activity = (LoginActivity)getActivity();
activity.showSpinner("Connecting, please wait...");
AsyncTask<String, Void, JsonResponse> asyncTask = new AsyncTask<String, Void, JsonResponse>() {
protected JsonResponse doInBackground(String... notused) {
return cmsServer().getCurrentUser(getActivity());
}
protected void onPostExecute(JsonResponse result) {
LoginActivity activity = (LoginActivity)getActivity();
activity.dismissSpinner();
//...more stuff here
}
};
asyncTask.execute();
}
Do you stop/cancel your AsyncTask if your app goes to background or is paused?
Consider the following scenario: your AsyncTask is executed, and when prompted with the progress bar, the user decides to do other stuff while she waits for the task to complete. She does so by pressing the home button. Alas, this might destroy the fragment and the activity. The running AsyncTask knows nothing about it, and when done, getActivity() method invocations (or local variables pointing to a non-existent Activity) may as well return null, causing your app to crash.
The Fragmentlife cycle is as follows
According to Fragment life-cycle onCreate() and onCreateView()are called before the Activity creation. so when we call getActivity() in these methods in returns null.
so instead of starting the async task in the onCreateView() start it in onStart() or onResume() so that getActivity() returns the exact Activity reference.
For more details click here