可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This is a snippet of code from my project that I am using to learn Android:
As you can see I must add @SuppressLint
to make my app work but on the guide this annotation wasn't necessary.
What am I doing wrong?
Here are my imports:
import android.annotation.SuppressLint; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.Settings; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.DialogFragment; import android.view.Menu; import android.view.View; import android.widget.TextView; import android.widget.ToggleButton;
回答1:
The example doesn't have those annotations because the class is in its own file. This means it is independent of the Activity that uses the Fragment.
In your case, your Fragment is inside an Activity and doesn't use the static modifier. This means it is tied to the Activity instance.
Having the Fragment depend on the Activity instance is a bad idea, both these classes have complex lifecyles (especially since Activities get destroyed and recreated quite often) and should be independent of each other.
You will need to make EnableGpsDialogFragment
's modifier static
.
public static class EnableGpsDialogFragment extends DialogFragment {
A static
class does not depend on the enclosing class' instance, so the warning will go away.
For more information, read the Java tutorial on nested classes.
Edit in response to your edit: Now that the classes don't depend on each other's instance, you will have to get out an instance of YourActivity
so you can call enabledLocationSettings()
one way is by casting and will only work if EnableGpsDialogFragment
is only used by YourActivity
:
@Override public void onClick(DialogInterface dialog, int which) { enableLocationSettings(); }
to
@Override public void onClick(DialogInterface dialog, int which) { ((YourActivity)getActivity()).enableLocationSettings(); }
If this Fragment will be used by multiple Activities, you should create an interface
to be implemented by each Activity instead.
回答2:
All DialogFragments should be public and - if an inner class - static. They should also have a public no-arg constructor, and rely only on setArguments() for parameter passing.
Failing to comply to this has for some time produced a Lint warning, that you could suppress if you really wanted to, but starting from the Android support library v25 and on, you will actually get an exception if trying to show a DialogFragment that doesn't comply to these rules:
java.lang.IllegalStateException: Fragment TestActivity$TestDialogFrament must be a public static class to be properly recreated from instance state.
The reason is, as stated, that the OS must be able to recreate all fragments in case something like a low-memory situation forces it to destroy fragments when an app is put into the background. When the app is put in the foreground again, the fragments should be possible to re-create from the serialized application state, and that is not possible for non-static inner classes other than from an instance of the enclosing outer class, and the re-creation is not done from that context.
Unfortunately this makes things more complex for dialogs, since it's usually very convenient to just create an anonymous sub-class that overrides onCreateDialog. However, such a dialog would not be able to re-create at all.
回答3:
It should not be !
From my point of view, I don't want my DialogFragment (your NetworkConnectionError) to be static because I want to be able to call variables or methods of my containing class (Activity) from it.
So It won't be static. But I don't want to generate memoryLeaks neither.
So what is the solution ?
Simple, when you go in onStop, insure you kill your DialogFragment, it's as simple as that. So the code looks like something like that:
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 that way you avoid memory leaks (because it's bad) and you insure you don't have a fucking static fragment that cannot access your activity's fields and methods. This is the good way to handle that problem, from my point of view.