填坑之旅--零散知识点

361 阅读6分钟

开发中总会遇到形形色色的小问题,猝不及防的就被射弯了膝盖🤣🤣🤣

特此整理记录,遇到的点滴,不定期更新,都是泪啊😂

1、SSLHandshakeException

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found

解决方法检查手机的时间是不是准确的 , 调整手机系统时间跟当前网络时间保持一致,再次刷新尝试。

2、gradle依赖加载失败问题

  • gradle版本gradle插件版本并不是一一对应的
  • 加载插件失败,可以尝试替换仓库:
google()
maven {
     url 'https://maven.google.com/'
     name 'Google'

 }

3、recyclerview 内容超过一屏时,findFistCompletelyVisibleItemPosition 会返回 -1 的原因

  • 原因是在 findOneVisibleChild 计算出来的 start 和 end 已经超过了 reclclerview 的 start 和 end.经过研究源码得到以下。
findFirstCompletelyVisibleItemPosition -> -1

findLastCompletelyVisibleItemPosition -> -1

findFirstVisibleItemPosition -> 正常

4、混淆打包后,插件中某个混淆路径和主工程完全相同问题

混淆配置中添加 -flattenpackagehierarchy '指定文件夹名称' 让对应的Classe文件放到指定文件下,避免冲突

5、解决5.0以上Button自带阴影效果的方案

在xml定义的Button中,添加以下样式定义

style="?android:attr/borderlessButtonStyle"

6、针对 onSingleTapUp 和 onSIngleTapConfirmed 的使用区别

前者在按下并抬起时发生,后者有一个附加条件时Android会确保点击之后在短时间内没有再次点击才会触发。常用于如果需要监听单击和双击事件。

7、如何理解 Intent 传递数据出现 TransactionTooLargeException的问题

Intent 传输数据的机制中,用到了 Binder。Intent 中的数据,会作为 Parcel 被存储在 Binder 的事务缓冲区(Binder transaction buffer)中的对象进行传输.而这个 Binder 事务缓冲区具有一个有限的固定大小,当前为 1MB。这里的 1MB 空间并不是当前操作独享的,而是由当前进程所共享。也就是说 Intent 在 Activity 间传输数据,本身也不适合传递太大的数据.

更好的解释 Android 开发太难了,这异常竟然捕获不到?

8、如何解决华为设备产生太多 broadcast 导致crash的问题

部分华为中,如果app注册超过500个BroadcastReceiver就会抛出 “ Register too many Broadcast Receivers ” 异常。通过分析发现其内部有一个白名单,自己可以通过创建一个新的app,使用微信包名进行测试,发现并没有这个限制。通过反射 LoadedApk 类拿到 mReceiverResource 中的 mWhiteList 对象添加我们的包名就可以了

LoadedApkHuaWei

9、Dalvik 分包构建每一个 dex 文件时可能出现 java.lang.NoClassDefFoundError

这个问题的原因是构建工具绘制行比较复杂决策来确定主 dex 文件中需要的类以便应用能够正常的启动。如果启动期间需要的任何类在主 dex 中未能找到,则会抛出上述异常。所有必须要 multiDexKeepFile 或 multiDexKeepProguard 属性中声明他们,手动将这些类指定为主 dex 文件中的必需项。

创建 multidex-new.txt文件,写入以下新增的类

com/example/Main2.class

com/example/Main3.class

创建 meltidex-new.pro,写入以下 keep 住的类

-keep class com.example.Main2

-keep class com.example.Main3

然后在gradle multiDexKeepFile属性 和 multiDexKeepProguard属性声明上述文件

android {

buildTypes {

    release {

        multiDexKeepFile file 'multidex-new.txt'

        multiDexKeepProguard 'multidex-new.pro'

        ...

    }

}

10、构建一个圆角图片

圆角图片实现

11、运行时注解与编译时注解的区别是什么呢?

a)保留阶段不同。运行时注解保留到运行时,可在运行时访问。而编译时注解保留到编译时,运行时无法访问。

b)原理不同。运行时注解是Java反射机制,Retrofit运行时注解,需要用的时候才用到,而编译时注解通过APT、AbstractProcessor

