欢迎Follow我的GitHub, 关注我的CSDN, 精彩不断!

CSDN: http://blog.csdn.net/caroline_wendy/article/details/68923156

在GitHub上Clone的某开源Android项目, 下载配置, 完毕构建, 在手机上能够安装, 可是无法执行. 项目的编译版本号(compileSdkVersion)是25(7.1), 最低的兼容版本号(minSdkVersion)是19(4.4), 手机的系统版本号是21(5.0), 已经满足应用的最低执行条件. 然而, 在同样系统版本号(25, 7.1)的模拟机上, 应用执行正常.

在我的手机执行应用时, 报错例如以下:

  1. E/AndroidRuntime: FATAL EXCEPTION: main
  2. java.lang.RuntimeException: Unable to start activity ComponentInfo{com.saulmm.cui/com.saulmm.cui.HomeActivity}:
  3. java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
  4. Caused by: java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.
  5. at android.support.v7.app.AppCompatDelegateImplV9.createSubDecor(AppCompatDelegateImplV9.java:359)
  6. at android.support.v7.app.AppCompatDelegateImplV9.ensureSubDecor(AppCompatDelegateImplV9.java:328)
  7. at android.support.v7.app.AppCompatDelegateImplV9.setContentView(AppCompatDelegateImplV9.java:289)
  8. at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
  9. at android.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:276)
  10. at android.databinding.DataBindingUtil.setContentView(DataBindingUtil.java:261)
  11. at com.saulmm.cui.HomeActivity.onCreate(HomeActivity.java:42)

定位

问题起源于DataBindingUtil#setContentView, DataBindingUtil绑定layout布局.

  1. // HomeActivity.java
  2. @Override
  3. protected void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. binding = DataBindingUtil.setContentView(this, R.layout.activity_home);
  6. // ...
  7. }

调用AppCompatActivity#setContentView, Activity绑定layout布局.

  1. // DataBindingUtil.java
  2. public static <T extends ViewDataBinding> T setContentView(Activity activity, int layoutId,
  3. DataBindingComponent bindingComponent) {
  4. activity.setContentView(layoutId);
  5. // ...
  6. }

终于是Activity代理实现类AppCompatDelegateImplV9实现setContentView的详细逻辑. 通过ensureSubDecor方法创建DecorView, 填充Activity的自己定义布局resId, ensureSubDecor再调用createSubDecor方法创建DecorView.

  1. // AppCompatDelegateImplV9.java
  2. @Override
  3. public void setContentView(int resId) {
  4. ensureSubDecor(); // 创建并初始化DecorView
  5. ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content);
  6. contentParent.removeAllViews();
  7. LayoutInflater.from(mContext).inflate(resId, contentParent);
  8. mOriginalWindowCallback.onContentChanged();
  9. }
  10. private void ensureSubDecor() {
  11. if (!mSubDecorInstalled) {
  12. mSubDecor = createSubDecor();
  13. // ...
  14. }
  15. }

createSubDecor方法, 依据应用的样式主题(Theme)设置根布局DecorView的样式, 并执行初始化. 当未含有AppCompatTheme_windowActionBar属性时, 则觉得主题未设置, 并抛出异常IllegalStateException.

  1. // AppCompatDelegateImplV9.java
  2. // 依据布局样式Style设置根布局DecorView的样式
  3. private ViewGroup createSubDecor() {
  4. TypedArray a = mContext.obtainStyledAttributes(R.styleable.AppCompatTheme);
  5. // 没有布局属性
  6. if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) {
  7. a.recycle();
  8. // 问题所在!
  9. throw new IllegalStateException(
  10. "You need to use a Theme.AppCompat theme (or descendant) with this activity.");
  11. }
  12. // ...
  13. }

为什么API 25的模拟器能够启动, 我的手机(API 21)就不能启动呢? 原因非常easy, 就是由于开源项目的主题资源设置有误. 默认主题在AndroidManifesttheme属性中设置.

  1. <application android:theme="@style/AppTheme">

点击IDE的AppTheme跳转至声明, 发现仅仅有一处, 即在values-v23中声明.

原因

对于资源属性而言, 系统默认查找与匹配低于当前API等级的属性, 保证高版本号属性不会在低版本号中执行. 由于高版本号会加入很多其它的新接口, 低版本号无法找到, 强制使用可能导致异常甚至崩溃, 所以禁止訪问高版本号的属性.

解决

理解了问题的所在, 解决方式就非常easy. 为了支持最低API以上的所有系统, 在默认的values/themes.xml中, 加入AppTheme属性就可以.

  1. <style name="AppTheme" parent="Base.AppTheme"/>

