一、android的开发,HTC手机上不显示menu模拟键解决办法:

在AndroidManifest.xml中讲targetSdkVersion改为9。

<uses-sdk
android:minSdkVersion="4"
android: targetSdkVersion="9" />

原因:
(1)华为没有菜单键的硬按钮;
(2)高版本默认OptionsMenu在ActionBar里,不会有虚拟menu键;

二、Menu模拟键与android:targetSdkVersion
今天一个朋友的软件在我的机子上出现了这个问题,就是没有了menu,成了全屏软件,再翻看以前一些同学的代码和网上所谓的教程,也存在同样的问题,是有必要写篇博客了,好进入正题。

如果开发的时候使用的4.x之前的SDk,请在写置android:targetSdkVersion=""的时候不要写4.x的版本,不管你是否需要menu这都不是一个很好的编程习惯,保持界面的一致性是每个开发者应该共同维护的事情。

这里说明一下android:targetSdkVersion的含义:
这里必须提到另外几个概念minSdkVersion、maxSdkVersion
minSdkVersion与maxSdkVersion比较容易理解,就是在安装程序的时候,如果目标设备的API版本小于minSdkVersion,或者大于maxSdkVersion,程序将无法安装(这一点必须注意,如果你的程序希望给2.1用,而且没有用高级的api,请设定尽量低的版本)。一般来说没有必要设置maxSdkVersion,android自身平台具有向下兼容性。
targetSdkVersion相对复杂一些,如果设置了此属性,那么在程序执行时,如果目标设备的API版本正好等于此数值,他会告诉Android平台:此程序在此版本已经经过充分测,没有问题。不必为此程序开启兼容性检查判断的工作了。也就是说,如果targetSdkVersion与目标设备的API版本相同时,运行效率可能会高一些。这里就出现了刚才的问题,如果你为低版本的sdk软件设置了高版本的target,号称适应4.x,系统自然不会帮你检查兼容性,4.x取消了屏幕下方的menu键,也就出现了这个问题。所以要注意,target不是说你能支持的版本,是你的目标版本。新的adt建议设置target,又是指最高版本,google会去发布这个规定吗,所以还是需要多去理解,不能生硬看api才能更多的从android开发中学到东西,android给了我们个人或小团队开发者一个做真正有用产品的机会。
这也带来了另一个必须说的问题,就是比如说,使用了targetSdkVersion这个SDK版本中的一个特性,但是这个特性在低版本中是不支持的,那么在低版本的API设备上运行程序时,可能会报错:java.lang.VerifyError,我今天也刚刚遇到用户反馈的这个问题,现在通过具体了解这个问题也有了更加清晰的认识。这个错误也就是说,此属性不会帮你解决兼容性的测试问题。因此你至少需要在minSdkVersion这个版本上将程序完整的跑一遍来确定兼容性是没有问题的。

在default.properties中的target是指在编译的时候使用哪个版本的API进行编译。

再吐槽几句吧,如果希望开发Android平台,请不要抱怨分辨率,不要抱怨机型,为你的用户定做最合适的产品是你的义务。
另一方面说,如果我们试着去习惯4.x的设计和编码理念,就会减少很多这方面的困扰,google给了我们很多解决方案,我们应该试着去习惯,而不是做一个2.x的开发者,虽然我们的用户大都是2.x的版本,但是理念总归需要先进一点的,开放,共同学习,这才是android。

最后补充官方文档的一些解释:
(1)targetsdkversion即其以上的版本将使用新的功能(os new api),但对低版本的需要进行code支持,即文章【1】写到的使用反射(reflection)的技术对老版本使用的一些api功能进行支持,否则会出现老版本上崩溃的现象;
(2)使用最新的开发平台开发,并设置其对应的targetsdkversion;发布的时候,需要从min到target上均需要进行测试;
(3)文章【2】提到了最大兼容性的问题,体现到两个方面:device feature support(新的属性), 和OS version support(新的api)。当进入新的开发平台时,为了使应用程序最大兼容性,可以对用不到新平台支持的一些特性进行选择设置,使得老版本(不被Market过滤掉)可以安装使用.

(4)minSDKVersion是向后(老版本)兼容,targetSDKVersion是向前兼容。  


三、android:targetSdkVersion引起的问题

项目在三星S3和三星Note II 上调用系统相机点击存储的时候崩溃了。查了半天没弄明白原因,后来发现就是因为在manifest里设置了android:targetSdkVersion = 14,导致程序出问题了。后来查下资料,在sdkversion 12以上,不包含12,设置了android:targetSdkVersion之后,android:configChanges="orientation|keyboardHidden"没有起作用,导致程序onCreate还会走。解决方法就是在android:configChanges="orientation|keyboardHidden|sreenSize".这样就ok了。

