Android踩坑日记

0、介绍

本篇整理自己在开发过程中遇到的各种坑,以便以后参考。

1、自定义Dialog样式时发现顶部出现一条蓝色横线

//部分手机dialog会出现蓝色横线,因此将它隐藏掉
        Context context = getDialog().getContext();
        int divierId = context.getResources().getIdentifier("android:id/titleDivider", null, null);
        View divider = getDialog().findViewById(divierId);
        if (divider != null) divider.setBackgroundColor(Color.TRANSPARENT);

在show之前将横线隐藏掉

2、 Permission Denial: starting Intent with revoked permission android.permission.CAMERA

崩溃原因:测试机版本>=M,代码中通过ACTION调取摄像机,如果Manifest文件中声明了android.permission.CAMERA权限则会崩溃。


Android踩坑日记_第1张图片
image.png

解决方案:
1、如果项目中没有使用到相机权限则把CAMERA权限删掉。
2、启动该ACTION时先询问相机权限是否已动态声明。

3、getExternalFilesDir(null)可能返回空

getExternalFilesDir(null).getPath() 由于可能返回空报NullPointerException,因此使用时需要加一层trycatch保护

4、升级AS的ndk时出现"No toolchains found in the NDK toolchains folder for ABI with prefix: mips64el-linux-android"

崩溃原因:更新之后少了ndk-bundle下的toolchains少了文件
解决方案:
https://developer.android.com/ndk/downloads/?hl=zh-en
在这里下载稳定的ndk库,下载完之后跟Android/sdk/ndk-bundle/toolchains/下的文件比对,把少了的补充进去。

5、gradle dependency中exclude用法

一般在dependencies下的依赖格式:
groupName:moduleName:版本号
例如:
com.android.support:appcompat-v7:$SUPPORT_LIBRARY_VERSION
查看某个依赖它下面的依赖树,一般类似于:

+--- com.android.support:appcompat-v7:27.1.1
|    +--- com.android.support:support-annotations:27.1.1
|    +--- com.android.support:support-core-utils:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1
|    |         +--- com.android.support:support-annotations:27.1.1
|    |         \--- android.arch.lifecycle:runtime:1.1.0
|    |              +--- android.arch.lifecycle:common:1.1.0
|    |              \--- android.arch.core:common:1.1.0
|    +--- com.android.support:support-fragment:27.1.1
|    |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    +--- com.android.support:support-core-ui:27.1.1
|    |    |    +--- com.android.support:support-annotations:27.1.1
|    |    |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    |    \--- com.android.support:support-core-utils:27.1.1 (*)
|    |    +--- com.android.support:support-core-utils:27.1.1 (*)
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    +--- android.arch.lifecycle:livedata-core:1.1.0
|    |    |    +--- android.arch.lifecycle:common:1.1.0
|    |    |    +--- android.arch.core:common:1.1.0
|    |    |    \--- android.arch.core:runtime:1.1.0
|    |    |         \--- android.arch.core:common:1.1.0
|    |    \--- android.arch.lifecycle:viewmodel:1.1.0
|    +--- com.android.support:support-vector-drawable:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1 (*)
|    \--- com.android.support:animated-vector-drawable:27.1.1
|         +--- com.android.support:support-vector-drawable:27.1.1 (*)
|         \--- com.android.support:support-core-ui:27.1.1 (*)
+--- com.jakewharton:butterknife:8.8.1
|    +--- com.jakewharton:butterknife-annotations:8.8.1
|    |    \--- com.android.support:support-annotations:25.3.0 -> 27.1.1
|    +--- com.android.support:support-annotations:25.3.0 -> 27.1.1
|    \--- com.android.support:support-compat:25.3.0 -> 27.1.1 (*)

exclude的格式为:

    implementation ('com.jakewharton:butterknife:8.8.1') {
        exclude group: 'com.android.support',module:'support-annotations'
    }
规则很简单,移除该依赖下的groupName为"com.android.support",且moduleName为"support-annotations"的依赖

改完之后的依赖树

