6九、多线程同时访问集合(ConcurrentModificationException)

问题现象: html

多线程同时修改集合时经常容易出现 ConcurrentModificationException ,即使是改为用 Collections.synchronizedCollection() 方法同步也无效。java

缘由分析:android

当集合正在迭代时,若是进行修改就会出现异常,@问题13 已经说过该问题。而 synchronizedCollection() 方法虽然对部分操做加上了 synchronized 关键字以保证线程安全,但其 iterator() 操做不是线程安全的,在迭代时操做依然会出现异常,而且效率也比较低。git

解决方法:程序员

在 Java 中早已有比较好的替代对象,相比起来有更加细化的锁机制,效率更高,不会出现 ConcurrentModificationException 异常。github

    ConcurrentHashMap 为 Map 的同步,设计与实现很是精巧,很适合学习 CopyOnWriteArrayList 为 List 的同步,采用写入时复制的方式避开并发问题,当修改操做较多时性能上会有比较大的代价

6八、Facebook 或 Twitter 自定义登录按钮样式

问题现象: web

使用官方的 SDK 作登录时,只提供了登录按钮做为跳转入口,可是样式和设计图有很大出入,直接设置按钮的样式很难达到想要的效果。数据库

缘由分析: json

官方应该是推荐登录时使用默认的样式,这样来避免或达到某些目的。虽然尽力想用默认的样式,不过因为与 UI 的其它部分太不搭了,仍是决定自定义。canvas

解决方法:

先将官方按钮设置为不可见,而后自定义效果样式按钮,并将点击事件实现为触发官方按钮的点击事件,以下:

<com.twitter.sdk.android.core.identity.TwitterLoginButton
    android:visibility="invisible" />

// 或使用 performClick() 方法
twitterLoginButton.callOnClick();

6七、Android 5.0 的通知栏 SmallIcon 的 BUG

问题现象:

android.app.RemoteServiceException: Bad notification posted from package xxx.xxx.xxx: 
Couldn't create icon: StatusBarIcon(xxx.xxxx)

缘由分析:

算做是 Android5.0 的 Bug,在 android4.4 和 6.0 中都正常。

解决方法:

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP
    || Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1){
    iconId = mContext.getApplicationInfo().icon;
}
NotificationCompat.Builder.setSmallIcon(iconId)

6六、ScrollView与RecyclerView嵌套后的冲突问题

问题现象: 咱们之前在使用GridView,ListView与ScrollView嵌套时必定有遇到显示不全或者滑动冲突等问题, 在咱们的RecyclerView使用中仍然难逃此劫,甚至有的时候会有卡顿的问题。下面咱们介绍一下如何解决这个问题

缘由分析:

同理与ListView与GridView相同

解决方法:

一、卡顿,滑动不流畅问题。

首先解决卡顿的问题使用mRecyclerView.setNestedScrollingEnabled(false);
这个目前是最优解

二、显示不全(6.0以上容易出现此问题)

方法一:在Recycler的父布局中添加RelativeLayout隔离,不用像一些博客说的那样进行高度计算和 OnMeasured()重写。(未解决尝试方式二)

方法二:将你的ScrollView替换成android.support.v4.widget.NestedScrollView,此方法对此问题有优化(未解决尝试方式三)

方法三:如上还未解决或者只显示一行,把design库和V7库升级到23.2以上,而后加上以下代码
mLinearLayoutManager.setSmoothScrollbarEnabled(true);
mLinearLayoutManager.setAutoMeasureEnabled(true);
mRecuclerView.setLayoutManager(mLinearLayoutManager);
mRecuclerView.setHasFixedSize(true);
mRecuclerView.setNestedScrollingEnabled(false);

若是还未解决,或者只显示一行,你能够核对一下你的适配器子布局中高度是否使用了
android:layout_height=”match_parent”

6五、Android Studio 3.0 编译项目没法找到 Gradle

问题现象: build.gradle 文件:

// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0-alpha3'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
allprojects {
    repositories {
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}

Android Studio 3.0 Canary 3 编译项目提醒:

Error:Could not find com.android.tools.build:gradle:3.0.0-alpha2.
Searched in the following locations:
    file:/Applications/Android Studio 3.0 Preview.app/Contents/gradle/m2repository/com/android/tools/build/gradle/3.0.0-alpha2/gradle-3.0.0-alpha2.pom
    file:/Applications/Android Studio 3.0 Preview.app/Contents/gradle/m2repository/com/android/tools/build/gradle/3.0.0-alpha2/gradle-3.0.0-alpha2.jar
    https://jcenter.bintray.com/com/android/tools/build/gradle/3.0.0-alpha2/gradle-3.0.0-alpha2.pom
    https://jcenter.bintray.com/com/android/tools/build/gradle/3.0.0-alpha2/gradle-3.0.0-alpha2.jar
Required by:
    project :

缘由分析:找不到,多是网络或者服务器问题,最终定位到是 Google 更新了针对 Android Gradle 编译的仓库地址有更新。

解决方法:咱们须要在 build.gradle 文件中追加:

repositories {
   maven {
       url "https://maven.google.com"
   }
}

官方文档说明: https://android-developers.googleblog.com/2017/05/android-studio-3-0-canary1.html

6四、编译时出现jar包内包含相同的文件

问题现象: 我在项目中添加了一些jar的引用,但在编译的时候发现存在相同的文件,致使编译失败。 缘由分析:

Error:Execution failed for task ‘:app:transformResourcesWithMergeJavaResForDebug’.
com.android.build.api.transform.TransformException: com.android.builder.packaging.DuplicateFileException: Duplicate files copied in APK META-INF/*.properties

解决方法: 若是依赖的jar使用屡次引用版本不一样的jar包,那么最好的办法是选择留下最合适的版本jar包。小几率是由于使用不是相同的jar包时出现了文件冲突问题,这时候在build.gradle中添加packagingOptions就能解决。

packagingOptions { 
     exclude 'META-INF/***.properties      }

6三、关于so库使用小总结

问题现象: 应用中新添加了so库,在32位处理器上没有问题,跑64处理器的时候出现了UnsatisfiedLinkError的问题,查看了异常是lib64的so库没有找到,以后添加了ndk的配置后,成功在64处理器上跑通,但发现library里的so库受到影响,加载失败。 缘由分析:

java.lang.UnsatisfiedLinkError:dalvik.system.PathClassLoader
java.lang.UnsatisfiedLinkError:No implementation found for void io.vov…. MedioPlayer.native_init()

第一个异常里面有lib64 so 没有发现,直接找64和32位的问题,第二个 问题指向的是一个native方法init失败,打包apk发现只有armeabi中的so库,而library中为了优化性能和文件大小,只在armeabi留下一个库,其余都放在了其余文件夹中。 解决方法: 处理64位兼容上,使用了兼容armeabi的方法,在build.gradle中添加了

ndk {
    abiFilters "armeabi"
    }

因为library中armeabi只有一个so库,因此加载失败了。缘由是指定要ndk须要兼容的架构(这样其余依赖包里mips,x86,armeabi,arm-v8之类的so会被过滤掉),因此在上面添加了

ndk {
    abiFilters "armeabi", "x86","armeabi-v7a"
    }

这样就能兼容我使用的库中的全部so,但仍是担忧后面有加载库失败的问题,查看了网上abi的资料,没问题。 在项目只包含了 armeabi,那么在全部Android设备均可以运行; 若是项目只包含了 armeabi-v7a,除armeabi架构的设备外均可以运行; 若是项目只包含了 x86,那么armeabi架构和armeabi-v7a的Android设备是没法运行的; 若是同时包含了 armeabi, armeabi-v7a和x86,全部设备均可以运行,程序在运行的时候去加载不一样平台对应的so,这是较为完美的一种解决方案,同时也会致使包变大。

6二、Google Play Store 过滤问题总结

说明:当用户在 Google Play 上搜索或浏览应用如下载时,会根据哪些应用与其设备兼容来过滤搜索结果。例如,若是应用须要摄像头,Google Play 不会在没有摄像头的设备上显示该应用。这种过滤帮助开发者管理其应用的分发,而且有助于确保为用户提供最佳的体验

过滤规则 : https://developer.android.com/google/play/filters.html?hl=zh-cn

注:须要硬件支持的权限也会默认进行设备兼容过滤;

如何去掉指定功能设备兼容过滤 :

Nexus 7 没有电话功能 ,然而在应用的 Manifest 文件里声明了电话相关的权限,但愿不支持电话功能的设备也能搜索该 APP ,就在 Manifest 文件添加以下代码 :

<uses-feature android:name="android.hardware.telephony" android:required="false"/>

注:经过显式声明某项功能并加入 android:required=”false” 属性,能够在 Google Play 上有效停用全部针对指定功能的过滤。

更多功能声明 : https://developer.android.com/guide/topics/manifest/uses-feature-element.html?hl=zh-cn#permissions-features

6一、媒按键监听,Android5.0+ 不一样的监听方式

使用场景描述: 应用中须要播放音乐的时候,一般有个使人捉急的问题就是媒体焦点;假如同时用 QQ音乐 与本身的应用同时播放音乐的时候,媒体焦点到底花落谁家,谁可以响应此次媒体按键;这就要看谁最后申请了这个焦点

以往的方式都是经过广播的形式,来看看 Android 5.0+ 的注册方式

int result = audioManager
            .requestAudioFocus(onAudioFocusChangeListener,
                    AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

    if (AudioManager.AUDIOFOCUS_REQUEST_GRANTED == result) {

        if (android.os.Build.VERSION.SDK_INT >= 21) {
            //注册媒体按键 Android 5.0+
             session = new MediaSession(mContext, "tag");
            session.setCallback(new MediaSession.Callback() {
                //这里重写 播放/暂停,上下一曲的回调 ,按键都走这里的回调         
            }

        } else {
            //一般的注册媒体按键 ,广播的方式
            audioManager.registerMediaButtonEventReceiver(mComponentName);
        }

    }

Android 5.0+ 若是用以往广播的方式注册,焦点抢不过来;

详细代码请参考:Android 注册媒体按键监听

WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE

问题: Android6.0+的手机上使用录音功能后播放无声音,此时用户点击了容许录音的权限,可是仍然没法录音。

解决: 经过现象排查,因为出现此问题的手机Android系统均为6.0+,而6.0+的手机在权限这块改定较大,经过调试发现此问题的缘由是没法获取WRITE_EXTERNAL_STORAGE权限,致使录音文件未被写入SD卡,以致于播放录音无声音;将文件存储路径改成/data/data/包名/cache/; 解决此问题,由于此路径为内置路径,在6.0系统( API > 23 )时,不须要申请权限就能够向这个目录写入文件。

5九、解决传说中的 Android 65k 问题

在 Android 开发中,有一个以前不多据说,最近偶尔江湖传闻听到过的问题,就是 65k 问题。什么是65k问题呢?其实很简单,就是 Android 有个限制,你的每一个 App 中函数最多只能有 65536 个。

这个限制实际上是这样的,由于在编译成 Dalvik 字节码,也就是把你的 Class 们生成打包到一个 classes.dex 中去的时候呢,编译器会给你的 App 中全部的函数方法指定一个 ID, 而后每个 classes.dex 中 ID 的范围是 [0, 0xffff] 。 因此,你懂的,就有了那么一个 65k 的问题。

编译报错现象

Error:Execution failed for task ':app:transformClassesWithDexForDebug'.
> com.android.build.api.transform.TransformException:
> com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command 'C:\Program Files\Java\jdk1.8.0_51\bin\java.exe'' finished with non-zero exit value 2

解决方法(针对Android Studio): 在build.gradle中对应的地方添加 multiDexEnabled true 这句代码就好了,以下

android {

    defaultConfig {
        multiDexEnabled true
    }

    ......

}

5八、 android 安装包过大

关于发现 android 安装包过大、想优化安装包大小时,应该先确认是哪些文件使安装包过大,能够先把安装包解压,而后查看各个目录的大小,再在目录底下确认是否引用了比较大的文件(如字体、图片等)。如某些图片过大,能够使用工具进行压缩下(如 pngyu )。若是是 res 文件夹太大,能够减小没必要要的图片资源,国际化相关的图片不须要在每一个文件夹都放入,只须要使用没有文字的图片,文字能够经过代码添加。而屏幕适配相关的图片能用 .9 图片去实现就用 .9 图片去实现。 res 文件夹太大也多是存在太多无用的资源,能够使用 Android lint 工具去检查,而后将无用资源文件通通删除。字体文件也多是致使安装包过大的缘由,能够用工具将须要使用的字体保留(如英文、数字等),其余的去除造成新的字体文件。若是使用字体的地方比较少也可以使用图片的形式去代替字体文件。项目中没用到的架包也需及时删除。关于一些比较大,但又必须的文件能够先不将其放入工程内,后面采用网络的方式加载。若是发现不了缘由能够比较项目不一样的版本,来肯定是那一次版本的更新使安装包过大,再经过更新的文件来检查缘由。

5七、BLE中心设备的 onCharacteristicChanged() 方法没有回调

描述: 当设备为 Indication 模式时,设备的值有变化时会主动返回给App,App在 onCharacteristicChanged() 方法中能收到返回的值。

问题: 在App中经过以下代码注册监听,注册成功后就能接收到设备主动反馈的值了。然而如下代码执行后依旧收不到反馈。

bluetoothGatt.setCharacteristicNotification(characteristic, true)

解决: 当上面的方法执行返回true后,还要执行以下的代码才能注册成功。(完整代码)

for(BluetoothGattDescriptor dp: characteristic.getDescriptors()){
    if (dp != null) {
        if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
        } else if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
            dp.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
        }
        gatt.writeDescriptor(dp);
    }
}

5六、Android 6.0 动态请求权限

描述: Android 应用在访问额外的资源或信息时,须要请求相应权限。根据权限的敏感性,系统可能会自动授予权限,或者由用户对请求进行许可。Android6.0及以上应用除了在清单文件中声明权限,敏感权限还须要在用户使用时动态授予。官方定义了普通和危险权限,经测试发现部分手机厂商的敏感权限会有所差别 。

问题: 应用中用到 READ_PHONE_STATE 权限来获取设备ID,在华为、小米的6.0系统的手机上运行均可以正常获取,然而在Nexus5X上获取失败而致使应用闪退。

缘由: 华为、小米等系统会默认容许该权限,而官方定义该权限为危险权限默认不被容许。

解决:

1,将 targetSdkVersion 版本号调整为 23 如下,这样应用不须要在运行时请求权限,系统会默认容许清单文件中全部权限。

2,在应用中向用户动态请求权限,请求方式可参考 5二、Android6.0扫描不到蓝牙设备的处理办法。更好的作法是使用Github上的第三方权限请求库。

5五、事件分发处理总结

在咱们Android程序中,除单一控件(继承ViewGroup)的,例如TextView,Button等是没法拦截事件外,其它View都可对事件进行分发,拦截以及向上传递。其中事件分发的事件dispatchTouchEvent。当咱们重写此方法时,能够接收父类传递下来的事件,传递true,消费此事件,不然会继续向下传递。

在传递过程当中咱们也能够经过子类对它进行拦截,方法时重写onInterceptTouchEvent方法,返回true拦截,false不拦截。

若是整个触摸事件过程当中,全部事件均未对它拦截,那么他的事件最终也会经过onTouchEvent从最下层的控件逐步向上传递,最终返回到Activity或Fragment的onTouchEvent中。

在整个事件分发中,咱们也能够经过getParent或getChildren拿到父类或子类事件进行处理。

常见事件分发冲突案例:ViewPager嵌套Fragment过程当中,在其中一个Fragment中有轮播图时,会照成事件冲突,或滑动偏移等状况。

解决方案:自定义Viewpager,重写onTouchEvent,当用户执行down与move事件时,事件分发给轮播图的控件处理,当执行到up与cancle事件时,在将事件从新传给viewPager处理。不过经过测试Android Studio中最近的v4包中好像已经修复了此问题。

5四、生命周期引发的监听问题

部分开发者在注册监听时,常常会在注册监听后在Activity或Fragment销毁时未移除此监听。

若是是单一的监听,可能仅仅只是形成内存泄漏的状况,至少用户感知不到,可是若是咱们在一个父类中写一个监听,同时有2个子类注册了此监听, 并在父类中有弹出Dialog或者刷新UI的操做时,当其中一个子类被finish掉后,其实例被回收,但其监听仍然会存在。这会引发当咱们在另一个未被finish的实例中去作跟监听相关的操做会,因为以前的实例被finish,监听又存在,回走屡次回调,而且颇有可能会致使空指针等一系列致使程序崩溃的异常。若是子类的监听无穷多,甚至会致使OOM。

建议,在实例销毁时必定要及时的移除不必的监听,竟能够节约内存,也能够避免在后期添加需求时代码的耦合性。

5三、Android细节点总结

1.timePicker点击肯定后须要clearFoucs才能获取手动输入的时间。

2.Handler在子线程使用Looper.prepare,或者new的时候给构造函数传入MainLooper来确保在主线程run。

3.ExpandableListView的子列表不能点击(禁用)要把Adapter的isChildSelectable方法返回true。

4.注意按钮的感应范围不小于9mm不然不易点击;输入框注意光标的位置更易用互输入。

5.服务器和客户端尽可能统一惟一标识(有多是ID),不然多少会有歧义和问题。

6.activity的finish方法中使用了synchronized (this),因此activity的方法尽可能不要使用 synchronized来修饰,或者有 synchronized (this)修饰的方法块,由于这些方法或者方法块一旦存在耗时操做,会致使finish方法没法执行,从而形成ANR。

7.PopupWindow中的EditText点击和长按的时候是没有复制,黏贴,全选这些选项弹出来的,这是android的一个系统bug,能够使用Dialog替代PopupWindow来达到一样的效果。

8.若是TextView的text含有特殊字符,使得text不靠TextView的左边显示,能够经过强制设置gravity为left来解决。

9. Android中animation自从开始起做用后,就缓存到了某个地方,只管不停的绘制,哪怕本身都不存在了,都还在那绘制,clearAnimation的做用就是通知一下他,你都没了,别再画了(好比一个button,startAnimation后没有clearAnimation,你点击的话很难相应,那就是由于这个button一直在不停的绘制,你点击的时候一直获取不到焦点)。

10. Android中animation对于目标view的位置其实是没有改变的,当android:fillAfter=”true”时,动画结束后view停在动画最后一祯的位置。

5二、Android6.0扫描不到蓝牙设备的处理办法

描述:在Android6.0手机上扫描不到蓝牙设备(如Nexus6),并会抛出一个异常:

java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results

解决办法: 1,在清单文件加入权限:

<uses-permissionandroid:name="android.permission.ACCESS_FINE_LOCATION"/> 
<uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION"/>

2,在Activity中调用 requestPermissions() 方法来请求权限,系统会弹出须要请求权限的对话框 3,重写Activity的onRequestPermissionsResult()方法,接收权限是否请求的请求状态 示例代码以下:

private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    ......
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // Android M Permission check
        if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
        }
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSION_REQUEST_COARSE_LOCATION:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // TODO request success
            }
        break;
    }
}

5一、Android输入法弹出,设置控件在软键盘之上显示

描述:当输入法弹出时,布局会被压缩,某些控件被遮挡住,可是需求可能并不想让该控件遮挡住。如何让某些控件也浮在软件盘上,好比“登陆”按钮。 解决:给最外层的布局设置一个OnGlobalLayoutListener的监听事件,当布局发生改变时改变控件位置的方式来实现,代码以下:

/**
    * @param root 最外层布局,须要调整的布局
    * @param scrollToView  被键盘遮挡的scrollToView,滚动root,使scrollToView在root可视区域的底部
    */
    private void controlKeyboardLayout(final View root, final View scrollToView) {
        // 注册一个回调函数,当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时调用这个回调函数。
        root.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    Rect rect = new Rect();
                    // 获取root在窗体的可视区域
                    root.getWindowVisibleDisplayFrame(rect);
                    // 当前视图最外层的高度减去如今所看到的视图的最底部的y坐标
                    int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom;
                    // 若rootInvisibleHeight高度大于100,则说明当前视图上移了,说明软键盘弹出了
                    if (rootInvisibleHeight > 100) {
                        //软键盘弹出来的时候
                        int[] location = new int[2];
                        // 获取scrollToView在窗体的坐标
                        scrollToView.getLocationInWindow(location);
                        // 计算root滚动高度,使scrollToView在可见区域的底部
                        int srollHeight = (location[1] + scrollToView.getHeight() + PixelUtil.dp2px(20, getContext())) - rect.bottom;
                        if (srollHeight != 0){
                            root.scrollTo(0, srollHeight);
                        }
                    } else {
                        // 软键盘没有弹出来的时候
                        root.scrollTo(0, 0);
                    }
                }
            });
    }