问题虽小, 但不可忽视, 否则就仅仅能在某些手机可用, 在某些手机崩溃, 摸不着头脑. 在开发中, 优先在默认values目录中加入属性, 假设须要额外支持, 在其它高版本号values-vXX中再加入. Do you get it?

That’s all! Enjoy it!

为什么手机无法执行应用? Values之谜的更多相关文章

  1. Linux下的Jenkins作为hub,Windows作为node节点,在Android手机上执行自动化脚本

    1.在Linux上放selenium-server-standalone-2.53.0.jar,在jar包目录下执行命令java -jar selenium-server-standalone-2.5 ...

  2. 【初体验】macos下android ndk交叉编译hello world,并拷贝到android手机上执行

    1.机器上以前安装了java 1.8(貌似android ndk不需要java) 2. 下载android ndk,版本是android-ndk-r14b (比较奇怪,我下载了最新的android-n ...

  3. 使用Java让android手机自动执行重复重启

    public static void main(String[] args)throws IOException,Exception { for(int j=0;j<10;j++) { Thre ...

  4. C#跨平台手机应用开发工具Xamarin尝试 与Eclipse简单对比

    Xamarin 支持使用C#开发基于Android.IOS.WindowsPhone应用开发,最大特点C#+跨平台,详细说明问度娘. 安装 研究 想体验研究的点击查看页面 Xamarin For Vi ...

  5. x86架构手机跑安卓好吗?(脑补)

    华硕低价位手机ZenFone一推出就掀起市场话题,许多人也对ZenFone所采用的Intel Atom处理器有所意见,深怕其相容性问题无法正确执行应用程式App,这究竟是怎么回事呢? Intel近几年 ...

  6. 技术解析:锁屏绕过,三星Galaxy系列手机也能“被”呼出电话

    近期,由两位安全研究人员,Roberto Paleari及Aristide Fattori,发布了关于三星Galaxy手机设备安全漏洞的技术细节.据称,Galaxy手机可在锁屏状态下被未授权的第三方人 ...

  7. Android手机一键Root原理分析

    图/文 非虫 一直以来,刷机与Root是Android手机爱好者最热衷的事情.即使国行手机的用户也不惜冒着失去保修的风险对Root手机乐此不疲.就在前天晚上,一年一度的Google I/O大会拉开了帷 ...

  8. 泛泰A900 刷4.4专用中文TWRP2.7.1.1版 支持自己主动识别手机版本号(全球首创)

    因本人手上的A900S已砖, 所以临时弄不了ROM了, 先上传之前已经弄好的刷4.4专用的新版TWRP recovery 2.7.1.1  这个版本号是我自己定义的,为差别之前公布的2.7.0.0版( ...

  9. 让Qt for Windows Phone 8.1在真机上执行

    让Qt for Windows Phone 8.1在真机上执行 前面几篇博文是为这篇文章做铺垫的,终于目的为的是使用Qt框架制作出可以在Windows Phone 8.1真机上执行的程序.因为Qt f ...

随机推荐

  1. HDUOJ-------- Fibonacci again and again

    Fibonacci again and again Time Limit : 1000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/ ...

  2. RHCE7 -- IPv6

    IPV6地址一个128位数字   如果在IPv6地址后面包括TCP和UDP网络端口,建议将IPv6放在方括号中,以便区分: [2001:db8:0:10::1]:80   IPv6的标准子网掩码是&q ...

  3. AR_标准应收过账至总账基本操作(流程)

    2014-06-04 Created By BaoXinjian

  4. tcp流协议产生的粘包问题和解决方案

    我们在前面曾经说过,发送端可以是一K一K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据,也就是说,应用程序所看到的数据是一个整体 ...

  5. Oracle监听配置、数据库实例配置等

    参考:http://jingyan.baidu.com/article/3aed632e7a638b70108091dd.html linux下面搞Orale参考:http://blog.sina.c ...

  6. jenkins 构建执行jmeter测试流程

    性能测试使用maven工程说明1.依赖尽量用maven依赖管理2.添加jmeter maven依赖 <dependency> <groupId>org.apache.jmete ...

  7. Android开发13——内容提供者ContentProvider的基本使用

    一.ContentProvider简介 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.ContentProvider为存储和获取数据提 ...

  8. 分享五:php数组操作

    一:PHP中array_merge和array相加的区别分析 1:键名是string: <?php $arr1 = array('a'=>'PHP'); $arr2 = array('a' ...

  9. ASP.NET 解决URL中文乱码的解决

    暂时先记录一个方法: 在Web.config文件中configuration下的system.web下加入一个配置项:globalization,主要是设置其requestEncoding,貌似中文系 ...

  10. PHP遍历目录返回统计目录大小实例

    分享一个 PHP遍历目录并返回统计目录大小的方法.代码: <?php $dirname = "test1"; //mkdir($dirname); //遍历一层目录 func ...