• Android重置APN时提示弹窗不消失问题


    问题:

    • 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

    1. @Override
    2. public boolean onOptionsItemSelected(MenuItem item) {
    3. switch (item.getItemId()) {
    4. case MENU_NEW:
    5. addNewApn();
    6. return true;
    7. case MENU_RESTORE:
    8. restoreDefaultApn();
    9. return true;
    10. }
    11. return super.onOptionsItemSelected(item);
    12. }

    2. 执行重置APN流程,后续工作交由Handler

    1. private boolean restoreDefaultApn() {
    2. //1.UI显示提示对话框
    3. showDialog(DIALOG_RESTORE_DEFAULTAPN);
    4. //2.设置标志位
    5. mRestoreDefaultApnMode = true;
    6. //3.创建UI和逻辑处理程序:RestoreApnUiHandler和RestoreApnProcessHandler
    7. if (mRestoreApnUiHandler == null) {
    8. mRestoreApnUiHandler = new RestoreApnUiHandler();
    9. }
    10. //(HandlerThread)mRestoreDefaultApnThread 定义时没有初始化,在这里进行。
    11. if (mRestoreApnProcessHandler == null || mRestoreDefaultApnThread == null) {
    12. mRestoreDefaultApnThread = new HandlerThread(
    13. "Restore default APN Handler: Process Thread");
    14. mRestoreDefaultApnThread.start();
    15. mRestoreApnProcessHandler = new RestoreApnProcessHandler(
    16. mRestoreDefaultApnThread.getLooper(), mRestoreApnUiHandler);
    17. }
    18. mRestoreApnProcessHandler
    19. .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_START);
    20. return true;
    21. }

    3.业务线程RestoreApnProcessHandler处理消息EVENT_RESTORE_DEFAULTAPN_START

    1. private class RestoreApnProcessHandler extends Handler {
    2. private Handler mRestoreApnUiHandler;
    3. RestoreApnProcessHandler(Looper looper, Handler restoreApnUiHandler) {
    4. super(looper);
    5. this.mRestoreApnUiHandler = restoreApnUiHandler;
    6. }
    7. @Override
    8. public void handleMessage(Message msg) {
    9. switch (msg.what) {
    10. //1.收到处理restoreDefaultApn方法中mRestoreApnProcessHandler发出的信息
    11. case EVENT_RESTORE_DEFAULTAPN_START:
    12. //2.重置业务的数据库内容处理
    13. final ContentResolver resolver = getContentResolver();
    14. resolver.delete(getUriForCurrSubId(DEFAULTAPN_URI), null, null);
    15. //3.UI线程发出重置完成的消息
    16. mRestoreApnUiHandler
    17. .sendEmptyMessage(EVENT_RESTORE_DEFAULTAPN_COMPLETE);
    18. break;
    19. }
    20. }
    21. }

     4. UI线程RestoreApnUiHandler处理消息EVENT_RESTORE_DEFAULTAPN_COMPLETE

    1. private class RestoreApnUiHandler extends Handler {
    2. @Override
    3. public void handleMessage(Message msg) {
    4. switch (msg.what) {
    5. case EVENT_RESTORE_DEFAULTAPN_COMPLETE:
    6. final Activity activity = getActivity();
    7. if (activity == null) {
    8. mRestoreDefaultApnMode = false;
    9. return;
    10. }
    11. fillList();
    12. getPreferenceScreen().setEnabled(true);
    13. mRestoreDefaultApnMode = false;
    14. //移除对话框并显示Toast提示
    15. removeDialog(DIALOG_RESTORE_DEFAULTAPN);
    16. Toast.makeText(
    17. activity,
    18. getResources().getString(
    19. R.string.restore_default_apn_completed),
    20. Toast.LENGTH_LONG).show();
    21. break;
    22. }
    23. }
    24. }

    可能原因

    1. 由于对Phone状态监听中有显示Dialog的调用,但是没有remove该对话框的回调条件。

    ApnSettings.java (revision 2a149d99) - OpenGrok cross reference for /packages/apps/Settings/src/com/android/settings/network/apn/ApnSettings.java

    1. private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
    2. @Override
    3. public void onPreciseDataConnectionStateChanged(
    4. PreciseDataConnectionState dataConnectionState) {
    5. if (dataConnectionState.getState() == TelephonyManager.DATA_CONNECTED) {
    6. if (!mRestoreDefaultApnMode) {
    7. fillList();
    8. } else {
    9. showDialog(DIALOG_RESTORE_DEFAULTAPN);
    10. }
    11. }
    12. }
    13. };

    2.Settings Dialog的机制

    SettingsPreferenceFragment.java (revision 2a149d99) - OpenGrok cross reference for /packages/apps/Settings/src/com/android/settings/SettingsPreferenceFragment.java

    1. // Dialog management
    2. protected void showDialog(int dialogId) {
    3. if (mDialogFragment != null) {
    4. Log.e(TAG, "Old dialog fragment not null!");
    5. }
    6. mDialogFragment = SettingsDialogFragment.newInstance(this, dialogId);
    7. mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId));
    8. }
    9. @Override
    10. public Dialog onCreateDialog(int dialogId) {
    11. return null;
    12. }
    13. @Override
    14. public int getDialogMetricsCategory(int dialogId) {
    15. return 0;
    16. }
    17. protected void removeDialog(int dialogId) {
    18. // mDialogFragment may not be visible yet in parent fragment's onResume().
    19. // To be able to dismiss dialog at that time, don't check
    20. // mDialogFragment.isVisible().
    21. if (mDialogFragment != null && mDialogFragment.getDialogId() == dialogId) {
    22. mDialogFragment.dismissAllowingStateLoss();
    23. }
    24. mDialogFragment = null;
    25. }
    26. /**
    27. * Sets the OnCancelListener of the dialog shown. This method can only be
    28. * called after showDialog(int) and before removeDialog(int). The method
    29. * does nothing otherwise.
    30. */
    31. protected void setOnCancelListener(DialogInterface.OnCancelListener listener) {
    32. if (mDialogFragment != null) {
    33. mDialogFragment.mOnCancelListener = listener;
    34. }
    35. }
    36. /**
    37. * Sets the OnDismissListener of the dialog shown. This method can only be
    38. * called after showDialog(int) and before removeDialog(int). The method
    39. * does nothing otherwise.
    40. */
    41. protected void setOnDismissListener(DialogInterface.OnDismissListener listener) {
    42. if (mDialogFragment != null) {
    43. mDialogFragment.mOnDismissListener = listener;
    44. }
    45. }
    46. public void onDialogShowing() {
    47. // override in subclass to attach a dismiss listener, for instance
    48. }

    总结

    • 关注showDialog(DIALOG_RESTORE_DEFAULTAPN)和removeDialog(DIALOG_RESTORE_DEFAULTAPN)的回调。
    • 由于时序问题可能导致对话框多次被创建但有些情况没有对应的移除操作。
      • 通过单例模式解决?
  • 相关阅读:
    pandas 学习 第15篇:分组 groupby
    考察进制转化 十进制转为二进制
    《web课程设计》 基于HTML+CSS+JavaScript实现中国水墨风的小学学校网站模板(6个网页)
    MySQL怎么为表添加描述
    区块链(1):区块链简介
    10进制转任意进制,任意进制转10进制
    k8s系列-kubectl 命令快速参考
    Chrome:如何在页面树状显示后端返回的JSON数据
    重构技战术(一)——通用型重构技巧
    HTTP 优缺点
  • 原文地址:https://blog.csdn.net/qq_38666896/article/details/125603844