I am working on an application in which I have multiple Fragments inside my Activity but the problem is that sometimes on "BackPress" my application got crashed and it shows me error i.e. "java.lang.IllegalStateException: Fragment not attached to Activity in Android" . And my logcat redirect me to Toast i.e.
Code
catch (Exception e) {
Toast.makeText(getActivity(), R.string.some_error_occured, Toast.LENGTH_LONG).show();
e.printStackTrace();
}
Have I done something wrong with Toast?
if you have a viewpager in your fragments then you need to add in your viewpager adapter.
#Override
public Parcelable saveState() {
return null;
}
Check back stack count and remove all active fragments then call parent class's onBackPressed() method.
override fun onBackPressed() {
supportFragmentManager.beginTransaction().remove(fragment)
super.onBackPressed()
}
hey check if you are attached to activity or not then make context related calls like getString which you are doing in Toast. so move your code inside
isAdded() : Return true if the fragment is currently added to its
activity.
if (isAdded()){
//your code goes here
} else {
//handle the case
}
docs
It's crashing because when you are pressing back button that time your activity is not attached to the view and if you want to show toast message then you need an instance of that activity.
Try this, to check fragment is attached to the activity
Activity activity = getActivity();
if(activity! = null && isAdded){
Toast.makeText(getActivity, "Show message", Toast.LENGTH_SHORT).show();
}
The answer is very simple.
Your fragment is not getting proper context refrence you should do like this it will never force stop.
Take reference of your activity in which fragments are integrated.
For example, your fragment is lying under MainActivity so you should code like this
MainActivity mainactivity;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// use this mainactivity object instead of getActivity() or getContext() or requireContext() or requireActivity()
mainactivity = (MainActivity) getActivity();
}
#D Developer
I guarantee, your app will work smoothly without any single error.
Related
So I have a curious problem I'm not able to solve right now.
RoomGamesFragment
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
roomActivity = (RoomActivity) activity;
gameTabContainerView = (LinearLayout) roomActivity.findViewById(R.id.game_tab_container); // findViewById returns null
// NullPointerException
gameTabContainerView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
}
});
}
This works totally fine when opening the activity which contains the fragment. But here is the problem: If I leave the activity open, put the app in the background (by clicking the home button), use other apps and then open my app again after some time, I get the NullPointerException, because findViewById returns null now.
How can I prevent this? Is the Activity removed from the stack, which leads to the Exception? I know I could just check for null, but I need the onClickListener, even when I return to the app after it has been in the background.
You should not perform this code in onAttach() but rather in onActivityCreated(). This is because the "View" is not yet created. onAttach() is above the onCreateView() in the Fragment lifecycle.
For more info : http://developer.android.com/guide/components/fragments.html#Creating
I am rarely getting this error while making an API call.
java.lang.IllegalStateException: Fragment not attached to Activity
I tried putting the code inside isAdded() method to check whether fragment is currently added to its activity but still i rarely gets this error. I fail to understand why I am still getting this error. How can i prevent it?
Its showing error on the line-
cameraInfo.setId(getResources().getString(R.string.camera_id));
Below is the sample api call that i am making.
SAPI.getInfo(getActivity(),
new APIResponseListener() {
#Override
public void onResponse(Object response) {
cameraInfo = new SInfo();
if(isAdded()) {
cameraInfo.setId(getResources().getString(R.string.camera_id));
cameraInfo.setName(getResources().getString(R.string.camera_name));
cameraInfo.setColor(getResources().getString(R.string.camera_color));
cameraInfo.setEnabled(true);
}
}
#Override
public void onError(VolleyError error) {
mProgressDialog.setVisibility(View.GONE);
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
}
}
});
This error happens due to the combined effect of two factors:
The HTTP request, when complete, invokes either onResponse() or onError() (which work on the main thread) without knowing whether the Activity is still in the foreground or not. If the Activity is gone (the user navigated elsewhere), getActivity() returns null.
The Volley Response is expressed as an anonymous inner class, which implicitly holds a strong reference to the outer Activity class. This results in a classic memory leak.
To solve this problem, you should always do:
Activity activity = getActivity();
if(activity != null){
// etc ...
}
and also, use isAdded() in the onError() method as well:
#Override
public void onError(VolleyError error) {
Activity activity = getActivity();
if(activity != null && isAdded())
mProgressDialog.setVisibility(View.GONE);
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(activity, errormsg, Toast.LENGTH_LONG).show();
}
}
}
Fragment lifecycle is very complex and full of bugs, try to add:
Activity activity = getActivity();
if (isAdded() && activity != null) {
...
}
I Found Very Simple Solution isAdded() method which is one of the fragment method to identify that this current fragment is attached to its Activity or not.
we can use this like everywhere in fragment class like:
if(isAdded())
{
// using this method, we can do whatever we want which will prevent **java.lang.IllegalStateException: Fragment not attached to Activity** exception.
}
Exception: java.lang.IllegalStateException: Fragment
DeadlineListFragment{ad2ef970} not attached to Activity
Category: Lifecycle
Description: When doing time-consuming operation in background thread(e.g, AsyncTask), a new Fragment has been created in the meantime, and was detached to the Activity before the background thread finished. The code in UI thread(e.g.,onPostExecute) calls upon a detached Fragment, throwing such exception.
Fix solution:
Cancel the background thread when pausing or stopping the
Fragment
Use isAdded() to check whether the fragment is attached
and then to getResources() from activity.
i may be late but may help someone .....
The best solution for this is to create a global application class instance and call it in the particular fragment where your activity is not being attached
as like below
icon = MyApplication.getInstance().getString(R.string.weather_thunder);
Here is application class
public class MyApplication extends Application {
private static MyApplication mInstance;
private RequestQueue mRequestQueue;
#Override
public void onCreate() {
super.onCreate();
mInstance = this;
}
public static synchronized MyApplication getInstance() {
return mInstance;
}
}
In Fragment use isAdded()
It will return true if the fragment is currently attached to Activity.
If you want to check inside the Activity
Fragment fragment = new MyFragment();
if(fragment.getActivity()!=null)
{ // your code here}
else{
//do something
}
Hope it will help someone
This error can happen if you are instantiating a fragment that somehow can't be instantiated:
Fragment myFragment = MyFragment.NewInstance();
public classs MyFragment extends Fragment {
public void onCreate() {
// Some error here, or anywhere inside the class is preventing it from being instantiated
}
}
In my case, i have met this when i tried to use:
private String loading = getString(R.string.loading);
So the base idea is that you are running a UI operation on a fragment that is getting in the onDetach lifecycle.
When this is happening the fragment is getting off the stack and losing the context of the Activity.
So when you call UI related functions for example calling the progress spinner and you want to leave the fragment check if the Fragment is added to the stack, like this:
if(isAdded){ progressBar.visibility=View.VISIBLE }
This will solve your problem.
Add This on your Fragemnt
Activity activity;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
activity = context instanceof Activity ? (Activity) context : null;
}
Then change getContext() , getActivity() , requireActivity() or requireContext() with activity
I adopted the following approach for handling this issue. Created a new class which act as a wrapper for activity methods like this
public class ContextWrapper {
public static String getString(Activity activity, int resourceId, String defaultValue) {
if (activity != null) {
return activity.getString(resourceId);
} else {
return defaultValue;
}
}
//similar methods like getDrawable(), getResources() etc
}
Now wherever I need to access resources from fragments or activities, instead of directly calling the method, I use this class. In case the activity context is not null it returns the value of the asset and in case the context is null, it passes a default value (which is also specified by the caller of the function).
Important This is not a solution, this is an effective way where you can handle this crash gracefully. You would want to add some logs in cases where you are getting activity instance as null and try to fix that, if possible.
this happen when the fragment does not have a context ,thus the getActivity()method return null.
check if you use the context before you get it,or if the Activity is not exist anymore . use context in fragment.onCreate and after api response usually case this problem
Sometimes this exception is caused by a bug in the support library implementation. Recently I had to downgrade from 26.1.0 to 25.4.0 to get rid of it.
This issue occurs whenever you call a context which is unavailable or null when you call it. This can be a situation when you are calling main activity thread's context on a background thread or background thread's context on main activity thread.
For instance , I updated my shared preference string like following.
editor.putString("penname",penNameEditeText.getText().toString());
editor.commit();
finish();
And called finish() right after it. Now what it does is that as commit runs on main thread and stops any other Async commits if coming until it finishes. So its context is alive until the write is completed. Hence previous context is live , causing the error to occur.
So make sure to have your code rechecked if there is some code having this context issue.
I am checking internet connection in my main activity.If connection is lost,I want to show reconnecting message in fragment.Example:If I run following code in main activity my app is crashing.
ConversationFragment conv1 = new ConversationFragment();
conv1.showReconnecting();
And this is the showReconnecting method in fragment:
public void showReconnecting() {
final RelativeLayout rel=(RelativeLayout)rootView.findViewById(R.id.reconnecting);
rel.setVisibility(View.VISIBLE);
}
I know why my app is crashing because rootView is setting in onCreateView and when I call this method from activity rootView is returning null.
What can I do for resolve this problem ?
Try this (Assuming reconnecting view is in fragment and your fragment is visible on screen),
public void showReconnecting() {
if (conv1 != null && conv1.getView()!=null) {
final RelativeLayout rel=(RelativeLayout)conv1.getView().findViewById(R.id.reconnecting);
rel.setVisibility(View.VISIBLE);
}
}
If conv1 is not available then please make it class variable.
According to what you want to do, a simple ProgressDialog will do the job. You can lauch it from your ChatFragment, like this:
First, declare it on your Fragment:
private ProgressDialog connectiongProgressDialog;
Then, when you want to show it, use:
connectiongProgressDialog = ProgressDialog.show(getActivity(), "My title", "Reconnecting");
When you want to dismiss it, use:
if (connectiongProgressDialog != null){
connectiongProgressDialog .dismiss();
}
It will display a simple dialog with the message you want.
Well, just looking at this and your explanation, I would think you can't call methods relating to a view (such as a fragment) without creating said fragment. An option, if the fragment is only used for showing the reconnecting, would be just to put some code in the activity and use a Toast.makeText(....).show();
which notifies the user that you are attempting to reconnect. So instead of conv1.showReconnecting(); maybe rather put, Toast.makeText(context,"Reconnecting", Toast.LONG).show(); and then do the necessary background work in an AsyncTask.
I hope this helps.
I have a fragment in an activity that I am using as a navigation drawer. It contains buttons that when clicked start new activities (startActivity from a fragment simply calls startActivity on the current activity).
For the life of me I can't seem to figure out how I would finish the current activity after starting a new one.
I am looking to achieve something like this in the fragment:
#Override
public void onClick(View view) {
// TODO Auto-generated method stub
if (view == mButtonShows) {
Intent intent = new Intent(view.getContext(), MyNewActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
}
But it seems Fragment.class does not implement finish() (like it implements startActivity(...)).
I would like the activity backstack cleared when they launch the 2nd activity. (so pressing back from the new activity would technically drop them back to the launcher)
When working with fragments, instead of using this or refering to the context, always use getActivity(). You should call
Java
getActivity().finish();
Kotlin
activity.finish()
to finish your activity from fragment.
Well actually...
I wouldn't have the Fragment try to finish the Activity. That places too much authority on the Fragment in my opinion. Instead, I would use the guide here: http://developer.android.com/training/basics/fragments/communicating.html
Have the Fragment define an interface which the Activity must implement. Make a call up to the Activity, then let the Activity decide what to do with the information. If the activity wishes to finish itself, then it can.
As mentioned by Jon F Hancock, this is how a fragment can 'close' the activity by suggesting the activity to close. This makes the fragment portable as is the reason for them. If you use it in a different activity, you might not want to close the activity.
Code below is a snippet from an activity and fragment which has a save and cancel button.
PlayerActivity
public class PlayerActivity extends Activity
implements PlayerInfo.PlayerAddListener {
public void onPlayerCancel() {
// Decide if its suitable to close the activity,
//e.g. is an edit being done in one of the other fragments?
finish();
}
}
PlayerInfoFragment, which contains an interface which the calling activity needs to implement.
public class PlayerInfoFragment extends Fragment {
private PlayerAddListener callback; // implemented in the Activity
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
callback= (PlayerAddListener) activity;
}
public interface PlayerAddListener {
public void onPlayerSave(Player p); // not shown in impl above
public void onPlayerCancel();
}
public void btnCancel(View v) {
callback.onPlayerCancel(); // the activity's implementation
}
}
You should use getActivity() method in order to finish the activity from the fragment.
getActivity().finish();
This does not need assertion, Latest update in fragment in android JetPack
requireActivity().finish();
In Fragment use getActivity.finishAffinity()
getActivity().finishAffinity();
It will remove all the fragment which pushed by the current activity from the Stack with the Activity too...
Every time I use finish to close the fragment, the entire activity closes. According to the docs, fragments should remain as long as the parent activity remains.
Instead, I found that I can change views back the the parent activity by using this statement:
setContentView(R.layout.activity_main);
This returns me back to the parent activity.
I hope that this helps someone else who may be looking for this.
Very simple...
1- just grab activity by getActivity() in the fragment
2- then call finish();
So just getActivity().finish(); will finish the parent activity.
Try this. There shouldn't be any warning...
Activity thisActivity = getActivity();
if (thisActivity != null) {
startActivity(new Intent(thisActivity, yourActivity.class)); // if needed
thisActivity.finish();
}
You have two options for Java and Kotlin. However, logic of both ways are same. You should call activity after call finish() method.
Answer for Kotlin,
If your activity cannot be null, use Answer_1. However, if your activity can be null, use Answer_2.
Answer_1: activity!!.finish()
Answer_2: activity?.finish()
Answer for Java,
getActivity().finish();
To finish activity in a Fragment use:
getActivity().finish();
Simple solution:
activity?.finish()
yes Fragment.class does not implement finish()
When working with fragments, instead of using this or refering to the context, always use getActivity(). You should call
I have a tabhost on my application and I'm using an Activity group which handles 3 activities inside.
Example:
ActivityGroup Handles
A -> B -> C
When i start this activities i'm using the flag Intent.FLAG_ACTIVITY_CLEAR_TOP.
My problem is when the user goes from A->B->C and press back button, my B activity shows up, but it does not resume or reload or refresh. It has the same state as before.
For example if the user goes again to C, C is refreshed, but when from C goes back.... B is not.
On B I have implementend methods such as onResume, onStart, onReestart and debugging it the main thread never goes in there...
And i need to refresh B because C can make changes that change the content displayed on B.
I have googleled this for 3 days and I couldn't found a solution..
I had this problem too.
I was using ActivityGroup code based on this blog post.
When I pressed the back button the pervious View would load fine, but the activity associated with it would not fire the onResume().
I was using an extended activity with on overridden and public onResume().
I found this blog post, so tried casting the view as my extended activity and called onResume().
Bingo.
Edit.... here's some more detail...
public class YFIMenuListActivity extends ListActivity {
....
#Override
public void onResume() {
super.onResume();
}
....
}
onResume() is normally protected, but I override it and make it public so that my ActivityGroup can call it.
I only have extended list activities in this activity group (I was just playing around). If you have different activities, each will have to override onResume() and I guess you'd have to look at the type of context you got back from v.getContext() before casting and calling it.
My ActivityGroup looks something like this:
public class BrowseGroup extends ActivityGroup {
.....
#Override
protected void onResume() {
super.onResume();
// call current activity's onResume()
View v = history.get(history.size()-1);
YFIMenuListActivity currentActivity = (YFIMenuListActivity)v.getContext();
currentActivity.onResume();
}
....
}
I've managed to implement an expanded version of cousin_itt's approach.
In both of my activities being used within the activity group I changed onResume from :
protected void onResume()
to
public void onResume()
I then wrote the following onResume function in my ActivityGroup to manually fire off onResumes:
#Override
protected void onResume() {
super.onResume();
View v = history.get(history.size()-1);
MainPeopleView currentActivity = null;
try {
currentActivity = (MainPeopleView)v.getContext();
currentActivity.onResume();
}
catch ( ClassCastException e ) {
Log.e(TAG, e.toString());
}
ProfileView otherActivity = null;
try {
otherActivity = (ProfileView)v.getContext();
otherActivity.onResume();
}
catch ( ClassCastException e ) {
Log.e(TAG, e.toString());
}
}
I have to say, this feels like the worst android hack I've ever written. I'm never using activitygroup again.
((ReportActivity)getLocalActivityManager().getActivity("ReportActivity")).onResume();
ReportActivity is that name you want to back Activity
ps: v.getContext();
only return the ActivityGroup ,it can't invoke child Activity onResume
I have found that onFocusChanged(boolean hasFocus) is great for situations like ActivityGroup. This will fire, even if onResume() does not. I use it for a few of my apps that have TabHosts and ActivityGroups. Here you can force the refresh and insure that it always gets fired when your Activity regains the focus.
I hope you have write your refresh data code in this method onResume().