- APN列表界面执行重置(“Reset to default” 菜单)时,偶现restore消息提示弹窗不消失。
- 切换APN或编辑当前选中APN内容保存后,迅速重置APN会高概率复现问题。
入口:ApnSettings.java (revision 2a149d99) - OpenGrok cross reference for /packages/apps/Settings/src/com/android/settings/network/apn/ApnSettings.java
1. 菜单选项重置APN
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_NEW:
addNewApn();
return true;
case MENU_RESTORE:
restoreDefaultApn();
return true;
}
return super.onOptionsItemSelected(item);
}
2. 执行重置APN流程,后续工作交由Handler
private boolean restoreDefaultApn() {
//1.UI显示提示对话框
showDialog(DIALOG_RESTORE_DEFAULTAPN);
//2.设置标志位
mRestoreDefaultApnMode = true;
//3.创建UI和逻辑处理程序:RestoreApnUiHandler和RestoreApnProcessHandler
if (mRestoreApnUiHandler == null) {
mRestoreApnUiHandler = new RestoreApnUiHandler();
}
//(HandlerThread)mRestoreDefaultApnThread 定义时没有初始化,在这里进行。
if (mRestoreApnProcessHandler == null || mRestoreDefaultApnThread == null) {
mRestoreDefaultApnThread = new HandlerThread(
"Restore default APN Handler: Process Thread");
mRestoreDefaultApnThread.start();
mRestoreApnProcessHandler = new RestoreApnProcessHandler(
mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
}
mRestoreApnProcessHandler
.sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
return true;
}
3.业务线程RestoreApnProcessHandler处理消息EVENT_RESTORE_DEFAULTAPN_START
private class RestoreApnProcessHandler extends Handler {
private Handler mRestoreApnUiHandler;
RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
super(looper);
this.mRestoreApnUiHandler = restoreApnUiHandler;
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
//1.收到处理restoreDefaultApn方法中mRestoreApnProcessHandler发出的信息
case EVENT_RESTORE_DEFAULTAPN_START:
//2.重置业务的数据库内容处理
final ContentResolver resolver = getContentResolver();
resolver.delete(getUriForCurrSubId(DEFAULTAPN_URI), null, null);
//3.UI线程发出重置完成的消息
mRestoreApnUiHandler
.sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE);
break;
}
}
}
4. UI线程RestoreApnUiHandler处理消息EVENT_RESTORE_DEFAULTAPN_COMPLETE
private class RestoreApnUiHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
final Activity activity = getActivity();
if (activity == null) {
mRestoreDefaultApnMode = false;
return;
}
fillList();
getPreferenceScreen().setEnabled(true);
mRestoreDefaultApnMode = false;
//移除对话框并显示Toast提示
removeDialog(DIALOG_RESTORE_DEFAULTAPN);
Toast.makeText(
activity,
getResources().getString(
R.string.restore_default_apn_completed),
Toast.LENGTH_LONG).show();
break;
}
}
}
可能原因
1. 由于对Phone状态监听中有显示Dialog的调用,但是没有remove该对话框的回调条件。
ApnSettings.java (revision 2a149d99) - OpenGrok cross reference for /packages/apps/Settings/src/com/android/settings/network/apn/ApnSettings.java
private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onPreciseDataConnectionStateChanged(
PreciseDataConnectionState dataConnectionState) {
if (dataConnectionState.getState() == TelephonyManager.DATA_CONNECTED) {
if (!mRestoreDefaultApnMode) {
fillList();
} else {
showDialog(DIALOG_RESTORE_DEFAULTAPN);
}
}
}
};
2.Settings Dialog的机制
SettingsPreferenceFragment.java (revision 2a149d99) - OpenGrok cross reference for /packages/apps/Settings/src/com/android/settings/SettingsPreferenceFragment.java
// Dialog management
protected void showDialog(int dialogId) {
if (mDialogFragment != null) {
Log.e(TAG, "Old dialog fragment not null!");
}
mDialogFragment = SettingsDialogFragment.newInstance(this, dialogId);
mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId));
}
@Override
public Dialog onCreateDialog(int dialogId) {
return null;
}
@Override
public int getDialogMetricsCategory(int dialogId) {
return 0;
}
protected void removeDialog(int dialogId) {
// mDialogFragment may not be visible yet in parent fragment's onResume().
// To be able to dismiss dialog at that time, don't check
// mDialogFragment.isVisible().
if (mDialogFragment != null && mDialogFragment.getDialogId() == dialogId) {
mDialogFragment.dismissAllowingStateLoss();
}
mDialogFragment = null;
}
protected void setOnCancelListener(DialogInterface.OnCancelListener listener) {
if (mDialogFragment != null) {
mDialogFragment.mOnCancelListener = listener;
}
}
protected void setOnDismissListener(DialogInterface.OnDismissListener listener) {
if (mDialogFragment != null) {
mDialogFragment.mOnDismissListener = listener;
}
}
public void onDialogShowing() {
// override in subclass to attach a dismiss listener, for instance
}
总结
- 关注showDialog(DIALOG_RESTORE_DEFAULTAPN)和removeDialog(DIALOG_RESTORE_DEFAULTAPN)的回调。
- 由于时序问题可能导致对话框多次被创建但有些情况没有对应的移除操作。
- 通过单例模式解决?



