热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

froyo系统原生bug及修正:改变系统语言时Launcher2的AllApps内shortcut不刷新

把froyo的Launcher2移植到eclair后,产生了一些小问题,都一一解决掉了.这是市场反馈回来的一个问题之一,摸清内部机制颇废了一番周折.也算见识了android系统内部

把froyo的Launcher2移植到eclair后,产生了一些小问题,都一一解决掉了.这是市场反馈回来的一个问题之一,摸清内部机制颇废了一番周折.也算见识了android系统内部的另一个面向切面编程案例,很有必要记录一下,有时间好好研究研究,可以借此做些特殊的系统功能.

严格意义上说,这并不是跨版本移植产生的问题,而是系统原生的一个bug,用samsung的galaxy tab平板模拟器测试同样是此现象:当在Launcher里面启动Settings,改变语言设置后,再回到Launcher,AllApps2D里面的shortcuts文字部分并不随之更新,还是保持原样.其它部分却已更新.

察看Settings源码可以知道,设置语言,改变的只是执行了如下代码:


Java代码 收藏代码
  1. try
  2.     IActivityManager am = ActivityManagerNative.getDefault(); 
  3.     Configuration config = am.getConfiguration(); 
  4.  
  5.     Loc loc = mLocales[position]; 
  6.     config.locale = loc.locale; 
  7.  
  8.     // indicate this isn't some passing default - the user wants this remembered 
  9.     config.userSetLocale = true
  10.  
  11.     am.updateConfiguration(config); 
  12.     // Trigger the dirty bit for the Settings Provider. 
  13.     BackupManager.dataChanged("com.android.providers.settings"); 
  14. } catch (RemoteException e) { 
  15.     // Intentionally left blank 
  16. finish(); 

try {IActivityManager am = ActivityManagerNative.getDefault();Configuration config = am.getConfiguration();Loc loc = mLocales[position];config.locale = loc.locale;// indicate this isn't some passing default - the user wants this rememberedconfig.userSetLocale = true;am.updateConfiguration(config);// Trigger the dirty bit for the Settings Provider.BackupManager.dataChanged("com.android.providers.settings");} catch (RemoteException e) {// Intentionally left blank}finish();

在configuration改变后,系统会让每一个切换到前台的Activity destroy,然后重新加载至原位置,非常奇妙的刷新操作,有时间要看看他如何保存当前状态的代码,比如,当前切换到前台的Activity是launcher,则会一直加载到allapps2d打开,而不是oncreate完成后的初始位置.对于状态机学习来说,Launcher无疑是很好的教科书.

然而,configuration的控制范围只是所有的Activity,Activity实现了一个接口ComponentCallbacks,里面有:

Java代码 收藏代码
  1. /**
  2. * Called by the system when the device configuration changes while your
  3. * activity is running.  Note that this will only be called if
  4. * you have selected configurations you would like to handle with the
  5. * {@link android.R.attr#configChanges} attribute in your manifest.  If
  6. * any configuration change occurs that is not selected to be reported
  7. * by that attribute, then instead of reporting it the system will stop
  8. * and restart the activity (to have it launched with the new
  9. * configuration).
  10. *
  11. *

    At the time that this function has been called, your Resources

  12. * object will have been updated to return resource values matching the
  13. * new configuration.
  14. *
  15. * @param newConfig The new device configuration.
  16. */ 
  17. public void onConfigurationChanged(Configuration newConfig) { 
  18.     mCalled = true
  19.  
  20.     if (mWindow != null) { 
  21.         // Pass the configuration changed event to the window 
  22.         mWindow.onConfigurationChanged(newConfig); 
  23.     } 

/*** Called by the system when the device configuration changes while your* activity is running. Note that this will only be called if* you have selected configurations you would like to handle with the* {@link android.R.attr#configChanges} attribute in your manifest. If* any configuration change occurs that is not selected to be reported* by that attribute, then instead of reporting it the system will stop* and restart the activity (to have it launched with the new* configuration).* *

At the time that this function has been called, your Resources* object will have been updated to return resource values matching the* new configuration.* * @param newConfig The new device configuration.*/public void onConfigurationChanged(Configuration newConfig) {mCalled = true;if (mWindow != null) {// Pass the configuration changed event to the windowmWindow.onConfigurationChanged(newConfig);}}

而对于Launcher来说,allapps里面的内容是通过LauncherModel.java里面的线程类去异步加载的,重启Launcher这个Activity,并不会让LauncherModel里面的缓存的allapps内容刷新,Launcher是直接拿了LauncherModel里面缓存的query数据而不是通知loader线程重新获取,问题就出在这里了.

解决的方法并不复杂,Launcher在调onCreate()的时候,会调用checkForLocaleChange()方法检查是否语言设置是否被修改,我们定义一个boolean类变量,把语言设置是否改变存到里面,然后为LauncherModel重构一个startLoader方法,在onCreat()代码的相应位置调用此重构方法,把状态值传进去.在内部类Loader的loadAndBindAllApps()方法里,增加判断条件让语言改变时走loadAllAppsByBatch()路线即可.

我们来看看可以从中学到些什么?

1\定义和使用configuration的类变量,可以很好的传递任何全局数据,可以和硬件方便的通信.

2\利用configuration控制framework各模块ui.一个简单例子,在launcher中,利用语言设置变化,显示或隐藏不同语言环境的应用,比如面向国内市场的机器,youtube反正用不上,就可以隐藏掉.加上youku.平板电脑没有phone功能的,把phone的shortcut给拿掉.

3\另一个想法,能否利用configuration绕过系统权限实现截屏等需要root权限的功能?


推荐阅读
author-avatar
你是谁你要知道_893
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有