在Setting中切换中英文后,打开最近应用,里面的提示字符不会切换中英文
来源:互联网 发布:页面置换算法例题详解 编辑:程序博客网 时间:2024/05/21 13:56
最近在项目中遇到一个初看比较奇怪的问题:在Setting中进行中英文切换,比如由中文切换到英文,这时别的界面字符都已经由中文变成了英文,但是,在打开最近应用界面的时候,却发现里面的提示字符还是中文,但是其中的最近应用的apk的名字已经变成了中文,而且,关机后开机,显示的字符串就正常了。第一眼看到的感觉是:哇塞(yu men),这怎么可能,一个界面中怎么有的字符会不切换!!!
Protected Methods void onCreate(Bundle savedInstanceState) void onStart() void onStop()
没办法,出现问题了,肯定是存在问题。只能静下心来仔细查看代码。
下面就记录下心路历程。
首先,查看这部分的源码在哪里。
源码路径:frameworks\base\policy\src\com\android\internal\policy\impl\ RecentApplicationsDialog.java
然后,查看与这个有相似功能的代码是否有问题。
我查看了之前在Framework层弹出Toast的是否有问题。经查看,弹出的Toast中的字符是会跟随Setting的中英文切换而变的。然后去查看了弹出Toast的代码:
Handler handler = new Handler(Looper.getMainLooper());handler.post(new Runnable() { public void run(){ Resources res = Resources.getSystem(); Toast.makeText(getContext(), res.getText(com.android.internal.R.string.input_again), Toast.LENGTH_SHORT).show(); } });然后查看了RecentApplicationsDialog中获取字符的部分:
getContext ().getResources ().getString (com.android.internal.R.string.tipinfo);
想着会不会是由于字符的获取问题导致的,于是改了RecentApplicationsDialog中获取字符串的方式,发现毫无影响。也是自己太相信自己(傻逼)了一回,竟然没有第一时间打印。以为问题应该出在这里。最后看到真相的我眼泪掉下来。
接着,立刻开始了打印字符、打印周期函数是否执行等。
结果发现,RecentApplicationsDialog的onCreate只会在第一次显示最近应用的时候执行一次,后面再弹出Dialog,都不会执行onCreate,直接从onStart开始执行。
这样就知道为什么提示字符不会跟随切换了,因为我们是在onCreate中设置布局,然后显示相应的字符。而onCreate不是每次都执行,所以里面的提示字符就没有切换。
/** * We create the recent applications dialog just once, and it stays around * (hidden) until activated by the user. * 从这里其实就可以看出来端倪了 * @see PhoneWindowManager#showRecentAppsDialog */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);Log.d("zmq","RecentApplicationDialog onCreate"); Context context = getContext(); if (sStatusBar == null) {sStatusBar = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); } Window window = getWindow(); window.requestFeature(Window.FEATURE_NO_TITLE); window.setType(WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY); window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); window.setTitle("Recents"); setContentView(com.android.internal.R.layout.recent_apps_dialog); //设置布局mpPackageManager = getContext().getPackageManager();maActivityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);mActivityInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(mpPackageManager, 0);mIconUtilities = new IconUtilities(getContext()); final WindowManager.LayoutParams params = window.getAttributes(); params.width = WindowManager.LayoutParams.MATCH_PARENT; params.height = WindowManager.LayoutParams.MATCH_PARENT; window.setAttributes(params); window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND); mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0); mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1); mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2); mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3); mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4); mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5); mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6); mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7); mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); tipinfo = (TextView)findViewById(com.android.internal.R.id.tipinfo); //要显示提示的控件TextView ActivityManager activityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);final List<ActivityManager.RunningTaskInfo> list = activityManager.getRunningTasks(1);mGridView = (GridView) findViewById(com.android.internal.R.id.recent_gridview);mResolveInfos = getResolveInfo();mRecentAdapter = new RecentAdapter(mResolveInfos, context);mGridView.setAdapter(mRecentAdapter);if(list.get(0).topActivity.getPackageName().equals("com.android.zmq")){tipinfo.setText (Resources.getSystem().getText(com.android.internal.R.string.tipsinfo)); }mGridView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1, int arg2,long arg3) {// TODO Auto-generated method stubtry {if (mRecentAdapter.getmResolveInfos() != null) {RecentTag recentTag = getTag(mRecentAdapter.getmResolveInfos().get(arg2));if (recentTag != null){if(list.get(0).topActivity.getPackageName().equals("com.android.zmq")){isForceStopOne = true;forceStopPackage(recentTag);mRecentAdapter.setmResolveInfos(getResolveInfo());mRecentAdapter.notifyDataSetChanged();isForceStopOne = false;}else{switchTo(recentTag);dismiss(); } } }} catch (Exception e) {// TODO: handle exception}}});}知道了原因,问题就比较好解决了。既然每次都会跑onStart,那么我们就把字符的显示放在onStart中。
/** * Set up and show the recent activities dialog. */ @Override public void onStart() { super.onStart();Log.d("zmq","RecentApplicationDialog onStart");mRecentAdapter.setmResolveInfos(getResolveInfo());mRecentAdapter.notifyDataSetChanged(); if (sStatusBar != null) { sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); }ActivityManager am = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);final List<ActivityManager.RunningTaskInfo> runList = am.getRunningTasks(1); //显示字符,这样就可以每次都切换到啦。if(runList.get(0).topActivity.getPackageName().equals("com.android.zmq")){tipinfo.setText (Resources.getSystem().getText(com.android.internal.R.string.tipsinfo));}else{tipinfo.setText(Resources.getSystem().getText(com.android.internal.R.string.recent_remove_message_pb));} // receive broadcasts getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter); mHandler.removeCallbacks(mCleanup);mGridView.setFocusable(true);mGridView.setFocusableInTouchMode(true);mGridView.requestFocus(); }
问题是解决了。但是我们还是要找出根源:即为什么onCreate只会执行一次。
首先看到RecentApplicationsDialog是继承Dialog,在RecentApplicationsDialog中,除了构造函数,还有onCreate、onStart、onStop等函数。
Similar to
onCreate(Bundle)
, you should initialize your dialog in this method, including calling setContentView(View)
.Called when the dialog is starting.
Called to tell you that you're stopping.
RecentApplicationsDialog 中的onCreate只会执行一次,而且在退出dialog的时候会执行onStop,并且并没有看到相关的控制。于是开始在Dialog的源码中寻找根源。
在打开最近应用这个对话框的时候,会先调用RecentApplicationsDialog 的构造函数(如果已经打开过一次,则不会再运行),然后判断这个对话框是否处于showing模式,如果不是的话,则show,否则,dismiss。
void showOrHideRecentAppsDialog(final int behavior) { mHandler.post(new Runnable() { @Override public void run() { if (mRecentAppsDialog == null) { mRecentAppsDialog = new RecentApplicationsDialog(mContext); } if (mRecentAppsDialog.isShowing()) { switch (behavior) { case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: case RECENT_APPS_BEHAVIOR_DISMISS: mRecentAppsDialog.dismiss(); break; case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: mRecentAppsDialog.dismissAndSwitch(); break; case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: default: break; } } else { switch (behavior) { case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: mRecentAppsDialog.show(); break; case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: try { mWindowManager.setInTouchMode(false); } catch (RemoteException e) { } mRecentAppsDialog.show(); break; case RECENT_APPS_BEHAVIOR_DISMISS: case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: default: break; } } } }); }在Dialog中,show方法:
/** * Start the dialog and display it on screen. The window is placed in the * application layer and opaque. Note that you should not override this * method to do initialization when the dialog is shown, instead implement * that in {@link #onStart}. */ public void show() { Log.d("zmq","Dialog show"); if (mShowing) { if (mDecor != null) { if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); } mDecor.setVisibility(View.VISIBLE); } return; } mCanceled = false; //mCreated初始值为false,即第一次是会执行的 if (!mCreated) { dispatchOnCreate(null); } onStart(); mDecor = mWindow.getDecorView(); if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { final ApplicationInfo info = mContext.getApplicationInfo(); mWindow.setDefaultIcon(info.icon); mWindow.setDefaultLogo(info.logo); mActionBar = new ActionBarImpl(this); } WindowManager.LayoutParams l = mWindow.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); nl.copyFrom(l); nl.softInputMode |= WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; l = nl; } try { mWindowManager.addView(mDecor, l); mShowing = true; sendShowMessage(); } finally { } }可以看到,只有第一次的时候,mCreated为false,才会运行dispatchOnCreate,在dispatchOnCreate中:
// internal method to make sure mcreated is set properly without requiring // users to call through to super in onCreate void dispatchOnCreate(Bundle savedInstanceState) { Log.d("zmq","Dialog dispatchOnCreate");Log.d("zmq","Dialog dispatchOnCreate mCreated = "+mCreated);if(savedInstanceState!=null){Log.d("zmq","Dialog dispatchOnCreate savedInstanceState != null");}else{Log.d("zmq","Dialog dispatchOnCreate savedInstanceState == null");} //mCreated第一次是false if (!mCreated) { //执行RecentApplicationsDialog中的onCreate onCreate(savedInstanceState); mCreated = true; //设置为true,以后就不再执行。这里就是根源啦 } }
这样我们就找到RecentApplicationsDialog中onCreate只执行一次根源啦。
执行完onCreate ,回到show方法,继续执行onStart,然后回到show方法,最后显示出dialog。
dismiss掉Dialog的时候,最终会调用dimissDialog方法,然后会调用onStop。
/** * Dismiss this dialog, removing it from the screen. This method can be * invoked safely from any thread. Note that you should not override this * method to do cleanup when the dialog is dismissed, instead implement * that in {@link #onStop}. */ @Override public void dismiss() { Log.d("zmq","Dialog dismiss"); if (Looper.myLooper() == mHandler.getLooper()) { dismissDialog(); } else { mHandler.post(mDismissAction); } } void dismissDialog() {Log.d("zmq","Dialog dismissDialog"); if (mDecor == null || !mShowing) { return; } if (mWindow.isDestroyed()) { Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!"); return; } try { mWindowManager.removeViewImmediate(mDecor); } finally { if (mActionMode != null) { mActionMode.finish(); } mDecor = null; mWindow.closeAllPanels(); onStop(); mShowing = false; sendDismissMessage(); } }
最后总结一句话就是:因为在Dialog这个类中,show方法中会有标志位mCreated做判断,mCreated初始值为false。在第一次创建这个Dialog的时候会执行onCreate ,后然mCreated被设置为true。再次调用show方法时,就不会去跑onCreate,只会去跑onStart了。
也算是知其所以然了~
0 0
- 在Setting中切换中英文后,打开最近应用,里面的提示字符不会切换中英文
- PB中中英文的切换
- Android应用 中英文切换
- 谷歌拼音输入法PinyinIME源码修改----随着Setting中中英文的切换对应改变软键盘中英文输入且字符变换
- cmd 里面切换中英文输入法
- 在NetBeans中进行中英文版本切换
- 中英文切换
- 中英文切换
- 关于中英文切换 切换后按钮背景颜色改变的
- Android 应用(中英文)切换
- Android 应用(中英文)切换
- Android 应用(中英文)切换
- Android 应用(中英文)切换
- Android 应用(中英文)切换
- Struts2的国际化,中英文切换
- Struts2的国际化,中英文切换
- struts2的国际化,中英文切换
- 开发APP的中英文切换
- TNS-01189 The listener could not authenticate the user
- 内存泄漏从入门到精通三部曲之排查方法篇
- iBatis简单入门教程
- <UIKit/UIKit.h> 继承关系图
- sip路由原理
- 在Setting中切换中英文后,打开最近应用,里面的提示字符不会切换中英文
- <9> go worker线程池
- html5,html5教程
- linux oracle 乱码
- 接口是否可继承接口(java)
- Windows下MySQL 5.6.27.0.安装及配置
- Oracle改变会话日期格式
- 选择排序,冒泡排序
- 谁说菜鸟不会数据分析(工具篇)---读书笔记