技巧1:tools:node=”remove”
-
WorkManager 初始化是这样的
1 2 3 4 5 6 7 8 9 10 11 12
WorkManager.initialize(context,configuration) public static void initialize(Context context, Configuration configuration) { synchronized (sLock) { if (sDelegatedInstance != null && sDefaultInstance != null) { throw new IllegalStateException("WorkManager is already initialized. Did you " + "try to initialize it manually without disabling " + "WorkManagerInitializer? See " + "WorkManager#initialize(Context, Configuration) or the class level" + "Javadoc for more information."); } ...
这里可以看到,WorkManager是不能被重复初始化的
-
那么有没有对 AndroidManifest.xml 中的这段代码存在疑惑?
1 2 3 4 5 6 7 8 9
<provider android:name="androidx.work.impl.WorkManagerInitializer" android:authorities="${applicationId}.workmanager-init" android:directBootAware="false" android:exported="false" android:multiprocess="true" tools:node="remove" tools:targetApi="n" />
1 2 3 4 5 6 7 8
public class WorkManagerInitializer extends ContentProvider { @Override public boolean onCreate() { // Initialize WorkManager with the default configuration. WorkManager.initialize(getContext(), new Configuration.Builder().build()); return true; } ...
说到底,这个 provider 也是执行初始化作用的,那么在 AndroidManifest.xml 中写这个 provider 不是重复初始化了么?
-
这里的秘诀在于 tools:node=”remove” 添加这个标签意味着将不会出现在 Merged Menifest 中,拓展一下,这个方法可以删除第三方SDK中申明的权限,比如
1
<uses-permission android:name="android.permission.INTERNET" tools:node="remove"/>
-
参考自
技巧2:开发第三方类库自己初始化
- 知识普及:ContentProvider 是在 Application 之前就去初始化的。
- 能干啥事:利用这点可以干很多事,尤其是 SDK 开发,很多时候都要在文档中要求开发者在 Application 初始化,这时候完全可以定义一个 ContentProvider 自己去初始化,对接入的开发者无感了。
- 有攻就有防:对付它就用上面的 技巧1。
技巧3:Message.obtain()
-
使用
Message.obtain()
来复用 Message 对象。 -
简单源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
public final class Message implements Parcelable { Message next; private static Message sPool; public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); } //回收Message public void recycle() { ... } }
技巧4: Tint 着色器
为 ImageView 添加属性andorid:tint="@color/colorAccent"
即可改变 ImageView 上图片的显示颜色。
技巧5: 复用图片
-
一张图片明明旋转下就满足要求了,就不要再创建另一张了:
1 2 3 4 5
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@mipmap/ic_launcher" android:fromDegrees="90" android:toDegrees="90" />
技巧6: 移除无用 String
-
appcompat-v7
等三方库中包含大量的国际化资源,可以选择性的移除掉:1 2 3 4
defaultConfig { ... resConfigs('zh-rCN') }
技巧7: Android 系统是如何安装 so 文件的?
-
查看手机支持的架构:
1 2
✗ adb shell getprop ro.product.cpu.abilist ➜ arm64-v8a,armeabi-v7a,armeabi
-
APK 在安装的时候,会按照上面的顺序查看 apk 中是否有对应的文件夹,找到的话就将该文件夹下的所有 so 文件拷贝到 /data/app/packageName/lib/ 目录下,然后马上就停止查找了。
技巧8: 减少冷启动
-
用户点击返回键,默认就退出应用了,下次再点击的时候就是冷启动。
-
在用户点返回的时候,使应用进入后台,而不是退出应用:
1 2 3 4
@Override public void onBackPressed(){ moveTaskToBack(true); }
技巧9:如何获得 bitmap 在内存中的大小
-
系统方法:
1 2 3
public final int getByteCount() { return getRowBytes() * getHeight(); }
技巧10:FragmentTransaction.commit 的正确姿势
- 不要随意使用
FragmentTransaction.commitAllowingStateLoss()
来代替。 - 推荐在
onPostResume()
,onResumeFragment()
或onCreate()
中调用 commit。
技巧11:绕过系统反射限制
-
Native hook 住 ShouldDenyAccessToMember 方法,直接返回 false
-
破坏调用堆栈绕过去,使 VM 无法识别调用方:通过 JniEnv::AttachCurrentThread(…) 函数创建一个新的 Thread 来完成,
Jni层新建个线程,在这个线程里去反射,去除掉了java调用的信息,从而让安卓系统以为这个是系统调用
-
参考