その向きが変更された後、正しいダイアログフラグメントを閉じることに問題があります。そのアクティビティが再作成された後、新しいアクティビティと対応するコンテキストが作成されたため、それは古いコンテキストが原因だと思います。onSaveInstance にいくつかの変数を設定して、ダイアログのステータスを保存し、必要に応じてダイアログを再作成するか、マニフェストの「方向」に 1 つの属性を配置できることを知っています。しかし、おそらく、マニフェストにハードコードせず、手動で onSaveIntance に保存しないようにするためのより良い方法がありますか? また、メイン フラグメントとダイアログ フラグメントの両方で setRetainInstance を使用しようとしましたが、役に立ちません。
断片:
public class MainFragment extends Fragment implements ServiceExecutorListener, OnClickListener, DialogClickListener {
private static final String TAG = MainFragment.class.getName();
private TextView serviceStatus;
Intent intent;
Boolean bound = false;
ServiceConnection sConn;
RESTService service;
ProgressDialogFragment pd;
private Button btnSend, btnCheck;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setRetainInstance(true);
intent = new Intent(getActivity(), RESTService.class);
getActivity().startService(intent);
sConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.d(TAG, "MainFragment onServiceConnected");
service = ((RESTService.MyBinder) binder).getService();
service.registerListener(MainFragment.this);
if (service.tasksAreDone())
serviceStatus.setText(service.getResult());
bound = true;
}
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG, "MainFragment onServiceDisconnected");
bound = false;
}
};
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.main_fragment, container, false);
serviceStatus = (TextView) rootView.findViewById(R.id.tvServiceStatusValue);
btnSend = (Button) rootView.findViewById(R.id.btnSend);
btnCheck = (Button) rootView.findViewById(R.id.btnCheck);
btnSend.setOnClickListener(this);
btnCheck.setOnClickListener(this);
return rootView;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnSend:
pd = new ProgressDialogFragment();
pd.newInstance(null);
pd.setDialogClickListener(this);
pd.show(getActivity().getSupportFragmentManager(), "ProgressDialog");
service.run(RESTService.REQUEST, 7);
service.run(RESTService.REQUEST, 2);
service.run(RESTService.REQUEST, 4);
break;
case R.id.btnCheck:
if (service != null)
serviceStatus.setText(String.valueOf(service.tasksAreDone()) + service.getTasksCount());
break;
}
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart: Bind service");
getActivity().bindService(intent, sConn, 0);
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: Unbind service");
if (!bound)
return;
getActivity().unbindService(sConn);
service.unregisterListener();
bound = false;
}
@Override
public void onComplete(int taskID, int action, String result) {
Log.d(TAG, "Task #" + taskID + ", action = " + action + " Completed");
pd.dismiss();
serviceStatus.setText(result);
}
@Override
public void onDialogClick(int action) {
switch (action) {
case Dialog.BUTTON_POSITIVE:
Log.d(TAG, "POSITIVE BUTTON");
break;
case Dialog.BUTTON_NEGATIVE:
Log.d(TAG, "NEGATIVE BUTTON");
service.removeTasks();
break;
case Dialog.BUTTON_NEUTRAL:
Log.d(TAG, "NEUTRAL BUTTON");
break;
}
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
ダイアログ:
public class ProgressDialogFragment extends DialogFragment implements OnClickListener {
final String TAG = ProgressDialogFragment.class.getName();
private DialogClickListener listener;
public ProgressDialogFragment newInstance(Bundle args) {
ProgressDialogFragment pdf = new ProgressDialogFragment();
pdf.setArguments(args);
return pdf;
}
public void setDialogClickListener(DialogClickListener listener) {
this.listener = listener;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
Log.d(TAG, "onCreate");
}
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder adb = new AlertDialog.Builder(getActivity())
.setTitle("Title!")
.setPositiveButton(R.string.yes, this)
.setNegativeButton(R.string.no, this)
.setNeutralButton(R.string.maybe, this)
.setCancelable(false)
.setMessage(R.string.message_text)
.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
return true;
}
});
return adb.create();
}
public void onClick(DialogInterface dialog, int which) {
if (listener != null)
listener.onDialogClick(which);
}
public void onDismiss(DialogInterface dialog) {
Log.d(TAG, "Dialog: onDismiss, dialog = " + getDialog() + ", retainInstance = " + getRetainInstance());
// Fix to avoid simple dialog dismiss in orientation change
if ((getDialog() != null) && getRetainInstance())
getDialog().setDismissMessage(null);
}
public void onCancel(DialogInterface dialog) {
super.onCancel(dialog);
Log.d(TAG, "Dialog: onCancel");
}
ログキャット:
04-29 06:17:17.860: E/AndroidRuntime(4202): FATAL EXCEPTION: main
04-29 06:17:17.860: E/AndroidRuntime(4202): java.lang.NullPointerException
04-29 06:17:17.860: E/AndroidRuntime(4202): at android.support.v4.app.DialogFragment.dismissInternal(DialogFragment.java:184)
04-29 06:17:17.860: E/AndroidRuntime(4202): at android.support.v4.app.DialogFragment.dismiss(DialogFragment.java:155)
04-29 06:17:17.860: E/AndroidRuntime(4202): at com.example.restservice.fragments.MainFragment.onComplete(MainFragment.java:108)
04-29 06:17:17.860: E/AndroidRuntime(4202): at com.example.restservice.service.RESTService$1.run(RESTService.java:79)
04-29 06:17:17.860: E/AndroidRuntime(4202): at android.os.Handler.handleCallback(Handler.java:605)
04-29 06:17:17.860: E/AndroidRuntime(4202): at android.os.Handler.dispatchMessage(Handler.java:92)
04-29 06:17:17.860: E/AndroidRuntime(4202): at android.os.Looper.loop(Looper.java:137)
04-29 06:17:17.860: E/AndroidRuntime(4202): at android.app.ActivityThread.main(ActivityThread.java:4514)
04-29 06:17:17.860: E/AndroidRuntime(4202): at java.lang.reflect.Method.invokeNative(Native Method)
04-29 06:17:17.860: E/AndroidRuntime(4202): at java.lang.reflect.Method.invoke(Method.java:511)
04-29 06:17:17.860: E/AndroidRuntime(4202): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
04-29 06:17:17.860: E/AndroidRuntime(4202): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
04-29 06:17:17.860: E/AndroidRuntime(4202): at dalvik.system.NativeStart.main(Native Method)
編集:
dialogFragment を呼び出すメイン フラグメントと onCreate メソッドの DialogFragment に setRetainInstance(true) を配置すると、getRetainInstance が true を返し、getDialog が方向変更の過程でオブジェクトを持っていることがわかります (そうでない場合は NPE)。この場合、私も NPE を持っていませんが、次の奇妙な動作があります: ダイアログが作成されて表示され、ダイアログが再作成され (向きの変更)、閉じられ (なぜ?)、ダイアログが再作成され (再び向きが変更され)、表示されます (wtf? 前回つまり、一方の側ではダイアログが閉じられましたが、もう一方の側では表示されるべきであることに注意してください。それは何ですか?