c)性能不同。运行时注解由于使用Java反射,因此对性能上有影响。编译时注解对性能没影响。这也是为什么ButterKnife从运行时切换到了编译时的原因。

d)产物不同。运行时注解只需自定义注解处理器即可,不会产生其他文件。而编译时注解通常会产生新的Java源文件

12、魅族安装apk失败问题

  1.打开手机-->设置,进入设置界面,找到指纹和安全,点击进入;
  2.进入指纹和安全界面,打开访客模式,如果已经开启访客模式直
    接点击进入;
  3.进入访客模式界面。
    如果有“清除数据”选项,直接点击清楚访客数据;
    如果没有“清楚数据”的选项,直接锁屏,然后输入访客密码,进
    入访客模式,删除里面对应的APP,锁屏,然后再输入手机密
    码(不是访客密码,是你手机解锁密码)重新进入手机安装apk。

13、关于RecyclerView中包含Edittext的问题的几种解决方法

RecyclerView中包含Edittext的问题的几种解决方法

14、HTTPS如何实现自签名SSL证书

Android HTTPS如何10分钟实现自签名SSL证书

15、InputManagerService异常DeadObjectException

mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);  

 这一行代码怎么看也不会有问题,但是仔细查看以下相关文档的说明发现有:(gjhappyyy.iteye.com/blog/129872…)

OpenGl ES关于渲染方式有以下两种:

RENDERMODE_CONTINUOUSLY
RENDERMODE_WHEN_DIRTY

默认渲染方式为RENDERMODE_CONTINUOUSLY,这两种渲染的含义是:

RENDERMODE_CONTINUOUSLY:渲染器会不停地渲染场景,

RENDERMODE_WHEN_DIRTY:只有在创建和调用requestRender()时才会刷新。

一般设置为RENDERMODE_WHEN_DIRTY方式,这样不会让CPU一直处于高速运转状态,提高手机电池使用时间和软件整体性能。  

也就是说activity页面在开着的时候,即使不做任何操作,手机的CPU等资源也是处于高速运转的状态,意味着有可能会耗掉其他app所需要的资源,从而触发其他应用导致InputManagerService的异常信息。

16、安卓6.0~9.0适配

安卓6.0~9.0适配

17、避坑!!webview如何加载pdf

避坑!!webview如何加载pdf

18、dialog的context问题

dialog.getContext()不一定能拿到创建时传入的context:

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
    if (createContextThemeWrapper) {
        if (themeResId == ResourceId.ID_NULL) {
            final TypedValue outValue = new TypedValue();
            context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
            themeResId = outValue.resourceId;
        }
        //这里创建了一个ContextWrapper
        mContext = new ContextThemeWrapper(context, themeResId);
    } else {
        mContext = context;
    }

    mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

    final Window w = new PhoneWindow(mContext);
    mWindow = w;
    w.setCallback(this);
    w.setOnWindowDismissedCallback(this);
    w.setOnWindowSwipeDismissedCallback(() -> {
        if (mCancelable) {
            cancel();
        }
    });
    w.setWindowManager(mWindowManager, null, null);
    w.setGravity(Gravity.CENTER);

    mListenersHandler = new ListenersHandler(this);
}

19. Arrays.asList后往里add数据会报错

通常使用的ArrayListjava.util.ArrayList这个包下,实现了List接口

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
public void add(int index, E element) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}

image.png Arrays.asList生成的ArrayList在java.util.Arrays包里面的,而这里面的ArrayList并没有去实现List接口,所以也就没有add,get等方法,另外在kotlin里面,我们会看到一个细节,当你敲完Arrays.asList的时候,编译器会提示你,可以转换成listof函数,而这个还是我们知道生成的list都是只能读取,不能往里写数据

20.Thread.sleep(0)到底“睡没睡”

在Android操作系统中,每个线程使用cpu资源都是有优先级的,优先级高的才有资格使用,而操作系统则是在一个线程释放cpu资源以后,重新计算所有线程的优先级来重新分配cpu资源,所以sleep真正的意义不是暂停,而是在接下去的时间内不参与cpu的竞争,等到cpu重新分配完资源以后,如果优先级没变,那么继续执行,所以sleep(0)秒的真正含义是触发cpu资源重新分配