The inner fragment class must be static

I have a FragmentActivity class with an inner class that Dialog should display. But I have to make it static . Eclipse offers me to suppress the error with @SuppressLint("ValidFragment") . Is it a bad style if I do it and what are the possible consequences?

 public class CarActivity extends FragmentActivity { //Code @SuppressLint("ValidFragment") public class NetworkConnectionError extends DialogFragment { private String message; private AsyncTask task; private String taskMessage; @Override public void setArguments(Bundle args) { super.setArguments(args); message = args.getString("message"); } public void setTask(CarActivity.CarInfo task, String msg) { this.task = task; this.taskMessage = msg; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { // Use the Builder class for convenient dialog construction AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setMessage(message).setPositiveButton("Go back", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { Intent i = new Intent(getActivity().getBaseContext(), MainScreen.class); startActivity(i); } }); builder.setNegativeButton("Retry", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int id) { startDownload(); } }); // Create the AlertDialog object and return it return builder.create(); } } 

startDownload() starts Asynctask.

+64
android android-dialogfragment fragment
Mar 22 '13 at 13:02
source share
5 answers

Non-stationary inner classes contain a reference to their parent classes. The problem with creating the inner Fragment non-static class is that you always keep a reference to the Activity. GarbageCollector cannot collect your activity. Thus, you can skip an action if, for example, orientation changes. Because the Fragment can still live and is inserted into a new action.

EDIT:

Since some people asked me about an example, I started writing one, doing this, I found a few more problems when using non-static fragments:

  • They cannot be used in an XML file because they do not have an empty constructor (they can have an empty constructor, but you usually create non-static nested classes by doing myActivityInstance.new Fragment() , and this is different from calling only an empty constructor)
  • They cannot be reused at all, since the FragmentManager sometimes calls this empty constructor. If you have added a fragment to any transaction.

So, to make my work example, I had to add

 wrongFragment.setRetainInstance(true); 

The line will not cause the application to crash when changing orientation.

If you execute this code, you will have activity with some text images and two buttons - buttons increase some counter. And the Fragments show what orientation they consider their activity. In the beginning, everything works correctly. But after changing the orientation of the screen, only the first fragment works correctly - the second still causes the material when it is old.

My Activity class:

 package com.example.fragmenttest; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.res.Configuration; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; public class WrongFragmentUsageActivity extends Activity { private String mActivityOrientation=""; private int mButtonClicks=0; private TextView mClickTextView; private static final String WRONG_FRAGMENT_TAG = "WrongFragment" ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int orientation = getResources().getConfiguration().orientation; if (orientation == Configuration.ORIENTATION_LANDSCAPE) { mActivityOrientation = "Landscape"; } else if (orientation == Configuration.ORIENTATION_PORTRAIT) { mActivityOrientation = "Portrait"; } setContentView(R.layout.activity_wrong_fragement_usage); mClickTextView = (TextView) findViewById(R.id.clicksText); updateClickTextView(); TextView orientationtextView = (TextView) findViewById(R.id.orientationText); orientationtextView.setText("Activity orientation is: " + mActivityOrientation); Fragment wrongFragment = (WrongFragment) getFragmentManager().findFragmentByTag(WRONG_FRAGMENT_TAG); if (wrongFragment == null) { wrongFragment = new WrongFragment(); FragmentTransaction ft = getFragmentManager().beginTransaction(); ft.add(R.id.mainView, wrongFragment, WRONG_FRAGMENT_TAG); ft.commit(); wrongFragment.setRetainInstance(true); // <-- this is important - otherwise the fragment manager will crash when readding the fragment } } private void updateClickTextView() { mClickTextView.setText("The buttons have been pressed " + mButtonClicks + " times"); } private String getActivityOrientationString() { return mActivityOrientation; } @SuppressLint("ValidFragment") public class WrongFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout result = new LinearLayout(WrongFragmentUsageActivity.this); result.setOrientation(LinearLayout.VERTICAL); Button b = new Button(WrongFragmentUsageActivity.this); b.setText("WrongFragmentButton"); result.addView(b); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { buttonPressed(); } }); TextView orientationText = new TextView(WrongFragmentUsageActivity.this); orientationText.setText("WrongFragment Activities Orientation: " + getActivityOrientationString()); result.addView(orientationText); return result; } } public static class CorrectFragment extends Fragment { private WrongFragmentUsageActivity mActivity; @Override public void onAttach(Activity activity) { if (activity instanceof WrongFragmentUsageActivity) { mActivity = (WrongFragmentUsageActivity) activity; } super.onAttach(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { LinearLayout result = new LinearLayout(mActivity); result.setOrientation(LinearLayout.VERTICAL); Button b = new Button(mActivity); b.setText("CorrectFragmentButton"); result.addView(b); b.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mActivity.buttonPressed(); } }); TextView orientationText = new TextView(mActivity); orientationText.setText("CorrectFragment Activities Orientation: " + mActivity.getActivityOrientationString()); result.addView(orientationText); return result; } } public void buttonPressed() { mButtonClicks++; updateClickTextView(); } } 

Note that you probably shouldn't onAttach activity on onAttach if you want to use your fragment in different actions, but here it works as an example.

Activity_wrong_fragement_usage.xml:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".WrongFragmentUsageActivity" android:id="@+id/mainView"> <TextView android:id="@+id/orientationText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" /> <TextView android:id="@+id/clicksText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="" /> <fragment class="com.example.fragmenttest.WrongFragmentUsageActivity$CorrectFragment" android:id="@+id/correctfragment" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 
+88
Mar 22 '13 at 17:19
source share
— -

I will not talk about the inner fragment, but more specifically about the DialogFragment defined in the framework of the action, because this is 99% case for this question.
From my point of view, I do not want my DialogFragment (your NetworkConnectionError) to be static, because I want to be able to call the variables or methods of my containing class (Activity). So it will not be static. But I do not want to generate memoryLeaks. So what is the solution?
Simple, when you go to onStop, forget that you killed your DialogFragment, it's that simple. So the code looks something like this:

 public class CarActivity extends AppCompatActivity{ /** * The DialogFragment networkConnectionErrorDialog */ private NetworkConnectionError networkConnectionErrorDialog ; //... your code ...// @Override protected void onStop() { super.onStop(); //invalidate the DialogFragment to avoid stupid memory leak if (networkConnectionErrorDialog != null) { if (networkConnectionErrorDialog .isVisible()) { networkConnectionErrorDialog .dismiss(); } networkConnectionErrorDialog = null; } } /** * The method called to display your dialogFragment */ private void onDeleteCurrentCity(){ FragmentManager fm = getSupportFragmentManager(); networkConnectionErrorDialog =(DeleteAlert)fm.findFragmentByTag("networkError"); if(networkConnectionErrorDialog ==null){ networkConnectionErrorDialog =new DeleteAlert(); } networkConnectionErrorDialog .show(getSupportFragmentManager(), "networkError"); } 

And this way you avoid memory leaks (because it's bad), and you guarantee that you don't have an [expletive] static fragment that cannot access your fields and activity methods. This is a good way to deal with this problem, from my point of view.

+15
Mar 10 '16 at 12:29
source share

If you develop it in android studio, then there is no problem if you do not give it as static.The project will work without any errors and during apk generation you will get Error: this internal fragment must be static [ValidFragment]

Thats lint error, you are probably building with gradle to disable error interrupt, add:

 lintOptions { abortOnError false } 

to build .gradle. `

+5
Jul 17 '15 at 7:28
source share

If you want to access the members of an external class (Activity) and still do not want to put static elements in the Activity (since the fragment must be public static), you can override onActivityCreated

 public static class MyFragment extends ListFragment { private OuterActivityName activity; // outer Activity @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); activity = (OuterActivityName) getActivity(); ... activity.member // accessing the members of activity ... } 
+3
Jan 06 '17 at 17:56 on
source share

add annotation before inner class

@SuppressLint ("validFragment")

-one
Mar 07 '17 at 7:42 on
source share



All Articles