+--- com.android.support:appcompat-v7:27.1.1
|    +--- com.android.support:support-annotations:27.1.1
|    +--- com.android.support:support-core-utils:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1
|    |         +--- com.android.support:support-annotations:27.1.1
|    |         \--- android.arch.lifecycle:runtime:1.1.0
|    |              +--- android.arch.lifecycle:common:1.1.0
|    |              \--- android.arch.core:common:1.1.0
|    +--- com.android.support:support-fragment:27.1.1
|    |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    +--- com.android.support:support-core-ui:27.1.1
|    |    |    +--- com.android.support:support-annotations:27.1.1
|    |    |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    |    \--- com.android.support:support-core-utils:27.1.1 (*)
|    |    +--- com.android.support:support-core-utils:27.1.1 (*)
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    +--- android.arch.lifecycle:livedata-core:1.1.0
|    |    |    +--- android.arch.lifecycle:common:1.1.0
|    |    |    +--- android.arch.core:common:1.1.0
|    |    |    \--- android.arch.core:runtime:1.1.0
|    |    |         \--- android.arch.core:common:1.1.0
|    |    \--- android.arch.lifecycle:viewmodel:1.1.0
|    +--- com.android.support:support-vector-drawable:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1 (*)
|    \--- com.android.support:animated-vector-drawable:27.1.1
|         +--- com.android.support:support-vector-drawable:27.1.1 (*)
|         \--- com.android.support:support-core-ui:27.1.1 (*)
+--- com.jakewharton:butterknife:8.8.1
|    +--- com.jakewharton:butterknife-annotations:8.8.1
|    \--- com.android.support:support-compat:25.3.0 -> 27.1.1 (*)

同时还支持只指定moduleName或者只指定groupName的情况。

只指定moduleName:

    implementation ('com.jakewharton:butterknife:8.8.1') {
        exclude module:'support-annotations'
    }

这之后的依赖树为:

+--- com.android.support:appcompat-v7:27.1.1
|    +--- com.android.support:support-annotations:27.1.1
|    +--- com.android.support:support-core-utils:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1
|    |         +--- com.android.support:support-annotations:27.1.1
|    |         \--- android.arch.lifecycle:runtime:1.1.0
|    |              +--- android.arch.lifecycle:common:1.1.0
|    |              \--- android.arch.core:common:1.1.0
|    +--- com.android.support:support-fragment:27.1.1
|    |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    +--- com.android.support:support-core-ui:27.1.1
|    |    |    +--- com.android.support:support-annotations:27.1.1
|    |    |    +--- com.android.support:support-compat:27.1.1 (*)
|    |    |    \--- com.android.support:support-core-utils:27.1.1 (*)
|    |    +--- com.android.support:support-core-utils:27.1.1 (*)
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    +--- android.arch.lifecycle:livedata-core:1.1.0
|    |    |    +--- android.arch.lifecycle:common:1.1.0
|    |    |    +--- android.arch.core:common:1.1.0
|    |    |    \--- android.arch.core:runtime:1.1.0
|    |    |         \--- android.arch.core:common:1.1.0
|    |    \--- android.arch.lifecycle:viewmodel:1.1.0
|    +--- com.android.support:support-vector-drawable:27.1.1
|    |    +--- com.android.support:support-annotations:27.1.1
|    |    \--- com.android.support:support-compat:27.1.1 (*)
|    \--- com.android.support:animated-vector-drawable:27.1.1
|         +--- com.android.support:support-vector-drawable:27.1.1 (*)
|         \--- com.android.support:support-core-ui:27.1.1 (*)
+--- com.jakewharton:butterknife:8.8.1
|    +--- com.jakewharton:butterknife-annotations:8.8.1
|    \--- com.android.support:support-compat:25.3.0 -> 27.1.1 (*)

剩余的一种情况就不演示了。

注意:

1、exclude语法在官方包(就是support库这些)的依赖下不奏效,这个不知道什么原因。

6、DialogFragment给Dialog配置onDismissListener()不起作用。

案例

      dialogFragment.getDialog().setOnDismissListener(new DialogInterface.OnDismissListener() {
        @Override
        public void onDismiss(DialogInterface dialogInterface) {
          //TODO
        }
      });

      dialogFragment.show(getFragmentManager(),"");