50、使用fragmentManager.add()方法打开新页面时,界面不更新保持在原界面上

描述:调用add()方法切换新页面后,界面并无替换,依旧停留在原来的页面上,而调用replace()方法时能够正常替换 缘由:替换是在LinearLayout布局中,新添加的布局显示在屏幕之外因此感受是没有开启新的页面。能够改为使用FrameLayout。

区别: add 是把一个fragment添加到一个容器 container 里。replace 是先remove掉相同id的全部fragment,而后在add当前的这个fragment。在使用add()的状况下,这个container其实有多层,多层确定要比一层的来得浪费,因此仍是推荐使用replace()。

4九、沉浸式状态栏对SlidingMenu无效的问题

针对Andorid4.4以及5.0之后,更多的APP更亲耐于沉浸式状态栏,不管从视觉和体验上都以成主流,但这种沉浸式的状态栏并未完美无缺,因为Android 中SlidingMenu有继承与ViewGroup,ViewPage等,因为源码冲突,使用普通的方法不管是设置主题,仍是经过代码设置setTranslucentStatus实测均对SlidingMenu无效。经过对SlidingMenu源码简单分析,换一种概念的来实现这种沉浸式的效果。 简单来讲分为4步来设置SlidingMenu无效的问题:

一、取消状态栏修改颜色

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);//去掉信息栏
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);//显示状态栏
        setTranslucentStatus(activity, true);
    }

