这是我用来学习Android的项目代码片段:
private void enableLocationSettings() {
Intent settingsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(settingsIntent);
}
@SuppressLint("ValidFragment")
public class EnableGpsDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setTitle("Tytuł")
.setMessage("wiadomosc")
.setPositiveButton("odpal", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
enableLocationSettings();
}
})
.create();
}
}
正如您所看到的,我必须添加@SuppressLint
以使我的应用有效,但在guide上无需注释。
我做错了什么?
以下是我的导入:
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;
答案 0 :(得分:20)
该示例没有这些注释,因为该类位于其自己的文件中。这意味着它是使用Fragment的Activity的独立。
在您的情况下,您的Fragment位于Activity内部,不使用static修饰符。这意味着它与Activity实例绑定。
让Fragment依赖于Activity实例是一个坏主意,这两个类都有复杂的生命周期(特别是因为活动被破坏并经常重新创建)并且应该彼此独立。
您需要制作EnableGpsDialogFragment
的修饰符static
。
public static class EnableGpsDialogFragment extends DialogFragment {
static
类不依赖于封闭类的实例,因此警告将消失。
有关详细信息,请阅读nested classes上的Java教程。
编辑以响应您的修改:
既然这些类不依赖于彼此的实例,那么你必须得到一个YourActivity
的实例,这样你就可以通过强制转换来调用enabledLocationSettings()
,只有{{1}才能使用EnableGpsDialogFragment
}仅由YourActivity
使用:
@Override
public void onClick(DialogInterface dialog, int which) {
enableLocationSettings();
}
到
@Override
public void onClick(DialogInterface dialog, int which) {
((YourActivity)getActivity()).enableLocationSettings();
}
如果多个活动将使用此片段,您应该create an interface
to be implemented by each Activity instead。
答案 1 :(得分:3)
所有DialogFragments都应该是公共的,如果是内部类,则应该是静态的。它们还应该有一个公共的无参数构造函数,并且仅依赖于setArguments()来传递参数。
一段时间没有遵守这一点会产生一个Lint警告,如果你真的想要,你可以抑制,但是从Android支持库v25开始,如果你试图显示一个DialogFragment,你实际上会得到一个例外这不符合这些规则:
java.lang.IllegalStateException: Fragment TestActivity$TestDialogFrament must be a public static class to be properly recreated from instance state.
原因是,如上所述,操作系统必须能够重新创建所有碎片,以防低内存情况迫使它在应用程序放入后台时破坏碎片。当应用程序再次置于前台时,应该可以从序列化应用程序状态重新创建片段,这对于非静态内部类是不可能的,而不是来自封闭外部类的实例,并且 - 创造不是从那种背景下完成的。
不幸的是,这会使对话框变得更复杂,因为创建一个覆盖onCreateDialog的匿名子类通常非常方便。但是,这样的对话框根本无法重新创建。
答案 2 :(得分:1)
不应该!
从我的角度来看,我不希望我的DialogFragment(你的NetworkConnectionError)是静态的,因为我希望能够从中调用我的包含类(Activity)的变量或方法。
所以它不会是静止的。
但我也不想产生记忆泄漏
那么解决方案是什么?
很简单,当你进入onStop时,确保你杀了你的DialogFragment,就这么简单。
所以代码看起来像这样:
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");
}
这样你可以避免内存泄漏(因为它很糟糕)并且你确保你没有他妈的静态片段无法访问你的活动的领域和方法。 从我的角度来看,这是处理这个问题的好方法。