这种情况下dialog关闭时onDismiss不会调用。
原因
查看DialogFragment的源码发现,DialogFragment里面也有给dialog设置监听器。

   public void onActivityCreated(Bundle var1) {
        super.onActivityCreated(var1);
          ......

            this.mDialog.setCancelable(this.mCancelable);
            this.mDialog.setOnCancelListener(this);
            this.mDialog.setOnDismissListener(this);
            if (var1 != null) {
                Bundle var4 = var1.getBundle("android:savedDialogState");
                if (var4 != null) {
                    this.mDialog.onRestoreInstanceState(var4);
                }
            }

        }
    }

因此如果我们按案例中的方案设置的监听器会被DialogFragment本身覆盖,自然调用不到。

解决方案
自定义DialogFragment,覆盖DialogFragment的onDismiss()方法,添加上自己的逻辑既可。

  @Override
  public void onDismiss(DialogInterface dialogInterface) {
    super.onDismiss(dialogInterface);
    if (onDissmissListener != null) onDissmissListener.onDismiss(dialogInterface);
  }

7、GridView的item有默认点击背景

解决方案:

gridView.setSelector(new ColorDrawable(Color.TRANSPARENT));// 去掉默认点击背景

8、gradle dependecy一直依赖最新版本的依赖


configurations.all {
    resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}

9、Android stroke边线框只画某一边


     
          
               
               
          
     

10、TextView当使用Spannable时不显示省略号的问题

重写TextView,反射修改其中的属性

public class FoldTextView extends AppCompatTextView {
    public FoldTextView (Context context) {
        super(context);
    }

    public FoldTextView (Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FoldTextView (Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        StaticLayout layout = null;
        Field field = null;
        try {
            Field staticField = DynamicLayout.class.getDeclaredField("sStaticLayout");
            staticField.setAccessible(true);
            layout = (StaticLayout) staticField.get(DynamicLayout.class);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        if (layout != null) {
            try {
                field = StaticLayout.class.getDeclaredField("mMaximumVisibleLineCount");
                field.setAccessible(true);
                field.setInt(layout,2);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        super.onMeasure(widthMeasureSpec,heightMeasureSpec);
        if (layout != null && field != null) {
            try {
                field.setInt(layout,Integer.MAX_VALUE);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

11、子module下的资源文件id不是静态常量

原因:
(1)该module编译后的代码中该资源被替换成值
(2)主工程下有同名资源id的话会被替换掉
(3)主工程会重新针对该资源生成一个id
(4)之后就会出现子module中该资源找不到的情况

子module资源id非静态常量可能出现的情况
(1)主工程有相同名称资源时会使用主工程的
(2)子module下由于资源id非静态常量,没办法使用switch-case
(3)子module下没法直接使用ButterKnife

12、当同个布局下出现两个同名id控件的情况

出现情况:Fragment包含ViewPager,ViewPager又包含Fragment,此时父Fragment和子Fragment拥有同id控件,父Fragment通过findViewById()找到的不一定是父Fragment下的控件,因为它会返回第一个找到的控件

13、Fragment中调用startActivityForResult

(1)getActivity().startActivityForResult(),只有父Aty的onActivityResult被调用,Fragment的不被调用
(2)startActivityForResult(),当前Fragment和父Activity的onActivityResult被调用
()getParentFragment().startAcitivtyForResult(),父Fragment和父Activity的onActivityResult被调用

14、latest.release指向非最新版本号

与第三方联调时候会发现当第三方第一时间更新了maven依赖时通过latest.release没有把最新版本的依赖拉下来,拉的是之前的版本。这个时候手动改版本号就可解决。
如果找得到原因的话,这里补充

15、Dialog初始化Context误区

因为最近有个需求是需要计时后弹出Dialog,此时如果用户的app在后台且计时到了需要弹窗,如果Activity被回收了,出现了crash

android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@ce0817e is not valid; is your activity running?

原因
Dialog可以传入Context初始化,但Dialog的展示需要依附Activity,换言之就是show()时候需要判断Activity是否存活
解决方案:
初始化时Context尽量传入为Activity

if(!activity.isFinishing()) dialog.show()

你可能感兴趣的:(Android踩坑日记)