二、在须要沉浸的UI父布局中添加以下属性,注意是必须添加

android:fitsSystemWindows="true"

此时状态栏若是为白色,则前面2步OK,不然rockback;

三、将总体布局往上移一个状态栏的高度,将布局顶上去

@TargetApi(19)
    public static void setTranslucentStatus(Activity activity,boolean on) {
        Window win = activity.getWindow();
        WindowManager.LayoutParams winParams = win.getAttributes();
        final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
        if (on) {
                winParams.flags |= bits;
        } else {
                winParams.flags &= ~bits;
        }
        win.setAttributes(winParams);
    }

四、经过子布局上方显示与隐藏来控制上边距

//状态栏显示隐藏设置 public static void setStatusBarViewVisibility(View view) { if (view == null) { return; } //注释掉状态栏view if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { view.setVisibility(View.VISIBLE); } else{ view.setVisibility(View.GONE); } }

以上方法在项目中亲测,有效。

4八、ListView中数据与界面显示不一样步致使的BUG

异常日志以下: java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. 我代码中产生的缘由是因为ListView数据设置的是ListA的引用,而ListA会常常变更,但界面没有跟随刷新致使。給几个避免该问题的解决办法:

    确保Adapter的数据更新后必定要调用notifyDataSetChanged()方法通知ListView 数据更新和notifyDataSetChanged()放在UI线程内,且必须同步顺序执行,不可异步 我是经过将ListView的数据与源数据隔离,如经过“new ArrayList<>(ListA)”的方式与源数据分离

4七、自定义View中绘制文字居中的问题

问题说明:在自定义View中,获取文字的高宽,并不能彻底的居中,关键代码以下:

mFontPaint.getTextBounds(text, 0, text.length(), fontRect);  
// 设置文字左下角的起始点坐标,绘制文字  
canvas.drawText(text, centerX-fontRect.width()/2, centerY+fontRect.height()/2, mFontPaint);

上面方式不能居中的缘由主要在于文字并非在它的方格正中间绘制的,而是以Baseline做为参考线绘制的。在计算文字的高度时,应该是文字的顶部减去底部的值,经过Paint.getFontMetrics()获取一个FontMetrics对象,再用它的bottom-top。设置文字居中能够用Paint.setTextAlign(Paint.Align.CENTER)方法。示例代码以下:

mPaint.setTextAlign(Paint.Align.CENTER);  
Paint.FontMetrics fontMetrics= mPaint.getFontMetrics();  
float top = fontMetrics.top;  
float bottom = fontMetrics.bottom;
canvas.drawText(text,centerX,centerY+(bottom-top)/2,mPaint);

详情参考:自定义View中文本居中显示

4六、生命周期引发的问题:

谨慎使用Android的透明主题,透明主题会致使不少问题,好比:若是新的Activity采用了透明主题,那么当前Activity的onStop方法不会被调用;在设置为透明主题的Activity界面按Home键时,可能会致使刷屏不干净的问题;进入主题为透明主题的界面会有明显的延时感;

当前Activity的onPause方法执行结束后才会执行下一个Activity的onCreate方法,因此在onPause方法中不适合作耗时较长的工做,这会影响到页面之间的跳转效率;

45.Android Jackson、Gson、FastJson解析框架总结

一、比较来讲, Gson 比 fastjson 考虑更全面, 对用 URL , UUID, BIT_SET, CALENDAR 等等,都有特定的输出规则.

二、小数量的调用 Gson 比 fastjson 快一点. (几十毫秒,能够满不在乎.猜想是由于 javassist 生成新的 Wrapper 类致使,由于还要编译的.)

三、大数量的调用 fastjson 比 Gson 快. (千万级别的.还不太肯定为何会变快, 猜想是 gson 的反射调用,毕竟比不上 fastjson Wrapper 类的真实调用.)

四、代码可阅读性: fastjson 比 Gson 好不少不少.

五、fastjson 在要序列化对象的类型的判断上,使用的是 if else 。

六、Gson 使用的是遍历 TypeAdapterFactory集合,在每一个 TypeAdapterFactory 里面作判断.并且使用了 N 多的匿名内部类, 想要一眼看出有哪些 TypeAdapterFactory 的实现都很困难.

七、若是普通平常使用,推荐使用 fastjson,简单易懂,而且是国内程序员开发,有问题能够较容易的得到支持.

八、Gson 有对各类类型的属性支持, 若是有特殊类型json化需求或复杂结构时能够选择 gson ,并自定义扩充.

九、若是你不须要对JSON文档进行按需解析、且性能要求较高的话,能够尝试使用Jackson.

44.ListView , GridView OnItemClickListener事件无响应

分析: 在Android软件设计与实现中咱们一般都会使用到ListView这个控件,系统有一些预置的Adapter能够使用,例如SimpleAdapter和ArrayAdapter,可是老是会有一些状况咱们须要经过自定义ListView来实现一些效果,那么在这个时候,咱们一般会碰到自定义ListView没法选中整个ListViewItem的状况,也就是没法响应ListView的onItemClickListener中的onItemClick()方法

解决方法: 能够经过对Item Layout的根控件设置其android:descendantFocusability=”blocksDescendants” , 这样Item Layout就屏蔽了全部子控件获取Focus的权限

注意:这个属性不能设置给ListView,设置了也不起做用 ;

43.三星手机从相册选择图片会旋转问题完美解决

问题说明: 项目中有上传图片的功能,那么涉及到拍照,从相册中选择图片,别的手机都ok没有问题,惟独三星的手机拍照以后,你会很清楚的看到会把照片旋转一下,而后你根据路径找到的图片就是已经被旋转的了; 只要在从相册中选择到照片以后获取旋转角度,而后旋转图片就完美解决了. 代码以下 : 先获取到照片的旋转角度 ;

/**
*读取照片exif信息中的旋转角度 
    * @param path 照片路径 
    * @return角度
    */
public static int readPictureDegree(String path) {  
    int degree  = 0;  
    try {  
        ExifInterface exifInterface = new ExifInterface(path);  
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  
        switch (orientation) {  
            case ExifInterface.ORIENTATION_ROTATE_90:  
                degree = 90;  
                break;  
            case ExifInterface.ORIENTATION_ROTATE_180:  
                degree = 180;  
                break;  
            case ExifInterface.ORIENTATION_ROTATE_270:  
                degree = 270;  
                break;  
        }  
    } catch (IOException e) {  
        e.printStackTrace();  
    }  
    return degree;  
}

而后咱们只须要根据旋转角度将图片旋转过来就OK了

