Android 平台应用使用RxAndroid

前提: 需要已经在Android Studio中使用过RxAndroid,以便我们可以提取其下载下来的RxAndroid库。


找到库文件

在用户目录的子路径中找到RxAndroid和RxJava(RxAndroid依赖RxJava)的库文件(aar或者jar)。路径一般如下,请根据自己的RxAndroid版本号自行替换路径中某些值。

RxAndroid:

主目录/.gradle/caches/modules-2/files-2.1/io.reactivex/rxandroid/1.0.0/9d4f880d8a3111646977ed77d00a9fd19279225/rxandroid-1.0.0.aar

RxJava:

主目录/.gradle/caches/modules-2/files-2.1/io.reactivex/rxjava/1.0.13/b8668706414b5936d38c8a9e4c2be16e3c999c62/rxjava-1.0.13.jar

注意不要找到rxjava-1.0.13-sources.jar这个源码jar包了。

提取jar文件

提取你jar库文件到你需要的模块下,可以建个libs文件夹存放,比如packages/apps/Launcher3/libs。

rxjava-1.0.13.jar: 纯粹的jar包,自然是不用说,可以直接放在libs下。
rxandroid-1.0.0.aar: aar格式其实是专门为Android制作的压缩包结构,主要针对Android库有时需要声明资源类型因而将其打包成这样的格式。压缩包结构如下:
这里写图片描述

但RxAndroid这个aar库中并不包含资源,只是在AndroidManifest文件中声明了个包名而已。因此我们直接提取其中的classes.jar文件出来作为依赖jar包放在libs下,同时可以将classes.jar重命名成比如我当前RxAndroid版本的rxandroid-1.0.0.jar

在Android.mk文件中声明编译依赖的jar文件

我添加的声明如下:

...
LOCAL_STATIC_JAVA_LIBRARIES += rxjava rxandroid
...
include $(BUILD_PACKAGE)

####################################
include $(CLEAR_VARS)
LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := rxjava:libs/rxjava-1.0.13.jar \
                                        rxandroid:libs/rxandroid-1.0.0.jar
include $(BUILD_MULTI_PREBUILT)
#######################################

其中主要是使用LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES预编译静态java库,并且使用LOCAL_STATIC_JAVA_LIBRARIES使用编译出的库。

更详细的如何在mk文件添加jar包依赖的方法请自行百度。

接着mmm编译成功, 但是 …

将生成的APK安装到手机上,一运行发现挂了,如下异常:

05-16 16:36:50.666  6540  6540 D AndroidRuntime: Shutting down VM
05-16 16:36:50.668  6540  6540 E AndroidRuntime: FATAL EXCEPTION: main
05-16 16:36:50.668  6540  6540 E AndroidRuntime: Process: com.example.ningxiang.appcategory, PID: 6540
05-16 16:36:50.668  6540  6540 E AndroidRuntime: java.lang.ExceptionInInitializerError
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at rx.internal.schedulers.EventLoopsScheduler.<clinit>(EventLoopsScheduler.java:28)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at rx.schedulers.Schedulers.<init>(Schedulers.java:40)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at rx.schedulers.Schedulers.<clinit>(Schedulers.java:33)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at rx.schedulers.Schedulers.io(Schedulers.java:117)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at com.example.ningxiang.appcategory.Main2Activity.onCreate(Main2Activity.java:23)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.Activity.performCreate(Activity.java:6666)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2762)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2874)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.ActivityThread.-wrap12(ActivityThread.java)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1612)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:110)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:203)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:6336)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1066)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:927)
05-16 16:36:50.668  6540  6540 E AndroidRuntime: Caused by: java.lang.RuntimeException: java.lang.NoSuchFieldException: No field counter in class Lrx/internal/util/RxThreadFactory; (declaration of 'rx.internal.util.RxThreadFactory' appears in base.apk)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at java.util.concurrent.atomic.AtomicLongFieldUpdater$CASUpdater.<init>(AtomicLongFieldUpdater.java:373)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at java.util.concurrent.atomic.AtomicLongFieldUpdater.newUpdater(AtomicLongFieldUpdater.java:60)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at rx.internal.util.RxThreadFactory.<clinit>(RxThreadFactory.java:24)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    ... 17 more
05-16 16:36:50.668  6540  6540 E AndroidRuntime: Caused by: java.lang.NoSuchFieldException: No field counter in class Lrx/internal/util/RxThreadFactory; (declaration of 'rx.internal.util.RxThreadFactory' appears in base.apk)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at java.lang.Class.getDeclaredField(Native Method)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    at java.util.concurrent.atomic.AtomicLongFieldUpdater$CASUpdater.<init>(AtomicLongFieldUpdater.java:356)
05-16 16:36:50.668  6540  6540 E AndroidRuntime:    ... 19 more

原因是:
Caused by: java.lang.RuntimeException: java.lang.NoSuchFieldException: No field counter in class Lrx/internal/util/RxThreadFactory; (declaration of ‘rx.internal.util.RxThreadFactory’ appears in base.apk)

说是在rx/internal/util/RxThreadFactory类中找不到counter这个字段,于是查看源码,发现counter是存在的,但在整个库中没有直接引用过,而是通过反射使用的。同时查看生成APK中解出来的smali文件确实找不到counter字段。
因此猜测是在编译期优化时被优化掉了。

找大神询问,得知是proguard混淆时优化的,解决方案是禁用混淆或者配置混淆规则,使编译时略过对该库的优化。

使用方法分别如下:
1. 禁用proguard
在Android.mk中添加一行内容:LOCAL_PROGUARD_ENABLED := disabled
如此,便禁用了整个模块的混淆优化。(有点粗暴~)

2. 编辑混淆规则使之忽略RxAndroid和RxJava
2.1 模块下新建文本文件proguard.flags(名字其实可以自定义的哈)
2.2 在proguard.flags中填入内容:-keep class rx.** {*;}
如此可对rx包下的所有类进行排除混淆优化(更多proguard规则配置请自行百度)
2.3 在Android.mk中添加一行:LOCAL_PROGUARD_FLAG_FILES := proguard.flags
这样就将我们编辑的混淆规则引入到编译系统中了。

编译,运行,成功

阅读更多
换一批

没有更多推荐了,返回首页