提交 c80b6a10 编写于 作者: B Blankj

see 07/15 log

上级 25119457
* `19/07/10` [upd] Bus plugin for use BusUtils. Publish bus plugin v2.0.
* `19/07/10` [add] Api plugin for use ApiUtils. Publish api plugin v1.0.
* `19/07/09` [upd] The frame of project.
* `19/07/06` [upd] BusUtils which behave same as EventBus.
* `19/07/03` [add] ApiUtils which decoupling modules.
* `19/06/30` [add] LanguageUtils support activity's class name. Publish v1.24.7.
* `19/06/29` [add] ClickUtils#OnMultiClickListener, and remove dangerous function. Publish v1.24.6.
* `19/06/28` [add] LanguageUtils. Publish v1.24.5.
......
......@@ -99,6 +99,7 @@ class Config {
glide : new DepConfig("com.github.bumptech.glide:glide:4.7.1"),
retrofit : new DepConfig("com.squareup.retrofit2:retrofit:2.4.0"),
commons_io : new DepConfig("commons-io:commons-io:2.6"),
eventbus : new DepConfig("org.greenrobot:eventbus:3.1.1"),
test : [
junit : new DepConfig("junit:junit:4.12"),
......
......@@ -164,14 +164,14 @@ class ConfigUtils {
}
})
StringBuilder sb = new StringBuilder()
taskInfoList.each {
sb.append(String.format("%7sms %s\n", it.exeDuration, it.task.path))
}
int buildSec = (System.currentTimeMillis() - startBuildMillis) / 1000;
int m = buildSec / 60;
int s = buildSec % 60;
def timeInfo = (m == 0 ? "${s}s" : "${m}m ${s}s")
def timeInfo = (m == 0 ? "${s}s" : "${m}m ${s}s (${buildSec}s)")
sb.append("BUILD FINISHED in $timeInfo")
taskInfoList.each {
sb.append(String.format("%7sms %s\n", it.exeDuration, it.task.path))
}
def content = sb.toString()
GLog.l(content)
File file = new File(result.gradle.rootProject.buildDir.getAbsolutePath(),
......
apply plugin: 'kotlin-kapt'
dependencies {
kapt 'org.greenrobot:eventbus-annotation-processor:3.0.1'
}
\ No newline at end of file
......@@ -89,6 +89,10 @@
android:name=".feature.bus.BusActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop" />
<activity
android:name=".feature.bus.BusCompareActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:launchMode="singleTop" />
<activity
android:name=".feature.clean.CleanActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
......
......@@ -66,7 +66,8 @@ class BusActivity : CommonTitleActivity() {
busPost,
busPostSticky,
busPost2IoThread,
busRemoveSticky
busRemoveSticky,
busStartCompare
)
}
......@@ -99,6 +100,9 @@ class BusActivity : CommonTitleActivity() {
R.id.busRemoveSticky -> {
BusUtils.removeSticky(TAG_STICKY_BUS)
}
R.id.busStartCompare -> {
BusCompareActivity.start(this)
}
}
}
......
package com.blankj.utilcode.pkg.feature.bus
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.View
import com.blankj.lib.common.CommonTaskActivity
import com.blankj.utilcode.pkg.R
import com.blankj.utilcode.util.BusUtils
import com.blankj.utilcode.util.ThreadUtils
import kotlinx.android.synthetic.main.activity_busutils_vs_eventbus.*
import org.greenrobot.eventbus.EventBus
import java.util.*
/**
* ```
* author: Blankj
* blog : http://blankj.com
* time : 2019/07/14
* desc : demo about BusUtils
* ```
*/
class BusCompareActivity : CommonTaskActivity<Unit>() {
override fun doInBackground() {
}
override fun runOnUiThread(data: Unit?) {
}
companion object {
fun start(context: Context) {
val starter = Intent(context, BusCompareActivity::class.java)
context.startActivity(starter)
}
}
override fun bindTitle(): CharSequence {
return getString(R.string.demo_bus)
}
override fun initData(bundle: Bundle?) {}
override fun bindLayout(): Int {
return R.layout.activity_busutils_vs_eventbus
}
override fun initView(savedInstanceState: Bundle?, contentView: View?) {
applyDebouncingClickListener(
busCompareRegister10000TimesBtn,
busComparePostTo1Subscriber1000000TimesBtn,
busComparePostTo100Subscribers100000TimesBtn,
busCompareUnregister10000TimesBtn
)
}
override fun doBusiness() {
}
override fun onDebouncingClick(view: View) {
when (view.id) {
R.id.busCompareRegister10000TimesBtn -> {
compareRegister10000Times()
}
R.id.busComparePostTo1Subscriber1000000TimesBtn -> {
comparePostTo1Subscriber1000000Times()
}
R.id.busComparePostTo100Subscribers100000TimesBtn -> {
comparePostTo100Subscribers100000Times()
}
R.id.busCompareUnregister10000TimesBtn -> {
compareUnregister10000Times()
}
}
}
override fun onDestroy() {
super.onDestroy()
ThreadUtils.cancel(ThreadUtils.getCpuPool())
}
/**
* 注册 10000 个订阅者,共执行 10 次取平均值
*/
private fun compareRegister10000Times() {
val eventBusTests = java.util.ArrayList<BusEvent>()
val busUtilsTests = java.util.ArrayList<BusEvent>()
compareWithEventBus("Register 10000 times.", 10, 10000, object : CompareCallback {
override fun runEventBus() {
val test = BusEvent()
EventBus.getDefault().register(test)
eventBusTests.add(test)
}
override fun runBusUtils() {
val test = BusEvent()
BusUtils.register(test)
busUtilsTests.add(test)
}
override fun restState() {
for (test in eventBusTests) {
EventBus.getDefault().unregister(test)
}
eventBusTests.clear()
for (test in busUtilsTests) {
BusUtils.unregister(test)
}
busUtilsTests.clear()
}
}, object : OnFinishCallback {
override fun onFinish() {
}
})
}
/**
* 向 1 个订阅者发送 * 1000000 次,共执行 10 次取平均值
*/
private fun comparePostTo1Subscriber1000000Times() {
comparePostTemplate("Post to 1 subscriber 1000000 times.", 1, 1000000)
}
/**
* 向 100 个订阅者发送 * 100000 次,共执行 10 次取平均值
*/
private fun comparePostTo100Subscribers100000Times() {
comparePostTemplate("Post to 100 subscribers 100000 times.", 100, 100000)
}
private fun comparePostTemplate(name: String, subscribeNum: Int, postTimes: Int) {
val tests = java.util.ArrayList<BusEvent>()
for (i in 0 until subscribeNum) {
val test = BusEvent()
EventBus.getDefault().register(test)
BusUtils.register(test)
tests.add(test)
}
compareWithEventBus(name, 10, postTimes, object : CompareCallback {
override fun runEventBus() {
EventBus.getDefault().post("EventBus")
}
override fun runBusUtils() {
BusUtils.post("busUtilsFun", "BusUtils")
}
override fun restState() {
}
}, object : OnFinishCallback {
override fun onFinish() {
for (test in tests) {
EventBus.getDefault().unregister(test)
BusUtils.unregister(test)
}
}
})
}
/**
* 注销 10000 个订阅者,共执行 10 次取平均值
*/
private fun compareUnregister10000Times() {
val tests = ArrayList<BusEvent>()
for (i in 0..9999) {
val test = BusEvent()
EventBus.getDefault().register(test)
BusUtils.register(test)
tests.add(test)
}
compareWithEventBus("Unregister 10000 times.", 10, 1, object : CompareCallback {
override fun runEventBus() {
for (test in tests) {
EventBus.getDefault().unregister(test)
}
}
override fun runBusUtils() {
for (test in tests) {
BusUtils.unregister(test)
}
}
override fun restState() {
for (test in tests) {
EventBus.getDefault().register(test)
BusUtils.register(test)
}
}
}, object : OnFinishCallback {
override fun onFinish() {
for (test in tests) {
EventBus.getDefault().unregister(test)
BusUtils.unregister(test)
}
}
})
}
/**
* @param name 传入的测试函数名
* @param sampleSize 样本数
* @param times 每次执行的次数
* @param callback 比较的回调函数
* @param onFinishCallback 执行结束的回调
*/
private fun compareWithEventBus(name: String, sampleSize: Int, times: Int,
callback: CompareCallback, onFinishCallback: OnFinishCallback) {
setLoadingVisibility(true)
setBtnEnabled(false)
ThreadUtils.executeByCpu(object : ThreadUtils.Task<String>() {
override fun doInBackground(): String {
val dur = Array(2) { LongArray(sampleSize) }
for (i in 0 until sampleSize) {
var cur = System.currentTimeMillis()
for (j in 0 until times) {
callback.runEventBus()
}
dur[0][i] = System.currentTimeMillis() - cur
cur = System.currentTimeMillis()
for (j in 0 until times) {
callback.runBusUtils()
}
dur[1][i] = System.currentTimeMillis() - cur
callback.restState()
}
var eventBusAverageTime: Long = 0
var busUtilsAverageTime: Long = 0
for (i in 0 until sampleSize) {
eventBusAverageTime += dur[0][i]
busUtilsAverageTime += dur[1][i]
}
return name +
"\nEventBusCostTime: " + eventBusAverageTime / sampleSize +
"\nBusUtilsCostTime: " + busUtilsAverageTime / sampleSize;
}
override fun onSuccess(result: String?) {
onFinishCallback.onFinish()
setBtnEnabled(true)
setLoadingVisibility(false)
this@BusCompareActivity.busCompareAboutTv.text = result
}
override fun onCancel() {
onFinishCallback.onFinish()
setLoadingVisibility(false)
setBtnEnabled(true)
}
override fun onFail(t: Throwable?) {
onFinishCallback.onFinish()
setLoadingVisibility(false)
setBtnEnabled(true)
}
})
}
private fun setBtnEnabled(enable: Boolean) {
busCompareRegister10000TimesBtn.isEnabled = enable
busComparePostTo1Subscriber1000000TimesBtn.isEnabled = enable
busCompareUnregister10000TimesBtn.isEnabled = enable
}
interface CompareCallback {
fun runEventBus()
fun runBusUtils()
fun restState()
}
interface OnFinishCallback {
fun onFinish()
}
}
package com.blankj.utilcode.pkg.feature.bus
import com.blankj.utilcode.util.BusUtils
import org.greenrobot.eventbus.Subscribe
/**
* ```
* author: Blankj
* blog : http://blankj.com
* time : 2019/07/14
* desc : demo about BusUtils
* ```
*/
class BusEvent {
@Subscribe
fun eventBusFun(param: String) {
}
@BusUtils.Bus(tag = "busUtilsFun")
fun busUtilsFun(param: String) {
}
}
\ No newline at end of file
......@@ -54,5 +54,12 @@
android:layout_height="wrap_content"
android:text="@string/bus_remove_sticky" />
<Button
android:id="@+id/busStartCompare"
style="@style/WideBtnStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bus_start_compare" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="@dimen/spacing_16">
<TextView
android:id="@+id/busCompareAboutTv"
style="@style/TextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/busCompareRegister10000TimesBtn"
style="@style/WideBtnStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bus_compare_register_10000_times" />
<Button
android:id="@+id/busComparePostTo1Subscriber1000000TimesBtn"
style="@style/WideBtnStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bus_compare_post_to_1_subscriber_1000000_times" />
<Button
android:id="@+id/busComparePostTo100Subscribers100000TimesBtn"
style="@style/WideBtnStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bus_compare_post_to_100_subscriber_100000_times" />
<Button
android:id="@+id/busCompareUnregister10000TimesBtn"
style="@style/WideBtnStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/bus_compare_unregister_10000_times" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="demo_activity">ActivityUtils Demo</string>
<string name="demo_adapt_screen">AdaptScreenUtils Demo</string>
<string name="demo_api">ApiUtils Demo</string>
......@@ -143,6 +143,11 @@
<string name="bus_post_sticky">Post Sticky</string>
<string name="bus_post_to_io_thread">Post To IO Thread</string>
<string name="bus_remove_sticky">Remove Sticky</string>
<string name="bus_start_compare">Start BusUtils Vs EventBus</string>
<string name="bus_compare_register_10000_times">Compare Register 10000 Times</string>
<string name="bus_compare_post_to_1_subscriber_1000000_times">Compare Post To 1 Subscriber 1000000 Times</string>
<string name="bus_compare_post_to_100_subscriber_100000_times">Compare Post To 100 Subscribers 100000 Times</string>
<string name="bus_compare_unregister_10000_times">Compare Unregister 10000 Times</string>
<!-- Flashlight相关 -->
<string name="flashlight_status">Flashlight Status</string>
......
......@@ -10,5 +10,6 @@ dependencies {
api Config.depConfig.kotlin.dep
api Config.depConfig.free_proguard.dep
api Config.depConfig.swipe_panel.dep
api Config.depConfig.eventbus.dep
compileOnly Config.depConfig.leakcanary.android_no_op.dep
}
\ No newline at end of file
......@@ -45,7 +45,7 @@ public abstract class CommonTaskActivity<T> extends CommonTitleActivity {
ThreadUtils.executeByIo(bgTask);
}
void setLoadingVisibility(boolean isVisible) {
public void setLoadingVisibility(boolean isVisible) {
if (loadingView == null) {
loadingView = new ProgressBar(this, null, android.R.attr.progressBarStyle);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
......
......@@ -20,5 +20,5 @@ dependencies {
testImplementation Config.depConfig.test.junit.dep
testImplementation Config.depConfig.test.robolectric.dep
testImplementation Config.depConfig.support.appcompat_v7.dep
testImplementation Config.depConfig.lib.base.dep
testImplementation Config.depConfig.eventbus.dep
}
\ No newline at end of file
......@@ -27,7 +27,8 @@ import java.util.Locale;
*/
public class LanguageUtils {
private static final String KEY_LOCALE = "KEY_LOCALE";
private static final String KEY_LOCALE = "KEY_LOCALE";
private static final String VALUE_FOLLOW_SYSTEM = "VALUE_FOLLOW_SYSTEM";
private LanguageUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
......@@ -89,7 +90,7 @@ public class LanguageUtils {
final String activityClassName,
final boolean isFollowSystem) {
if (isFollowSystem) {
SPUtils.getInstance().put(KEY_LOCALE, "");
SPUtils.getInstance().put(KEY_LOCALE, VALUE_FOLLOW_SYSTEM);
} else {
String localLanguage = locale.getLanguage();
String localCountry = locale.getCountry();
......@@ -112,6 +113,10 @@ public class LanguageUtils {
static void applyLanguage(@NonNull final Activity activity) {
final String spLocale = SPUtils.getInstance().getString(KEY_LOCALE);
if (TextUtils.isEmpty(spLocale)) {
return;
}
if (VALUE_FOLLOW_SYSTEM.equals(spLocale)) {
Locale sysLocale = Resources.getSystem().getConfiguration().locale;
updateLanguage(Utils.getApp(), sysLocale);
updateLanguage(activity, sysLocale);
......
......@@ -85,6 +85,46 @@ public class BusUtilsTest extends BaseTest {
getInstance.method("registerBus", TAG_SINGLE, BusUtilsTest.class.getName(), "singleFun", CountDownLatch.class.getName(), "latch", false, "SINGLE");
}
@Test
public void testMultiThread() {
final BusUtilsTest test = new BusUtilsTest();
// for (int i = 0; i < 100; i++) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// BusUtils.register(test);
// }
// }).start();
// }
// for (int i = 0; i < 100; i++) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// BusUtils.post(TAG_NO_PARAM);
// }
// }).start();
// }
// for (int i = 0; i < 100; i++) {
// new Thread(new Runnable() {
// @Override
// public void run() {
// BusUtils.unregister(test);
// }
// }).start();
// }
// for (int i = 0; i < 100; i++) {
// final int finalI = i;
// new Thread(new Runnable() {
// @Override
// public void run() {
// BusUtils.register(test);
// BusUtils.post(TAG_ONE_PARAM, "" + finalI);
// BusUtils.unregister(test);
// }
// }).start();
// }
}
@Test
public void registerAndUnregister() {
BusUtilsTest test = new BusUtilsTest();
......
package com.blankj.utilcode.util;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* <pre>
* author: blankj
* blog : http://blankj.com
* time : 2019/07/14
* desc :
* </pre>
*/
public class BusUtilsVsEventBusTest extends BaseTest {
@Subscribe
public void eventBusFun(String param) {
}
@BusUtils.Bus(tag = "busUtilsFun")
public void busUtilsFun(String param) {
}
@Before
public void setUp() throws Exception {
// 这一步是在 AOP 的时候注入的,这里通过反射来注入 busUtilsFun 事件,效果是一样的
ReflectUtils getInstance = ReflectUtils.reflect(BusUtils.class).method("getInstance");
getInstance.method("registerBus", "busUtilsFun", BusUtilsVsEventBusTest.class.getName(), "busUtilsFun", String.class.getName(), "param", false, "POSTING");
}
/**
* 注册 10000 个订阅者,共执行 10 次取平均值
*/
@Test
public void compareRegister10000Times() {
final List<BusUtilsVsEventBusTest> eventBusTests = new ArrayList<>();
final List<BusUtilsVsEventBusTest> busUtilsTests = new ArrayList<>();
compareWithEventBus("Register 10000 times.", 10, 10000, new CompareCallback() {
@Override
public void runEventBus() {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
EventBus.getDefault().register(test);
eventBusTests.add(test);
}
@Override
public void runBusUtils() {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
BusUtils.register(test);
busUtilsTests.add(test);
}
@Override
public void restState() {
for (BusUtilsVsEventBusTest test : eventBusTests) {
EventBus.getDefault().unregister(test);
}
eventBusTests.clear();
for (BusUtilsVsEventBusTest test : busUtilsTests) {
BusUtils.unregister(test);
}
busUtilsTests.clear();
}
});
}
/**
* 向 1 个订阅者发送 * 1000000 次,共执行 10 次取平均值
*/
@Test
public void comparePostTo1Subscriber1000000Times() {
comparePostTemplate("Post to 1 subscriber 1000000 times.", 1, 1000000);
}
/**
* 向 100 个订阅者发送 * 100000 次,共执行 10 次取平均值
*/
@Test
public void comparePostTo100Subscribers100000Times() {
comparePostTemplate("Post to 100 subscribers 100000 times.", 100, 100000);
}
private void comparePostTemplate(String name, int subscribeNum, int postTimes) {
final List<BusUtilsVsEventBusTest> tests = new ArrayList<>();
for (int i = 0; i < subscribeNum; i++) {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
EventBus.getDefault().register(test);
BusUtils.register(test);
tests.add(test);
}
compareWithEventBus(name, 10, postTimes, new CompareCallback() {
@Override
public void runEventBus() {
EventBus.getDefault().post("EventBus");
}
@Override
public void runBusUtils() {
BusUtils.post("busUtilsFun", "BusUtils");
}
@Override
public void restState() {
}
});
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().unregister(test);
BusUtils.unregister(test);
}
}
/**
* 注销 10000 个订阅者,共执行 10 次取平均值
*/
@Test
public void compareUnregister10000Times() {
final List<BusUtilsVsEventBusTest> tests = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
BusUtilsVsEventBusTest test = new BusUtilsVsEventBusTest();
EventBus.getDefault().register(test);
BusUtils.register(test);
tests.add(test);
}
compareWithEventBus("Unregister 10000 times.", 10, 1, new CompareCallback() {
@Override
public void runEventBus() {
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().unregister(test);
}
}
@Override
public void runBusUtils() {
for (BusUtilsVsEventBusTest test : tests) {
BusUtils.unregister(test);
}
}
@Override
public void restState() {
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().register(test);
BusUtils.register(test);
}
}
});
for (BusUtilsVsEventBusTest test : tests) {
EventBus.getDefault().unregister(test);
BusUtils.unregister(test);
}
}
/**
* @param name 传入的测试函数名
* @param sampleSize 样本的数量
* @param times 每次执行的次数
* @param callback 比较的回调函数
*/
private void compareWithEventBus(String name, int sampleSize, int times, CompareCallback callback) {
long[][] dur = new long[2][sampleSize];
for (int i = 0; i < sampleSize; i++) {
long cur = System.currentTimeMillis();
for (int j = 0; j < times; j++) {
callback.runEventBus();
}
dur[0][i] = System.currentTimeMillis() - cur;
cur = System.currentTimeMillis();
for (int j = 0; j < times; j++) {
callback.runBusUtils();
}
dur[1][i] = System.currentTimeMillis() - cur;
callback.restState();
}
long eventBusAverageTime = 0;
long busUtilsAverageTime = 0;
for (int i = 0; i < sampleSize; i++) {
eventBusAverageTime += dur[0][i];
busUtilsAverageTime += dur[1][i];
}
System.out.println(
name +
"\nEventBusCostTime: " + eventBusAverageTime / sampleSize +
"\nBusUtilsCostTime: " + busUtilsAverageTime / sampleSize
);
}
public interface CompareCallback {
void runEventBus();
void runBusUtils();
void restState();
}
}
......@@ -28,11 +28,12 @@ public class BusClassVisitor extends ClassVisitor {
private BusInfo busInfo;
private String tag;
private String funParamDesc;
private int funDescIndex;
private String mBusUtilsClass;
public BusClassVisitor(ClassVisitor classVisitor, Map<String, List<BusInfo>> busMap) {
public BusClassVisitor(ClassVisitor classVisitor, Map<String, List<BusInfo>> busMap, String busUtilsClass) {
super(Opcodes.ASM5, classVisitor);
mBusMap = busMap;
mBusUtilsClass = busUtilsClass.replace(".", "/");
}
@Override
......@@ -50,7 +51,7 @@ public class BusClassVisitor extends ClassVisitor {
@Override
public AnnotationVisitor visitAnnotation(String desc1, boolean visible) {
final AnnotationVisitor av = super.visitAnnotation(desc1, visible);
if ("Lcom/blankj/utilcode/util/BusUtils$Bus;".equals(desc1)) {
if (("L" + mBusUtilsClass + "$Bus;").equals(desc1)) {
busInfo = new BusInfo(className, funName);
funParamDesc = desc.substring(1, desc.indexOf(")"));
return new AnnotationVisitor(Opcodes.ASM5, av) {
......
package com.blankj.bus
package com.blankj.bus;
class BusExtension {
boolean abortOnError = true
boolean abortOnError = true;
String busUtilsClass = "com.blankj.utilcode.util.BusUtils";
@Override
String toString() {
return "BusExtension { " +
"abortOnError: " + abortOnError +
", busUtilsClass: " + busUtilsClass +
" }";
}
}
package com.blankj.bus
import com.blankj.bus.util.LogUtils
import com.blankj.bus.util.ZipUtils
import org.apache.commons.io.FileUtils
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
class BusInject {
static void start(Map<String, BusInfo> busMap, File apiJar) {
String jarPath = apiJar.getAbsolutePath()
String decompressedJarPath = jarPath.substring(0, jarPath.length() - 4);
File decompressedJar = new File(decompressedJarPath)
ZipUtils.unzipFile(apiJar, decompressedJar)
static void start(Map<String, BusInfo> busMap, File busUtilsTransformFile, String busUtilsClass) {
LogUtils.l("===>" + busUtilsTransformFile)
if (busUtilsTransformFile.getPath().endsWith(".jar")) {
String jarPath = busUtilsTransformFile.getAbsolutePath()
String decompressedJarPath = jarPath.substring(0, jarPath.length() - 4);
File decompressedJar = new File(decompressedJarPath)
ZipUtils.unzipFile(busUtilsTransformFile, decompressedJar)
File apiUtilsFile = new File(decompressedJarPath + Config.FILE_SEP + Config.BUS_UTILS_CLASS)
File apiUtilsFile = new File(
decompressedJarPath + Config.FILE_SEP +
busUtilsClass.replace('.', Config.FILE_SEP) + '.class'
)
inject2BusUtils(apiUtilsFile, busMap, busUtilsClass)
FileUtils.forceDelete(busUtilsTransformFile)
ZipUtils.zipFiles(Arrays.asList(decompressedJar.listFiles()), busUtilsTransformFile)
FileUtils.forceDelete(decompressedJar)
} else {
File apiUtilsFile = new File(
busUtilsTransformFile.getAbsolutePath() + Config.FILE_SEP +
busUtilsClass.replace('.', Config.FILE_SEP) + '.class'
)
inject2BusUtils(apiUtilsFile, busMap, busUtilsClass)
}
}
private static void inject2BusUtils(File apiUtilsFile, Map<String, BusInfo> busMap, String busUtilsClass) {
ClassReader cr = new ClassReader(apiUtilsFile.bytes);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new BusUtilsClassVisitor(cw, busMap);
ClassVisitor cv = new BusUtilsClassVisitor(cw, busMap, busUtilsClass);
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(apiUtilsFile, cw.toByteArray())
FileUtils.forceDelete(apiJar)
ZipUtils.zipFiles(Arrays.asList(decompressedJar.listFiles()), apiJar)
FileUtils.forceDelete(decompressedJar)
}
}
\ No newline at end of file
......@@ -3,7 +3,6 @@ package com.blankj.bus
import com.android.build.gradle.AppExtension
import com.android.build.gradle.AppPlugin
import com.blankj.bus.util.LogUtils
import org.apache.commons.io.FileUtils
import org.gradle.api.Plugin
import org.gradle.api.Project
......@@ -17,9 +16,6 @@ class BusPlugin implements Plugin<Project> {
project.extensions.create(Config.EXT_NAME, BusExtension)
def android = project.extensions.getByType(AppExtension)
android.registerTransform(new BusTransform(project))
project.afterEvaluate {
def ext = project[Config.EXT_NAME] as BusExtension
}
}
}
}
\ No newline at end of file
package com.blankj.bus
import com.blankj.bus.util.LogUtils
import com.blankj.bus.util.ZipUtils
import groovy.io.FileType
import org.apache.commons.io.FileUtils
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
class BusScan {
Map<String, List<BusInfo>> busMap = [:]
File utilcodeJar
File busUtilsTransformFile
String busUtilsClass
BusScan(String busUtilsClass) {
this.busUtilsClass = busUtilsClass
}
void scanJar(File jar) {
File tmp = new File(jar.getParent(), "temp_" + jar.getName())
List<File> unzipFile = ZipUtils.unzipFile(jar, tmp)
if (unzipFile != null && unzipFile.size() > 0) {
scanDir(tmp)
scanDir(tmp, jar)
FileUtils.forceDelete(tmp)
}
}
void scanDir(File root) {
scanDir(root, root)
}
void scanDir(File root, File source) {
if (!root.isDirectory()) return
String rootPath = root.getAbsolutePath()
if (!rootPath.endsWith(Config.FILE_SEP)) {
rootPath += Config.FILE_SEP
}
root.eachFileRecurse(FileType.FILES) { File file ->
def fileName = file.name
if (!fileName.endsWith('.class')
......@@ -33,9 +47,19 @@ class BusScan {
return
}
def filePath = file.absolutePath
def packagePath = filePath.replace(rootPath, '')
def className = packagePath.replace(Config.FILE_SEP, ".")
// delete .class
className = className.substring(0, className.length() - 6)
if (busUtilsClass == className) {
busUtilsTransformFile = source
LogUtils.l("BusUtils transform file: $source")
}
ClassReader cr = new ClassReader(file.bytes);
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new BusClassVisitor(cw, busMap);
ClassVisitor cv = new BusClassVisitor(cw, busMap, busUtilsClass);
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(file, cw.toByteArray());
......
......@@ -40,11 +40,16 @@ class BusTransform extends Transform {
throws TransformException, InterruptedException, IOException {
super.transform(transformInvocation)
LogUtils.l(getName() + " started")
long stTime = System.currentTimeMillis()
def ext = mProject[Config.EXT_NAME] as BusExtension
LogUtils.l(ext)
if (ext.busUtilsClass.trim().equals("")) {
throw new Exception("BusExtension is empty.")
}
File jsonFile = new File(mProject.projectDir.getAbsolutePath(), "__bus__.json")
FileUtils.write(jsonFile, "{}")
long stTime = System.currentTimeMillis()
def inputs = transformInvocation.getInputs()
def referencedInputs = transformInvocation.getReferencedInputs()
def outputProvider = transformInvocation.getOutputProvider()
......@@ -52,7 +57,7 @@ class BusTransform extends Transform {
outputProvider.deleteAll()
BusScan busScan = new BusScan()
BusScan busScan = new BusScan(ext.busUtilsClass)
inputs.each { TransformInput input ->
input.directoryInputs.each { DirectoryInput dirInput ->// 遍历文件夹
......@@ -66,9 +71,9 @@ class BusTransform extends Transform {
)
FileUtils.copyDirectory(dir, dest)
LogUtils.l("scan dir: $dir [$dest]")
LogUtils.l("scan dir: ${dirInput.file} -> $dest")
busScan.scanDir(dir)
busScan.scanDir(dest)
}
input.jarInputs.each { JarInput jarInput ->// 遍历 jar 文件
File jar = jarInput.file
......@@ -82,25 +87,17 @@ class BusTransform extends Transform {
)
FileUtils.copyFile(jar, dest)
if (jarName.startsWith("com.blankj:utilcode:")
|| jarName.startsWith("com.blankj:utilcodex:")
|| jarName.equals(":lib:utilcode")) {
busScan.utilcodeJar = dest
LogUtils.l("utilcode jar: $jarName [$dest]")
return
}
if (jumpScan(jarName)) {
LogUtils.l("jump jar: $jarName [$dest]")
LogUtils.l("jump jar: $jarName -> $dest")
return
}
LogUtils.l("scan jar: $jarName [$dest]")
busScan.scanJar(jar)
LogUtils.l("scan jar: $jarName -> $dest")
busScan.scanJar(dest)
}
}
if (busScan.utilcodeJar != null) {
if (busScan.busUtilsTransformFile != null) {
if (busScan.busMap.isEmpty()) {
LogUtils.l("no bus.")
} else {
......@@ -123,6 +120,7 @@ class BusTransform extends Transform {
}
}
Map busDetails = [:]
busDetails.put("BusUtilsClass", ext.busUtilsClass)
busDetails.put("rightBus", rightBus)
busDetails.put("wrongBus", wrongBus)
String busJson = JsonUtils.getFormatJson(busDetails)
......@@ -130,17 +128,16 @@ class BusTransform extends Transform {
FileUtils.write(jsonFile, busJson)
if (wrongBus.size() > 0) {
def ext = mProject[Config.EXT_NAME] as BusExtension
if (ext.abortOnError) {
throw new Exception("These buses is not right: " + wrongBus +
"\n u can check it in file: " + jsonFile.toString())
}
}
BusInject.start(busScan.busMap, busScan.utilcodeJar)
BusInject.start(busScan.busMap, busScan.busUtilsTransformFile, ext.busUtilsClass)
}
} else {
LogUtils.l('u should <implementation "com.blankj:utilcode(x):1.25.+">')
throw new Exception("No BusUtils of ${ext.busUtilsClass} in $mProject.")
}
LogUtils.l(getName() + " finished: " + (System.currentTimeMillis() - stTime) + "ms")
......
......@@ -20,10 +20,12 @@ import java.util.Map;
public class BusUtilsClassVisitor extends ClassVisitor {
private Map<String, List<BusInfo>> mBusMap;
private String mBusUtilsClass;
public BusUtilsClassVisitor(ClassVisitor classVisitor, Map<String, List<BusInfo>> busMap) {
public BusUtilsClassVisitor(ClassVisitor classVisitor, Map<String, List<BusInfo>> busMap, String busUtilsClass) {
super(Opcodes.ASM5, classVisitor);
mBusMap = busMap;
mBusUtilsClass = busUtilsClass.replace(".", "/");
}
@Override
......@@ -67,7 +69,7 @@ public class BusUtilsClassVisitor extends ClassVisitor {
}
mv.visitInsn(busInfo.sticky ? ICONST_1 : ICONST_0);
mv.visitLdcInsn(busInfo.threadMode);
mv.visitMethodInsn(INVOKESPECIAL, "com/blankj/utilcode/util/BusUtils", "registerBus", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;)V", false);
mv.visitMethodInsn(INVOKESPECIAL, mBusUtilsClass, "registerBus", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;)V", false);
}
}
};
......
......@@ -14,6 +14,4 @@ class Config {
]
public static final String FILE_SEP = System.getProperty("file.separator")
public static final String BUS_UTILS_CLASS = 'com.blankj.utilcode.util.BusUtils'.replace('.', FILE_SEP) + '.class'
}
package com.blankj.bus;
import com.blankj.utilcode.util.BusUtils;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
......@@ -67,7 +66,7 @@ public class BusTest {
}
@BusUtils.Bus(tag = "manyparam", threadMode = BusUtils.ThreadMode.SINGLE)
public void haha() {
public void haha(int a, int b) {
final Thread thread = Thread.currentThread();
System.out.println(new Callback() {
@Override
......@@ -87,7 +86,7 @@ public class BusTest {
ClassReader cr = new ClassReader(BusTest.class.getName());
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new BusClassVisitor(cw, busMap);
ClassVisitor cv = new BusClassVisitor(cw, busMap, BusUtils.class.getName());
cr.accept(cv, ClassReader.SKIP_FRAMES);
System.out.println("busMap = " + busMap);
......@@ -97,7 +96,7 @@ public class BusTest {
private static void inject2BusUtils(Map<String, List<BusInfo>> busMap) throws IOException {
ClassReader cr = new ClassReader(BusUtils.class.getName());
ClassWriter cw = new ClassWriter(cr, 0);
ClassVisitor cv = new BusUtilsClassVisitor(cw, busMap);
ClassVisitor cv = new BusUtilsClassVisitor(cw, busMap, BusUtils.class.getName());
cr.accept(cv, ClassReader.SKIP_FRAMES);
FileUtils.writeByteArrayToFile(new File("BusUtils2333.class"), cw.toByteArray());
......
package com.blankj.utilcode.util;
package com.blankj.bus;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
......@@ -7,7 +7,6 @@ import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册