/**
 * 旋转图片
 * @img 须要旋转的 图片
 * @rotate 旋转的角度
 * */
public static Bitmap rotateBitmap(Bitmap img, int rotate) {
    Matrix matrix = new Matrix();
    matrix.postRotate(rotate);
    int width = img.getWidth();
    int height = img.getHeight();
    img = Bitmap.createBitmap(img, 0, 0, width, height, matrix, true);
    return img;
}

42.Android七月份细节点分享

1.与Activity通信使用Handler更方便;若是你的框架回调链变长,考虑监听者模式简化回调。

2.有序队列操做add、delete操做时,注意保持排序,不然你会比较难堪哦。

3.数据库删除数据时,要注意级联操做避免出现永远删除不了的垃圾数据。

4.关于形参实参:调用函数时参数为基本类型传的是值,即传值;参数为对象传递的是引用,即传址。

5.listview在数据未满一屏时,setSelection函数不起做用;ListView批量操做时各子项和视图正确对应,可见即所选。

6.setSelection不起做用尝试smoothScroollToPosition. ListView的LastVisiblePosition(最后一个可见项)会随着getView方法执行位置不一样变更而变更。

7.控制Activity的代码量,保持主要逻辑清晰,其它类保持遵照SRP(单一职责),ISP(接口隔离)原则。

8.arraylist执行remove时注意移除int和Integer的区别。

9.Log请打上Tag,调试打印必定要作标记,能定位打印位置,不然尴尬的是:不知道是哪里在打印。

10.代码块/常量/资源能够集中公用的必定公用,即便公用逻辑稍微复杂一点也会值得,修改起来很轻松,修改一种,处处有效。

41.部分华为6.0系统手机闹钟锁屏以及延时的问题总结:

经过调试和现象确认,在华为Mate8,P9上确实会几率性出现一键桌面锁屏后闹钟不响(需唤醒屏幕),以及闹钟延时的问题。 针对这一问题,咱们经过Log初步排查,首先排除是固件问题,经过观察测试demo的状况,排除了APP逻辑问题。 其次,经过debug、log日志排查,排除了APP端问题。

经过以上排除法,以及在小米、魅族、Nexus上运行的现象,最终肯定此问题为华为Android 6.0定制系统所形成的问题,设置 闹钟后,华为Android 6.0定制系统的安全软件以及手机为了保护电量与安全等,会选择性暂停一些服务,其中包括咱们的闹钟服务。

40.Butterknife:8.2.1后运行致使的空指针问题

Butterknife:8.2.1相对于原来的Butterknife:7.1.0来讲,使用起来更方便,效率上也有必定的提高,可是在使用的过程当中要注意: Butterknife:8.2.1以后引用了“android-apt”这个插件,咱们在使用的过程当中也必须引用,不然在调用其注解下的View时会报空指针异常。 解决办法:

一、第一步
buildscript {
    repositories {
    mavenCentral()
}
dependencies {
    classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}
二、第二步
apply plugin: 'android-apt'

android {
 ...
}

dependencies {
    compile 'com.jakewharton:butterknife:8.2.1'
    apt 'com.jakewharton:butterknife-compiler:8.2.1'
}

提示:若是不引用android-apt也能使用,可是会有异常。

39.APP启动闪黑屏的解决办法

在启动APP时,因为Activity须要跑完onCreate和onResume才会显示界面,就会致使闪黑/白屏。即使是把初始化的工做尽可能减小,但因为解析界面仍是须要必定时间,黑屏也仍是会存在。能够经过下面两种方式尽可能减小黑屏的出现:

// 1,设置背景图Theme
<style name="Theme.AppStartLoad" parent="android:Theme">  
    <item name="android:windowBackground">@drawable/bg</item>  
    <item name="android:windowNoTitle">true</item>  
</style>
// 2,设置透明Theme
<style name="Theme.AppStartLoadTranslucent" parent="android:Theme">  
    <item name="android:windowIsTranslucent">true</item> 
    <item name="android:windowNoTitle">true</item>  
</style>

第一种方式的启动快,界面先显示背景图,而后再刷新其余界面控件,给人刷新不一样步感受。 第二种方式给人程序启动慢感受,界面一次性刷出来,刷新同步。

38.WebView关闭后,音乐不停的解法方法

在WebView关闭后,发现音乐还在后台播放,调用“webView.onPause()”也并无什么用。 有效的解决方法,第一种是能够加载一个空白页:

webView.loadUrl("about:blank");

可是下次打开时WebView默认加载的是一个空白页,效果不是很理想,那就调用从新加载页面吧:

webView.reload();

第二种解决方法(在webView关闭以前销毁) :

webView.onDestory();

37.Zxing很难识别扫描到的二维码的问题

在GitHub上下载了一个二维码扫描的Demo,但用来识别本身屏幕上的二维码时发现怎么也识别不出来,可是用其它的二维码扫描工具很快就识别出来了。 最后发现是设置了一个比较低分辨率的图片去解析致使的,将分辨率调高后问题就解决了。

36.关于使用AlarmManager设置闹钟延时的问题。

问题: 部分手机设置闹钟时,存在延时的状况。 问题缘由: 自从Android API 19(也就是Android4.4系统)开始,触发设置的系统闹钟时间是不许确的:能够保证的是闹钟不会提早触发,但有可能会延迟一些时间。Android 操做系统之因此使用这种策略,是由于要批量去唤醒系统闹钟,最大限度地减小唤醒设备的次数,以更有效的节省电量。

也就是说目前Android 系统自己基于一些考虑,对系统闹钟的设置作了一些优化调整。不过Android 4.4系统以前的手机应该不存在此类问题。

解决方案: 代码以下:

if (apiLevel >= 19) {    
    alarmManager.setExact(type, triggerAtMillis, pendingIntent);
} else {
    alarmManager.set(type, triggerAtMillis, pendingIntent);
}

参考官方文档 https://developer.android.com/reference/android/app/AlarmManager.html

35.Android 6月份细节点分享

1.所有Activity可继承BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的简历,万一须要总体变更,一处修改处处有效。

2.数据库表字段常量和SQL逻辑分离,更清晰,建议使用Lite系列框架LiteOrm库,超级清晰且重心能够放在业务上,不用关心数据库细节。

3.全局变量放全局类中,私有模块放在本身的常量清晰且集中。

4.不要相信庞大的管理类的东西会带来什么好处,多是一场灾难,而要时刻注意单一职责原则,一个类专心作好一件事情更为清晰。

5.若是数据没有加载的必要,数据请务必延迟初始化,谨记为用户节省内存,总不会有坏处。

6.异常抛出,在合适的位置处理或者集中处理,不要搞获得处都是catch,混乱且性能低,尽可能不要在循环中捕获异常,以提高性能。

7.地址引用链长时(三个以上指向)当心内存泄漏,和警戒堆栈地址指向,典型的易发事件是:数据更新了,ListView视图却没有刷新,这时Adapter极可能指向的并非你更新的数据容器地址。

8.信息同步:无论是数据库仍是网络操做,新插入的数据注意返回ID(若是没有赋予惟一ID),不然至关于没有同步。

9.多线程操做数据库时,db关闭了会报错,也颇有可能出现互锁的问题,推荐使用事务。

10.作以前先考虑那些能够公用,资源,layout,类,作一个结构、架构分析以加快开发,提高代码的可复用度。

34,LinearGradient水平或垂直渲染

在全部的Demo中看到的LinearGradient 渲染的效果都是从左上渲染到右下,那么要怎样调整渲染角度呢。构造以下:

public LinearGradient (float x0, float y0, float x1, float y1, int[] colors, float[] positions, Shader.TileMode tile);
    水平渲染:x0和x1的值相同 垂直渲染:y0和y1的值相同 其它角度根据调节x、y的值来转变

33,Matrix.setRotate(float degrees, float px, float py)注意

    degrees 旋转的角度 px 旋转的X轴坐标,X为Bitmap的相对坐标 py 旋转的Y轴坐标,Y为Bitmap的相对坐标

例如要以图片的左下角为重心旋转90度,代码为:matrix.setRotate(90, 0, bitamp.getHeight())

32,java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState异常

异常以及其解决方法以下: 1,getSupportFragmentManager().beginTransaction().commit()方法在Activity的onSaveInstanceState()以后调用 解决方法:把commit()方法替换成 commitAllowingStateLoss()

2,getSupportFragmentManager().popBackStackImmediate()方法在Activity的onSaveInstanceState()以后调用 解决方法:延迟处理在Activity的onResume()方法中执行该方法

注:onSaveInstanceState方法执行的时间(与onRestoreInstanceState方法“不必定”是成对的被调用): 一、当用户按下HOME键时。 二、长按HOME键,选择运行其余的程序时。 三、按下电源按键(关闭屏幕显示)时。 四、从activity A中启动一个新的activity时。 五、屏幕方向切换时,例如从竖屏切换到横屏时。

31,百度加固后,运行再小米2S等低版本手机会出现崩溃的问题。

现象:在小米2S中,一旦经过百度加固后,就会出现崩溃。 解决办法:经过逐步排查,发现只有是在Android Studio的项目中才会出现,经过二次排查,发现是在咱们的gradle中配置了 android:debuggable = true 就会致使运行崩溃。但经过资料调研后,发现 android:debuggable = true与百度加密的崩溃并不会有直接关系,经过排除法再次分析,认为问题只可能出如今百度加固的这个过程当中了。联系百度技术人员后,百度人员成功复现,并给出的解释为:

在mi2s上失败的缘由,是由于mi2s集成了Lbe,lbe会在应用启动的时候注入应用进程,它的行为和百度加固的逻辑有冲突 Lbe要获取大家dex里的类,加固事后,他获取的时候,大家的dex里的类尚未被壳加载起来 以前lbe的问题咱们联系了他们,他们不维护了,只能咱们作兼容。

经过一波多折的屡次迭代事后,测试经过。最终肯定问题为百度加固过程当中的不兼容性致使小米2S的手机崩溃。后续若是遇到此类问题,首先须要调试咱们程序中的debuggable;确认不是程序问题后,及时沟通第三方人员。

30,Android6+系统,变声录音异常的解决办法:

一、权限改变

Android 6.0之前安装应用时就会弹出权限对话框给用户,而Android6.0之后再安装或打开应用时并不会弹出权限对话框,而是在你使用到当前功能(这里指的是录音功能时才会弹出)

二、系统再也不支持8bit的编码率

上面已经说了,再低质量语音传输时8bit已经够了,再咱们6.0之前使用8bit编码率对大部分的手机录音已经足矣,这里须要解释一下编码率究竟是啥:

要算一个PCM音频流的码率是一件很轻松的事情,采样率值×采样大小值×声道数bps。一个采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的WAV文件,它的数据速率则为 44.1K×16×2 =1411.2 Kbps。咱们常说128K的MP3,对应的WAV的参数,就是这个1411.2 Kbps,这个参数也被称为数据带宽,它和ADSL中的带宽是一个概念。将码率除以8,就能够获得这个WAV的数据速率,即176.4KB/s。这表示存储一秒钟采样率为44.1KHz,采样大小为16bit,双声道的PCM编码的音频信号,须要176.4KB的空间,1分钟则约为10.34M,这对大部分用户是不可接受的。

因此有不少人为了再带宽上优化,增长采样率确定是不可取的,因此就把16bit改为8bit,而对Andorid 6.0之前的影响并不会很大,可是在6.0之后,你再使用8bit就会出现异常了,这点必定要注意。

具体内容见:android AudioRecord介绍与Android 6.0后的改变

29, Android 5月份细节点总结

    一个View,若是既设了padding,又设了paddingTop,那么只有padding生效,paddingTop是无效的。 在开发下载功能的时候,使用Service和DB是用来在activity死掉后,管理和记录下载状态。 能够把ListView的adapter设置为null,这样就只显示ListView的headView,4.0如下也是没有问题的。 要注意这样的问题:ListView的adapter是经过一个list关联其item的,若是子线程会动态修改这个list(即子线程和adapter引用同一个对象,子线程会修改这个对象的值),在滑动ListView的时候就会有异常抛出。 要十分注意数据库降版本的状况。 ListView若是布局高度不肯定的时候,会计算其或其父控件的高度,因此会形成其getView方法被重复调用的状况。 If an activity is paused or stopped, the system can drop it from memory either by asking it to finish (calling its finish() method), or simply killing its process. 若是ListView没有HeaderView或者FooterView的时候,与ListView相关联的Adapter就是传进来的参数Adapter。若是有,则原来的Adapter将被包装成HeaderViewListAdapter,经过getWrappedAdapter()方法能够获取原来的Adapter。

9.尽可能少使用setBackGround()方法设置背景,因为版本问题会引发运行错误;在activity中经过getWindow().setBackgroundDrawable(null);能够减小一个层级。(getWindow().setBackgroundDrawable()还有另一个用法就是输入法弹下去时背景为黑色,能够经过这个来改成想要的颜色)。

10.如何让EditText不自动获取焦点?在EditText的父Layout中,加入下面的两个属性便可 : android:focusable=”true”,android:focusableInTouchMode=”true”。

28. java float类型比较细节 :

举个例子 27.2 == 272/10.0; 求输出结果 ; 通常人第一眼看到确定以为很简单 , 返回就是true嘛 ; 当告知你答案是false ,你依然不解,急着在编译器上实践,结果发现真的是false ,为何呢?

答案是 : java中直接声明 27.2 默认是为double类型 ; 而272/10.0 返回时一个float类型 ; double == float 天然返回false ; 可换成这个写法 27.2f == 272/10.0 ; 直接声明一个float类型 ;

27.Android-G610手机出现的奇怪适配问题

机名:G610 Androd版本:4.2.2 主屏分辨率:960x540像素

出现的缘由:目前只能是猜想,因为手机和分辨率缘由,致使下面的布局被拥挤,或某属性在此手机内部支持的可能性。若是你们有接触过相似的问题,欢迎指正。

最终的解决办法:更换其余布局,使用适配性更高的写法。

26,RadioGroup调用check(id)方法时,onCheckedChanged(RadioGroup group, int checkedId)方法被执行多

屡次调用常常会干扰到程序的正常逻辑,致使出现奇怪的问题。最初我会放弃RadioGroup的onCheckedChanged()的监听,而改用它的onClick()事件,可是onClick()又会存在屡次点击的问题,依旧不是比较理想的解法。 要想让它只回调一次而不是屡次,正确的作法应该是:RadioButton.setChecked(true); Link

25,大图片裁剪终极解决方案

APP在Android手机上实现拍照截图这一功能,虽然看起来很是简单,可是网上大多只是Demo水准,用在实际项目中问题漏洞百出,常常致使截取照片时程序异常的BUG。 所幸在Google上搜到了一个不错的博客,才完美解决了这个问题。URL:Android大图片裁剪终极解决方案 总结一下最关键的缘由,截大图用URI,小图用Bitmap,网上的Demo几乎都是用的Bitmap,并且并不说起如何使用URI。咱们知道,如今的Android智能手机的摄像头都是几百万的像素,拍出来的图片都是很是大的。所以咱们截图不管大图小图都要统一使用Uri进行操做。 关键代码:

private void cropImageUri(Uri uri, int outputX, int outputY, int requestCode){
    Intent intent = new Intent("com.android.camera.action.CROP");
    intent.setDataAndType(uri, "image/*");
    intent.putExtra("crop", "true");
    intent.putExtra("aspectX", 2);
    intent.putExtra("aspectY", 1);
    intent.putExtra("outputX", outputX);
    intent.putExtra("outputY", outputY);
    intent.putExtra("scale", true);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
    intent.putExtra("return-data", false);
    intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
    intent.putExtra("noFaceDetection", true); // no face detection
    startActivityForResult(intent, requestCode);
}

24.总结如何快速、高效、无错误的修改应用的包名

android若是想修改包名,若是牵扯到Manifest或者自定义控件带命名空间的。总会出现一些错误,好比,包名错乱、包名缺乏、控件和控件交叉在一块儿。实际上是能够避免这样错误的,总结以下:

eclipse: 1.命名空间的书写问题 例如:xmlns:myxmlns=”http://schemas.android.com/apk/res/包名”,xmlns:app=”http://schemas.android.com/apk/res-auto”第一个跟包名有很大关系,若是用第一个每次修改包名后,你要对应的xml里修改命名空间的包名。因此,不建议用第一种。 2.xml结束符 修改包名跟layout里面的控件。例如,

23.布局优化

<include><merge>

22.Activity异常致使的资源回收

在编写代码时将数据放入文件中而不放static变量中,如登陆的用户信息放在Sharepreference中,每次直接从其中取值。若是实在须要将数据放入static变量中,如模块信息,须要在activity的onSaveInstanceState执行保存。这样能够保证在执行内存清理后打开应用还能使用onRestoreInstanceState将数据找回。(OnRestoreInstanceState一旦被调用,其参数是必定有值的)。

21.For语句的使用

#(1)不要在for的第二个条件中调用任何方法.

for (int j = 0; j < element.length; j++)
改成for(int j = 0 , k = element.length; j < k ; j++)

#(2)加强for循环.

可以用于实现了iterable接口的集合类及数组中。在集合类中,迭代器让接口调用hasNext()和next()方法。在ArrayList中,手写的计数循环迭代要快3倍(不管有没有JIT),但其余集合类中,改进的for循环语法和迭代器具备相同的效率。

20.Android 6.0系统注意事项(硬件设备)

根据Android官方文档:Android 6.0设备经过蓝牙和Wi-Fi扫描访问外部硬件设备时,你的应用须要添加ACCESS_FINE_LOCATION或者ACCESS_COARSE_LOCATION权限。

19.radiobutton setChecked(false)后,再setChecked(true)无效,只有先选择其它的radiobutton才会有效。

缘由:只设置了radiobutton的属性,并无设置radiogroup的属性,因此对于radiogroup来讲,它并不知道你的radiobutton已经设置成了false 解决:调用radioGroup.clearCheck() 来清空选择

18.Fragment栈管理。加入进栈,清空栈。

for (int i=0;i<getActivity().getSupportFragmentManager().getBackStackEntryCount();i++)
           getActivity().getSupportFragmentManager().popBackStack();    // 回退栈
     fragManager.beginTransaction()
             .replace(layoutId, fragment)
             .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
             // .addToBackStack(null)   // 是否将改动做添加到回退栈
               .commit();

17.华为手机Intent不能传序列化的Object对象

Service没有在清单文件中配置,在开启该Service时,程序不会报错。

16.Fragment在退出后getActivity()方法返回为空,如在Handler中延迟执行一个事件,在触发以前退出改Fragment,触发时会出错。

15.点击事件变色的Shape

主要是android:state_focused=”true” android:state_pressed=”true”这两个属性,具体参考:http://blog.csdn.net/u010134293/article/details/50161967

14.APP界面图片显示错位或混乱,而资源文件的相关引用肯定没有错误

问题:因为R文件生成错误致使 解决:在发布项目以前Clean Project

13.for循环,ConcurrentModificationException异常。(并发修改)

// 错误写法
for (String item : set) {
    if ("bbbbbbb".equals(item)) {
        set.remove(item);
    }
}
// 正确写法
Iterator iterator = set.iterator();
String item;
while(iterator.hasNext()){
    item = (String) iterator.next();
    if ("bbbbbbb".equals(item)) {
        iterator.remove();
    }
}

12.JNI加载so文件时,报java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader错误,但在armeabi下有这个文件,而且文件名正确。

可能缘由,还有其它的文件夹,如armeabi-v7a、x8六、mips等文件夹,可是该文件夹下没有对应的so文件,能够经过删除其它文件来解决BUG。 参考网址:http://www.it165.net/embed/html/201410/2707.html

11.Apk安装错误:Installation error: INSTALL_FAILED_VERSION_DOWNGRADE

是由于 androidversionCode 的缘由,咱们手机里面的APP 的 versionCode 高于将要安装的 APP! 将 androidversionCode 的版本号改为一个更高的版本。

10.关于自定义控件小米2s的坑总结

在自定义控件的时候有两个方法特别重要,第一个是onMeasure,第二个是onSizeChanged。onMeasure作计算屏幕的工做,可是小米2s,却在这里作了更多的处理。在切换到其余屏幕的时候,会屡次执行onMeasure,切换回原来界面也会屡次执行onMeasure。若是你在这里处理了逻辑问题,极可能会出现不少问题。目前能够把逻辑写入到onSizeChanged里面去。他会在第一次进入界面的时候调用。还有一种就是屏幕发生变化的时候进行调用,好比华为p6,它下面会多出一块操做区域。

9.关于gradle的使用

一、文件开头apply plugin是最新gradle版本的写法,之前的写法是apply plugin: ‘android’, 这里你们注意一下。 二、buildToolsVersion这个须要你本地安装该版本才行,不少人导入新的第三方库,失败的缘由之一是build version的版本不对,这个能够手动更改为你本地已有的版本或者打开 SDK Manager 去下载对应版本。 三、applicationId表明应用的包名,也是最新的写法,这里就不在多说了。 四、android 5.0开始默认安装jdk1.7才能编译,可是因为mac系统自带jdk的版本是1.6,因此须要手动下载jdk1.7并配置下,具体能够见我这篇博客Mac下安装和管理Java 五、minifyEnabled也是最新的语法,很早以前是runProguard,这个也须要更新下。 六、proguardFiles这部分有两段,前一部分表明系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,免去了咱们不少事,这个文件的目录在 sdk目录/tools/proguard/proguard-android.txt , 后一部分是咱们项目里的自定义的混淆文件,目录就在 app/proguard-rules.txt , 若是你用Studio 1.0建立的新项目默认生成的文件名是 proguard-rules.pro , 这个名字不要紧,在这个文件里你能够声明一些第三方依赖的一些混淆规则,因为是开源项目,SnailBulb_Basic_Android里并未进行混淆,具体混淆的语法也不是本篇博客讨论的范围。最终混淆的结果是这两部分文件共同做用的。 具体参考:http://blog.csdn.net/zhanggang740/article/details/49907745

8.关于小米闹钟弹框的坑总结

这个问题是以前作音箱类应用的时候遇到的,功能就是在应用未杀死的状况下,闹钟响时能弹出提示框。后来发现其余的手机均可以弹出,惟独是小米不行。缘由既然是小米把系统的悬浮窗给禁掉了,只有用户手动开打这个权限后才能弹,你们能够注意下这个问题。

7.关于内存溢出的总结

最近已经写了一篇博客对这块进行了总结。 具体参考:http://blog.csdn.net/zhanggang740/article/details/50393466

6.关于在tf卡下接听电话的坑总结

在tf卡下有电话进来会自动切换到a2dp模式,在a2dp模式下不用处理tf的音乐,由于a2dp下调用卡音乐的方法会在来电时自动接听,去电时会自动挂断。

5.解决客户反馈打开应用就闪退的隐形坑

4.不要在Android的Application对象中缓存数据

在咱们App中的不少地方都须要使用到数据信息,它多是一个session token,一次费时计算的结果等等,一般为了不Activity之间传递数据的开销,会将这些数据经过持久化来存储。

有人建议将这些数据放在Application对象中方便全部的Activity访问,这个解决方案简单、优雅而且是……彻底错误的。

你若是你将数据缓存到Application对象中,如何你并未对这个值进行初始化,那么有可能你的程序最终会因为一个NullPointerException异常而崩溃掉。若是你已经对他进行初始化,颇有可能会出如今这个值快速更新的状况下,他会变成你初始化事后的值。

为何会这样?

在上面这个例子中,程序之因此会崩溃掉是由于恢复以后APP的Application对象是全新的,因此缓存在Application中的用户名成员变量为空值,在程序调用String的toUpperCase()方法时因为NullPointerException而崩溃掉。

致使这个问题的主要缘由是:Application对象并非始终在内存中的,它有可能会因为系统内存不足而被杀掉。但Android在你恢复这个应用时并非从新开始启动这个应用,它会建立一个新的Application对象而且启动上次用户离开时的activity以形成这个app历来没有被kill掉得假象。

咱们觉得能够经过Application来缓存数据,却没想到恢复APP时直接跑了B Activity而不是先启动A Activity,最终致使的结果是程序意外的崩溃掉了。

有哪些替代方法可用呢?

一、对于数据缓存问题我也没有比较好的办法,但你能够按照下面其中一种方式来处理:

二、经过Intent在Activity之间来传递数据(可是请别传递大量数据,这有可能致使程序异常或者ANR);

三、使用官方推荐的方法中的一种将数据持久化,存储在磁盘中;

四、在使用数据和句柄的时候作空值检测;

3.四月Android开发细节点总结

    使用ListView时若是用到removeHeaderView,必定要肯定ListView已经使用了setAdapter方法,否则会报NullPointException,addFooterView必须在setAdapter以前才会生效。 使用ListView的时候,布局尽可能使用fill_parent或者写死,若是使用wrap_content,它初始化的时候须要测量,会不断调用adapter的getView方法。 使用ListView时若是要隐藏HeaderView,能够经过removeHeaderView来实现,也能够把headerView设为gone,而后headerView.setPadding(-headerView.height)来实现。 使用ListView时尽可能不使用onItemClick和onItemLongClick,而在adapter的getView中使用onClick和onLongClick。 Activity保存状态信息是应该在onPause时作,而不是onStop时作,觉得可能由于内存紧张,可能不会调用onStop方法就已经被回收。 在自定义一个UI控件的时候,必定要提供一个具备两个参数类型分别为Context和AttributeSet的构造函数,不然的话,该自定义控件就不能够在UI布局文件中使用。 在定义Dialog,调用其dismiss和show方法的时候,必定要注意判断调用该Dialog的activity是否是已经为空或者已经finish了。 单例中若是hold有context,必定要保证这个context是ApplicationContext,由于若是是Activity的context,会影响这个activity的回收。 用SparseArray代替HashMap能提升性能。 当使用.9图作为一个view的background,若是在代码中动态修改了它的background,那么,这个view原先设置的padding将会失效。应先保存去padding值,而后等动态设置完background后再经过setPadding设置padding值。

2.总结Testin中出现的BUG问题

一、对问题进行setBackgrond会致使低版本出现java.lang.NoSuchMethodError问题。 解决此类问题的版本以前已经提示过,可是好像没法完全解决,所以建议你们在项目中不要直接再去使用setBackgrond,所以带来的闪退是用户没法接受的,建议使用setBackgroundDrawablue和setbackgroundResource代替,以此来设备低版本出现的闪退问题。

二、ImageLoader致使出现的运行异常问题 目前对此问题的解决方法是在调用displayImage时进行try{}catch{}进行捕获,至少保证程序不会闪退。

三、Fragment中调用getResource致使的空指针异常 经过分析,出现此异常的缘由多是android生命周期引发的非正常状况,在某些手机上一旦出现Activity还未加载就获取getResource便会致使此类问题出现,解决的办法是延长此Fragment的生命周期,调用ApplicationContext();

四、在加载Log日志的时候,出现的空指针问题 在咱们的程序中,有时候会去打印一些集合或者实例化对象的某些属性,这些属性在某些状况下不作非空判断是会致使空指针出现的,通常咱们会忽略输出Log日志的忘掉非空判断,这里提醒你们,平时必定要注意。

1.Android 上传应用商店时出现ERROR getting 错误

最近出现一个bug,是上传应用商店的时候,部分应用商店会调用aapt工具获取apk信息,在获取信息时会出现错误。

这个错误并不长出现,只有一些国外的解决文章,仍是花了一些时间才解决,这里记录一下了,若是少年们出现了相似的问题也但是试一下下面的解决方案。

首先咱们若是出现上传问题之后能够使用aapt工具检测一下,工具在 sdk build-tools 文件夹下,用 cmd 的方式打开。 命令是 aapt dump badging xx.apk xx为应用名称,意思是获取apk相关信息。当程序出现问题就会出现和应用商店相同的提示信息。 ERROR getting ‘android:name’ attribute: attribute is not a string value 在我接手的项目里面出现这个问题的缘由是,AndroidManiFest 中 activity 的 android:name= 用了@string的模式,这种相关的使用方式致使 aapt 没法识别。 修改方法就是把 @string 中的字符串复制到 android:name 中,而后使用 aapt 工具跑一下就能够解决问题了。若是从新打包的应用上传的应用商店时还出现错误提示,能够尝试刷新页面。

网上有国外的解决方案是吧 AndroidMainFest中全部 @string 都是用硬编码的方式写到文件里,这里其实并不须要的,只要没有提示 ERROR getting ‘android:label’ attribute: attribute is not a string value 或者是其余的相似提示,都只要修改 activity 里 android:name 就能够了。