最近两天一直在纠结个问题,就是我们新版的软件通过IDEA编译出来运行在4.4的手机上整个相机UI是完全错乱的,同事几个手机运行都一样,错乱的样子就是整个UI压缩挤压在一起,完全不是你在布局里面设置的还具有相对位置的样子。 但是通过IDEA的布局文件的design按钮看到的布局展示demo又是正常的,所以,一直怀疑是编译的问题,或者某些控件的id是否有重复。于是重新rebuild,重新删除out,gen目录,重新编译,问题依旧。晕哦,怎么回事?于是,我想仔细去分析下。于是随意又用meizu的4.1系统的手机去试了下,结果,我擦,居然正常的,怎么回事?问了同事最近有没有改过相机相关的代码,都说没有。我看了提交记录,的确是没有啊,怎么可能呢?实在想不明白,后来追踪以前的记录,发现改了manifest里面一个地方就是android:targetSdkVersion这个属性,晕,这个属相和相机UI展示有毛线关系,哎,还是看看吧。同事从android:targetSdkVersion = 14改成了android:targetSdkVersion = 19,于是恢复试试,结果,我去,居然运行ok了,再改回19试试,擦,又不ok了。好了,原因找到了,是android:targetSdkVersion的问题,可是为什么android:targetSdkVersion会影响到相机UI的展示?八竿子打不着啊!!android:targetSdkVersion="14",targetSdkVersion属性会告诉系统应用是在api level为14的系统上进行的测试,应用不允许有向上兼容的行为。当应用运行在版本更高的api level的系统上时,应用还是按照targetSdkVersion版本的运行,而不需要根据更高版本的系统来显示。但是为什么会出现这个问题?接下来我看了下4.4系统api的说明,在Build.java类里面        /**         * <a href="http://www.it165.net/pro/ydad/" target="_blank" class="keylink">Android</a> 4.4: KitKat, another tasty treat.         *         * <p>Applications targeting this or a later release will get these         * new changes in behavior:</p>         * <ul>         * <li> The default result of {android.preference.PreferenceActivity#isValidFragment         * PreferenceActivity.isValueFragment} becomes false instead of true.</li>         * <li> In {@link android.webkit.WebView}, apps targeting earlier versions will have         * JS URLs evaluated directly and any result of the evaluation will not replace         * the current page content.  Apps targetting KITKAT or later that load a JS URL will         * have the result of that URL replace the content of the current page</li>         * <li> {@link android.app.AlarmManager#set AlarmManager.set} becomes interpreted as         * an inexact value, to give the system more flexibility in scheduling alarms.</li>         * <li> {@link android.content.Context#getSharedPreferences(String, int)         * Context.getSharedPreferences} no longer allows a null name.</li>         * <li> {@link android.widget.RelativeLayout} changes to compute wrapped content         * margins correctly.</li>         * <li> {@link android.app.ActionBar}'s window content overlay is allowed to be         * drawn.</li>         * <li>The {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}         * permission is now always enforced.</li>         * <li>Access to package-specific external storage directories belonging         * to the calling app no longer requires the         * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} or         * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}         * permissions.</li>         * </ul>         */        public static final int KITKAT = 19;里面有句话说了android.widget.RelativeLayout} changes to compute wrapped content margins correctly,说重新修改了RelativeLayout计算margin的方式,我想,可能是不是和改动RelativeLayout有关呢?接下来又去看了RelativeLayout的api说明。擦,这下貌似有问题了,RelativeLayout里面介绍说Note: In platform version 17 and lower, RelativeLayout was affected by a measurement bug that could cause child views to be measured with incorrect MeasureSpec values. (See MeasureSpec.makeMeasureSpec for more details.) This was triggered when a RelativeLayout container was placed in a scrolling container, such as a ScrollView or HorizontalScrollView. If a custom view not equipped to properly measure with the MeasureSpec mode UNSPECIFIEDwas placed in a RelativeLayout, this would silently work anyway as RelativeLayout would pass a very large AT_MOST MeasureSpec instead.This behavior has been preserved for apps that set android:targetSdkVersion="17" or older in their manifest's uses-sdk tag for compatibility. Apps targeting SDK version 18 or newer will receive the correct behavior他说RelativeLayout里面的MeasureSpec.makeMeasureSpec在17以前实现是有问题的,17以后才改了,哦,MeasureSpec.makeMeasureSpec这个方法有问题,好了,继续调查。我们的相机ui是这样写的    <com.pinguo.camera360.camera.controller.CameraLayout        android:id="@+id/layout_camera_container"        android:layout_width="fill_parent"        android:layout_height="fill_parent"        android:background="#ff000000">        <!-- 预览取景区域,ID不能随意变动 -->        <include            android:id="@+id/layout_camera_preview"            layout="@layout/camera_preview_container"/>        <!-- 底部bar,ID不能随意变动 -->        <include            android:id="@+id/layout_camera_bottom_bar"            layout="@layout/layout_camera_bottom_menu2"/>    </com.pinguo.camera360.camera.controller.CameraLayout>   这个CameraLayout是一个自定义的View,继承的是ViewGroup,   ----public class CameraLayout extends ViewGroup-----   然后CameraLayout里面重写了onMeasure方法,也用到了MeasureSpec.makeMeasureSpec方法,恩,可能有问题,继续       @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = MeasureSpec.getSize(widthMeasureSpec);        int height = MeasureSpec.getSize(heightMeasureSpec);        calcLayoutRect(width, height);        final int count = getChildCount();        for (int i = 0; i < count; i++) {            final View child = getChildAt(i);            if (child.getVisibility() != View.GONE) {                switch (child.getId()) {    // 就是这个android:id="@+id/layout_camera_preview"                    case PREVIEW_ID:                        int wm2 = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,preLayRect.right - preLayRect.left);                        int hm2 = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,preLayRect.bottom - preLayRect.top);                        child.measure(wm2, hm2);                        break;    // 就是这个android:id="@+id/layout_camera_bottom_bar"                    case BOTTOM_ID:                        int wm3 = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,botLayRect.right - botLayRect.left);                        int hm3 = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY,botLayRect.bottom - botLayRect.top);                        child.measure(wm3, hm3);                        break;                    default:                        break;                }            }        }    }仔细一看,发现 MeasureSpec.makeMeasureSpec(preLayRect.right - preLayRect.left,MeasureSpec.EXACTLY);这个方法参数传反了,public static int makeMeasureSpec(int size, int mode)方法第一个应该是size,第二个是mode,但是我们自己不小心写错了。那么为什么写错了,一直没出错呢,用户没反馈呢,不应该啊。继续看源码当我们把android:targetSdkVersion="14"配置成14的时候,也就是使用4.0的实现,4.0源码的makeMeasureSpec是这样实现的,4009        /**14010         * Creates a measure specification based on the supplied size and mode.14011         *14012         * The mode must always be one of the following:14013         * <ul>14014         *  <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>14015         *  <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>14016         *  <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>14017         * </ul>14018         *14019         * @param size the size of the measure specification14020         * @param mode the mode of the measure specification14021         * @return the measure specification based on size and mode14022         */14023        public static int makeMeasureSpec(int size, int mode) {14024            return size + mode;14025        }大爷的,这就是上面系统说的那个问题了,这个实现不管你参数传没传反,都是返回一样的结果。所以,配置成android:targetSdkVersion="14,即使参数传反了,也没问题。如果配置android:targetSdkVersion="19",那么采用4.4的实现来运行代码。而4.4修改后的实现是这样的        /**         * Creates a measure specification based on the supplied size and mode.         *         * The mode must always be one of the following:         * <ul>         *  <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li>         *  <li>{@link android.view.View.MeasureSpec#EXACTLY}</li>         *  <li>{@link android.view.View.MeasureSpec#AT_MOST}</li>         * </ul>         *         * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's         * implementation was such that the order of arguments did not matter         * and overflow in either value could impact the resulting MeasureSpec.         * {@link android.widget.RelativeLayout} was affected by this bug.         * Apps targeting API levels greater than 17 will get the fixed, more strict         * behavior.</p>         *         * @param size the size of the measure specification         * @param mode the mode of the measure specification         * @return the measure specification based on size and mode         */        public static int makeMeasureSpec(int size, int mode) {            if (sUseBrokenMakeMeasureSpec) {                return size + mode;            } else {                return (size & ~MODE_MASK) | (mode & MODE_MASK);            }        }sUseBrokenMakeMeasureSpec是什么呢?从源码可知它是用来适配的。// Older apps may need this compatibility hack for measurement.sUseBrokenMakeMeasureSpec = targetSdkVersion <= JELLY_BEAN_MR1;恩,问题找到了,当你配置android:targetSdkVersion="19"后,此时sUseBrokenMakeMeasureSpec == false,然后走的逻辑就是return (size & ~MODE_MASK) | (mode & MODE_MASK);因为此时我们方法参数传发了,所以,就导致UI布局整个出了问题,错乱了。当配置android:targetSdkVersion="14"后,及时当前运行在4.4的手机上,sUseBrokenMakeMeasureSpec也为ture,系统走的还是老的错误实现方式布局(虽然是错误的,但是google能让它正常运行,只是实现不对而已),所以,就还是ok的。这就是和原因所在。


更多相关文章

  1. mybatisplus的坑 insert标签insert into select无参数问题的解决
  2. android“设置”里的版本号
  3. 关于Android(安卓)Studio3.2新建项目Android(安卓)resource link
  4. Android(安卓)version and Linux Kernel version
  5. opengrok setup on ubuntu for android source code browser
  6. Android软键盘适配问题
  7. Android——开发环境
  8. android通过ksoap2对webservice的解析
  9. Android如何获得系统版本

随机推荐

  1. 安卓基础学习(android studio)
  2. Android浸入式
  3. android MultiDex
  4. Android(安卓)- MPTCP - (./net/ipv4/Kco
  5. Android(安卓)Activity 四种启动模式
  6. Fragment中跨线程调用控件的问题
  7. android4.0 上定制状态栏
  8. Android(安卓)Launcher 如何去掉主菜单,所
  9. android 仿微信多图选择器(带预览、照相
  10. Android(安卓)RIL 架构学习总结 .