解讀demo:https://github.com/north2016/T-MVP
一.前言
javassist是一個操作class文件即class字節碼的動態類庫;在打包過程中,用來檢查、”動態”修改以及創建 Java類。其功能與jdk自帶的反射功能類似,但比反射功能更強大。
爲了方便看,我將javassist的demo剝離出來
二.原理
gradle從1.5開始,gradle插件包含了一個叫Transform的API,這個API允許第三方插件在class文件轉爲爲dex文件前操作編譯好的class文件,這個API的目標是簡化自定義類操作,而不必處理Task,並且在操作上提供更大的靈活性。並且可以更加靈活地進行操作。
官方文檔:http://google.github.io/android-gradle-dsl/javadoc/
demo的原理也是基於此來完成的。即java代碼編譯後生成class文件,當要打包.class-->.dex時,Javassit庫操作.class文件,讀取所有的文件的註解,根據註解將EventBus的註解與反註解以及觸發事件的方法生成到當前的.class文件中。
三.核心類
ClassPool:javassist的類池,使用ClassPool 類可以跟蹤和控制所操作的類,它的工作方式與 JVM 類裝載器非常相似,CtClass: 提供了檢查類數據(如字段和方法)以及在類中添加新字段、方法和構造函數、以及改變類、父類和接口的方法。
CtField:用來訪問域 (屬性)
CtMethod :用來訪問方法
CtConstructor:用來訪問構造器
不過,Javassist 並未提供刪除類中字段、方法或者構造函數的任何方法。
CtClass.getDeclaredMethods()獲取自己申明的方法,CtClass.getMethods()會把所有父類的方法都加上
四.代碼詳解
注意:修改插件中的代碼一定要重新發布,發佈之前可先將之前的插件刪除,將build刪除,重新運行./gradlew -p plugin clean build uploadArchives --info
1.transform插件
1.1在插件module的build.gradle中加入javassist庫,並配置發佈的插件
apply plugin: 'groovy'
apply plugin: 'maven'
dependencies {
compile gradleApi()//gradle sdk
compile localGroovy()//groovy sdk
compile 'com.android.tools.build:gradle:2.3.1'
// compile 'com.android.tools.build:transform-api:1.5.0'
compile 'org.javassist:javassist:3.20.0-GA'//javassist庫
}
uploadArchives {
repositories.mavenDeployer {//重新發布之後,會在本地的repo路徑生成倉庫(也可發佈到遠程)可參照http://geek.csdn.net/news/detail/53459
repository(url: uri('../repo'))
pom.groupId = 'com.app.plugin'
pom.artifactId = 'gradleplugin'
pom.version = '1.0.0'
}
}
repositories {
jcenter()
}
//注意⚠️: 插件修改後運行前需要重新發布: ./gradlew -p plugin clean build uploadArchives --info
1.2繼承插件Plugin並將自定義的Transform註冊到android中的插件中
public class JavassistPlugin implements Plugin<Project> {
void apply(Project project) {
def log = project.logger
log.error "========================";
log.error "Javassist開始修改Class!";
log.error "========================";
//版本不一樣獲取的AppExtension方式不一樣,這裏一定要注意
//project.android.registerTransform(new JavassistTransform(project)) 這裏是無效的
def android = project.extensions.getByType(AppExtension);
android.registerTransform(new JavassistTransform(project));
project.task('transformPath') {
doLast {
System.out.println('+++++++++++++++++++++transformPath task')
}
}
}
}
1.3自定義Transformpublic class JavassistTransform extends Transform {
Project project
public JavassistTransform(Project project) { // 構造函數,我們將Project保存下來備用
this.project = project
project.logger.error("====start===JavassistTransform");
}
//transformClassesWithMyClassTransformForDebug 運行時的名字
//transformClassesWith + getName() + For + Debug或Release
@Override
String getName() {// 設置我們自定義的Transform對應的Task名稱
return com.app.plugin.JavassistTransform.simpleName;
}
@Override
// 指定輸入的類型,通過這裏的設定,可以指定我們要處理的文件類型這樣確保其他類型的文件不會傳入
//需要處理的數據類型,有兩種枚舉類型
//CLASSES和RESOURCES,CLASSES代表處理的java的class文件,RESOURCES代表要處理java的資源
Set<QualifiedContent.ContentType> getInputTypes() {
return Sets.immutableEnumSet(QualifiedContent.DefaultContentType.CLASSES)
}
@Override
/****指定Transform的作用範圍
*
* 指Transform要操作內容的範圍,官方文檔Scope有7種類型:
* EXTERNAL_LIBRARIES 只有外部庫
* PROJECT 只有項目內容
* PROJECT_LOCAL_DEPS 只有項目的本地依賴(本地jar)
* PROVIDED_ONLY 只提供本地或遠程依賴項
* SUB_PROJECTS 只有子項目。
* SUB_PROJECTS_LOCAL_DEPS 只有子項目的本地依賴項(本地jar)。
* TESTED_CODE 由當前變量(包括依賴項)測試的代碼
*/
Set<QualifiedContent.Scope> getScopes() {
return Sets.immutableEnumSet(QualifiedContent.Scope.PROJECT, QualifiedContent.Scope.PROJECT_LOCAL_DEPS,
QualifiedContent.Scope.SUB_PROJECTS, QualifiedContent.Scope.SUB_PROJECTS_LOCAL_DEPS,
QualifiedContent.Scope.EXTERNAL_LIBRARIES)
}
/***當前Transform是否支持增量編譯*/
@Override
boolean isIncremental() {
return false
}
/***
* Transform中的核心方法,
* @param context
* @param inputs 中是傳過來的輸入流,其中有兩種格式,一種是jar包格式一種是目錄格式。
* @param referencedInputs
* @param outputProvider outputProvider 獲取到輸出目錄,最後將修改的文件複製到輸出目錄,這一步必須做不然編譯會報錯
* @param isIncremental
* @throws IOException
* @throws TransformException
* @throws InterruptedException
*/
@Override
void transform(Context context, Collection<TransformInput> inputs,
Collection<TransformInput> referencedInputs,
TransformOutputProvider outputProvider, boolean isIncremental)
throws IOException, TransformException, InterruptedException {//只有打包apk時纔會執行,build不會執行
def startTime = System.currentTimeMillis();
project.logger.error("===exe=====transform" + inputs.size());
// Transform的inputs有兩種類型,一種是目錄,一種是jar包,要分開遍歷
inputs.each { TransformInput input ->
try {
input.jarInputs.each {
project.logger.error("===exe=====jarInputs" );
MyInject.injectDir(it.file.getAbsolutePath(), BusHelper.PKG_NAME, project)
String outputFileName = it.name.replace(".jar", "") + '-' + it.file.path.hashCode()
def output = outputProvider.getContentLocation(outputFileName, it.contentTypes, it.scopes, Format.JAR)
FileUtils.copyFile(it.file, output)
}
} catch (Exception e) {
project.logger.error e.getMessage();
}
//對類型爲“文件夾”的input進行遍歷
input.directoryInputs.each { DirectoryInput directoryInput ->
project.logger.error("===exe=====directoryInputs" );
//文件夾裏面包含的是我們手寫的類以及R.class、BuildConfig.class以及R$XXX.class等
MyInject.injectDir(directoryInput.file.absolutePath, BusHelper.PKG_NAME, project)
// 獲取output目錄
def dest = outputProvider.getContentLocation(directoryInput.name,
directoryInput.contentTypes, directoryInput.scopes,
Format.DIRECTORY)
// 將input的目錄複製到output指定目錄
FileUtils.copyDirectory(directoryInput.file, dest)
}
}
ClassPool.getDefault().clearImportedPackages();
project.logger.error("JavassistTransform cast :" + (System.currentTimeMillis() - startTime) / 1000 + " secs");
}
}
主要看transform(xxx)方法。當編譯打包時,會執行t該方法,通過看代碼,主要是遍歷兩個jar和文件夾列表。隨後主要是以下這行代碼。
MyInject.injectDir(it.file.getAbsolutePath(), BusHelper.PKG_NAME, project)
將當前文件夾路徑以及當前項目的包名作爲參數傳進去。注意包名:要有統一的包名的開頭,用於自動匹配app\build\intermediates\classes\debug\統一包名\....的包名路徑如這裏:BusHelper.PKG_NAME=“me\”;那麼自動匹配app\build\intermediates\classes\debug\me\...
MyInject.injectDir:
/****
*
* @param path jar包或者文件夾路徑
* @param packageName 自己的包名,一定要有一個統一的包名
* @param project
*/
public static void injectDir(String path, String packageName, Project project) {
project.logger.error( "p == "+path+" pkg "+packageName);
pool.appendClassPath(path)
//project.android.bootClasspath 加入android.jar,否則找不到android相關的所有類
pool.appendClassPath(project.android.bootClasspath[0].toString());
Utils.importBaseClass(pool);
File dir = new File(path)
if (dir.isDirectory()) {//遍歷文件夾
dir.eachFileRecurse { File file ->
String filePath = file.absolutePath//確保當前文件是class文件,並且不是系統自動生成的class文件
if (filePath.endsWith(".class") && !filePath.contains('R$') && !filePath.contains('$')//代理類
&& !filePath.contains('R.class') && !filePath.contains("BuildConfig.class")) {
// 判斷當前目錄是否是在我們的應用包裏面
int index = filePath.indexOf(packageName);
project.logger.error( index+" filePath == "+filePath);//C:\Users\Administrator\Desktop\AOP\EventBus-master-javassit\ViewFinder-master\sample\build\intermediates\classes\debug\me\brucezz\viewfinder\sample\SecondActivity.class
project.logger.error( index+" packageName == "+packageName);
boolean isMyPackage = index != -1;
project.logger.error( index+"isMyPackage == "+isMyPackage);
if (isMyPackage) {
//將路徑轉成包名+類名
String className = Utils.getClassName(index, filePath);
project.logger.error( "pool : "+pool.toString());
project.logger.error( "className : "+className);
CtClass c = pool.getCtClass(className)
if (c.isFrozen()) c.defrost()
BusInfo mBusInfo = new BusInfo()
mBusInfo.setProject(project)
mBusInfo.setClazz(c)
if (c.getName().endsWith("Activity") || c.getSuperclass().getName().endsWith("Activity")) mBusInfo.setIsActivity(true)
boolean isAnnotationByBus = false;
//getDeclaredMethods獲取自己申明的方法,c.getMethods()會把所有父類的方法都加上
for (CtMethod ctmethod : c.getDeclaredMethods()) {
String methodName = Utils.getSimpleName(ctmethod);
if (BusHelper.ON_CREATE.contains(methodName)) mBusInfo.setOnCreateMethod(ctmethod)
if (BusHelper.ON_DESTROY.contains(methodName)) mBusInfo.setOnDestroyMethod(ctmethod)
for (Annotation mAnnotation : ctmethod.getAnnotations()) {
if (mAnnotation.annotationType().canonicalName.equals(BusHelper.OkBusRegisterAnnotation))
mBusInfo.setBusRegisterMethod(ctmethod)
if (mAnnotation.annotationType().canonicalName.equals(BusHelper.OkBusUnRegisterAnnotation))
mBusInfo.setBusUnRegisterMethod(ctmethod)
if (mAnnotation.annotationType().canonicalName.equals(BusHelper.OkBusAnnotation)) {
project.logger.info " method:" + c.getName() + " -" + ctmethod.getName()
mBusInfo.methods.add(ctmethod)
mBusInfo.annotations.add(mAnnotation)
if (!isAnnotationByBus) isAnnotationByBus = true
}
}
}
if (((mBusInfo.BusRegisterMethod != null && mBusInfo.BusUnRegisterMethod == null
|| mBusInfo.BusRegisterMethod == null && mBusInfo.BusUnRegisterMethod != null)))
assert false: Utils.getBusErr()
if (mBusInfo != null && isAnnotationByBus) {
try {
project.logger.error( "intBus path == "+path);
BusHelper.intBus(mBusInfo, path)
} catch (DuplicateMemberException e) {
}
}
c.detach()//用完一定記得要卸載,否則pool裏的永遠是舊的代碼
}
}
}
}
}
一行行代碼看:
1:
private final static ClassPool pool = ClassPool.getDefault();Utils.importBaseClass(pool);
/**
* 事先載入相關類
* @param pool
*/
static void importBaseClass(ClassPool pool) {
pool.importPackage(LogTimeHelper.LogTimeAnnotation);
pool.importPackage(BusHelper.OkBusAnnotation);
pool.importPackage(BusHelper.OkBusRegisterAnnotation);
pool.importPackage(BusHelper.OkBusUnRegisterAnnotation);
pool.importPackage("android.os.Bundle");
pool.importPackage("me.brucezz.viewfinder.sample.event.OkBus")
pool.importPackage("me.brucezz.viewfinder.sample.event.Event")
pool.importPackage("android.os.Message")
}
將需要的包名都導入池子中。主要是新增的代碼所需要的導入的包。
2:遞歸遍歷文件夾中所有class文件,並根據文件路徑和包名開頭獲取class的包名+類名,從而從javassist庫的池子中獲取CtClass類操作當前.class
CtClass c = pool.getCtClass(className)
if (c.isFrozen()){
c.defrost()
}
BusInfo mBusInfo = new BusInfo()
mBusInfo.setProject(project)
mBusInfo.setClazz(c)
if (c.getName().endsWith("Activity") || c.getSuperclass().getName().endsWith("Activity")){
mBusInfo.setIsActivity(true)
}
獲取當前class實例,並將其解凍使其可用,隨後生成BusInfo實例,用以記錄增加EventBus註冊和反註冊以及觸發事件方法的註解。再者當前Activity命名必須是以activity結尾或父類的命名是以Activity結尾,這個寫一個BaseActivity就可以了。
BusInfo
public class BusInfo {
Project project//保留當前工程的引用
CtClass clazz//當前處理的class
List<CtMethod> methods = new ArrayList<>()//帶有Bus註解的方法列表
List<Annotation> annotations = new ArrayList<>()//帶有Bus註解的註解列表
List<Integer> eventIds = new ArrayList<>()//帶有Bus註解的註解id列表
boolean isActivity = false;//是否是在Activity
CtMethod OnCreateMethod//Activity或Fragment的初始化方法
CtMethod OnDestroyMethod//Activity或Fragment的銷燬方法
CtMethod BusRegisterMethod//被Register註解標註的初始化方法
CtMethod BusUnRegisterMethod//被UnRegister註解標註的銷燬方法
}
接着,遍歷當前類的方法是否有使用註解以及是否重寫onCreate()和onDestory(),如果有,則將註解信息解析存儲到busInfo實例中。
//getDeclaredMethods獲取自己申明的方法,c.getMethods()會把所有父類的方法都加上
for (CtMethod ctmethod : c.getDeclaredMethods()) {
String methodName = Utils.getSimpleName(ctmethod);
if (BusHelper.ON_CREATE.contains(methodName)) mBusInfo.setOnCreateMethod(ctmethod)
if (BusHelper.ON_DESTROY.contains(methodName)) mBusInfo.setOnDestroyMethod(ctmethod)
for (Annotation mAnnotation : ctmethod.getAnnotations()) {
if (mAnnotation.annotationType().canonicalName.equals(BusHelper.OkBusRegisterAnnotation))
mBusInfo.setBusRegisterMethod(ctmethod)
if (mAnnotation.annotationType().canonicalName.equals(BusHelper.OkBusUnRegisterAnnotation))
mBusInfo.setBusUnRegisterMethod(ctmethod)
if (mAnnotation.annotationType().canonicalName.equals(BusHelper.OkBusAnnotation)) {
project.logger.info " method:" + c.getName() + " -" + ctmethod.getName()
mBusInfo.methods.add(ctmethod)
mBusInfo.annotations.add(mAnnotation)
if (!isAnnotationByBus) isAnnotationByBus = true
}
}
最後:解析完信息後,在onCreate()、onDestory()或帶有註解的方法實現註冊與反註冊的EventBus,以及在當前類增加觸發事件的方法。
調用BusHelper.intBus(mBusInfo, path):
static void intBus(BusInfo mBusInfo, String path) {
if (mBusInfo.clazz.isFrozen()) mBusInfo.clazz.defrost()//解凍
if (mBusInfo.BusRegisterMethod != null) {//有被BusRegister註解
mBusInfo.project.logger.error "BusRegisterMethod not null" +
mBusInfo.BusRegisterMethod.insertAfter(getRegisterEventMethodStr(mBusInfo));
} else if (mBusInfo.getOnCreateMethod() == null) {//沒有OnCreateMethod,創建並加上新代碼
mBusInfo.project.logger.quiet "getOnCreateMethod null " + mBusInfo.isActivity
String pre_create_str = mBusInfo.isActivity ? Activity_OnCreate : Fragment_OnCreate;
String m = pre_create_str + getRegisterEventMethodStr(mBusInfo) + "}"
mBusInfo.project.logger.quiet m
mBusInfo.project.logger.error m
CtMethod mInitEventMethod = CtNewMethod.make(m, mBusInfo.clazz);
mBusInfo.clazz.addMethod(mInitEventMethod)
} else {//有OnCreateMethod,直接插入新代碼
mBusInfo.project.logger.error "OnCreateMethod not null"
mBusInfo.project.logger.quiet "OnCreateMethod not null"
mBusInfo.OnCreateMethod.insertAfter(getRegisterEventMethodStr(mBusInfo));
}
if (mBusInfo.BusUnRegisterMethod != null) {//有被BusUnRegister註解的方法
mBusInfo.project.logger.quiet "BusUnRegisterMethod not null"
mBusInfo.project.logger.error "BusUnRegisterMethod not null"
mBusInfo.BusUnRegisterMethod.insertAfter(getUnRegisterEventMethodStr(mBusInfo));
} else if (mBusInfo.OnDestroyMethod == null) {
mBusInfo.project.logger.quiet "OnDestroyMethod null"
mBusInfo.project.logger.error "OnDestroyMethod null"
String m = Pre_OnDestroy + getUnRegisterEventMethodStr(mBusInfo) + "}";
mBusInfo.project.logger.quiet m
CtMethod destroyMethod = CtNewMethod.make(m, mBusInfo.clazz)
mBusInfo.clazz.addMethod(destroyMethod)
} else {
mBusInfo.project.logger.quiet "OnDestroyMethod not null"
mBusInfo.project.logger.error "OnDestroyMethod not null"
mBusInfo.OnDestroyMethod.insertAfter(getUnRegisterEventMethodStr(mBusInfo));
}
mBusInfo.clazz.writeFile(path)
}
主要是查看是否有使用註解或是否重寫oncreate()和onDestory(),隨後在帶有註解的方法或onCreate()和onDestory()方法的最後通過ctMethod.insertAfter()插入EventBus的註冊與反註冊java語句或者class.addMethod()添加java方法,隨後通過javassit庫中的ctclass.writeFile()將新增的內容寫回文件中。
反註冊:
/**
* 生成取消事件註冊的代碼
* @param mBusInfo
*/
static String getUnRegisterEventMethodStr(mBusInfo) {
String dis_Str = "";
mBusInfo.eventIds.each { id -> dis_Str += "OkBus.getInstance().unRegister(" + id + ");\n" }
return dis_Str;
}
註冊:/**
* 獲取初始化OkBus方法的代碼
* @param mBusInfo 事件信息
* @return
*/
static String getRegisterEventMethodStr(BusInfo mBusInfo) {
String CreateStr = "";
//爲當前的類添加事件處理的接口:當前類要實現事件Event接口
mBusInfo.clazz.addInterface(mBusInfo.clazz.classPool.get("me.brucezz.viewfinder.sample.event.Event"));
for (int i = 0; i < mBusInfo.getMethods().size(); i++) {
MethodInfo methodInfo = mBusInfo.getMethods().get(i).getMethodInfo();
Annotation mAnnotation = mBusInfo.getAnnotations().get(i)
AnnotationsAttribute attribute = methodInfo.getAttribute(AnnotationsAttribute.visibleTag);
//獲取註解屬性
javassist.bytecode.annotation.Annotation annotation = attribute.getAnnotation(mAnnotation.annotationType().canonicalName);
//獲取註解
int id = ((IntegerMemberValue) annotation.getMemberValue("value")).getValue();//獲取註解的值
int thread = -1;
if (annotation.getMemberValue("thread") != null)
thread = ((IntegerMemberValue) annotation.getMemberValue("thread")).getValue();
mBusInfo.eventIds.add(id)
CreateStr += "OkBus.getInstance().register(" + id + ",(Event)this," + thread + ");\n"
}
initEventDispatch(mBusInfo)
return CreateStr;
}
當前類是實現統一事件的接口Event:註冊完後,生成事件分發的邏輯代碼方法如下:
/**
* 生成event事件分發的邏輯代碼
* @param mBusInfo
* @return
*/
static initEventDispatch(BusInfo mBusInfo) {
String SwitchStr = Pre_Switch_Str;//接口實現方法
for (int i = 0; i < mBusInfo.eventIds.size(); i++) {
CtMethod method = mBusInfo.getMethods().get(i)
CtClass[] mParameterTypes = method.getParameterTypes();
assert mParameterTypes.length <= 1
boolean one = mParameterTypes.length == 1
boolean isBaseType = false;
String packageName = "";
if (one) {
String mParameterType = mParameterTypes[0].name;
switch (mParameterType) {
//Primitive Types(原始型) Reference Types(Wrapper Class)(引用型,(包裝類))
case "boolean": mParameterType = "Boolean"; isBaseType = true; break;
case "byte": mParameterType = "Byte"; isBaseType = true; break;
case "char": mParameterType = "Character"; isBaseType = true; break;
case "float": mParameterType = "Float"; isBaseType = true; break;
case "int": mParameterType = "Integer"; isBaseType = true; break;
case "long": mParameterType = "Long"; isBaseType = true; break;
case "short": mParameterType = "Short"; isBaseType = true; break;
case "double": mParameterType = "Double"; isBaseType = true; break;
}
mBusInfo.project.logger.quiet "name:" + mParameterType;
packageName = isBaseType ? "java.lang." + mParameterType : mParameterType;
mBusInfo.clazz.classPool.importPackage(packageName)
}//如果是基本數據類型,需要手動拆箱,否則會報錯
String ParamStr = isBaseType ? ("((" + packageName + ")msg.obj)." +
mParameterTypes[0].name + "Value()") : ("(" + packageName + ")msg.obj");
SwitchStr += "case " + mBusInfo.eventIds.get(i) + ":" + method.getName() +
"(" + (one ? ParamStr : "") + ");\n break;\n"
mBusInfo.project.logger.error "pgkname:" + packageName;
}
String m = SwitchStr + "}\n}"
mBusInfo.project.logger.quiet m
CtMethod mDispatchEventMethod = CtMethod.make(m, mBusInfo.clazz);
mBusInfo.clazz.addMethod(mDispatchEventMethod)
}
MainActivity源代碼:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
TextView mTextView;
Button mButton;
EditText mEditText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.tv);
mButton = (Button) findViewById(R.id.btn);
mEditText = (EditText) findViewById(R.id.et);
mTextView.setOnClickListener(this);
mButton.setOnClickListener(this);
mEditText.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v == mTextView) {
Toast.makeText(this, "1 onTextClick", Toast.LENGTH_SHORT).show();
} else if (v == mButton) {
Toast.makeText(this, "1 onButtonClick", Toast.LENGTH_SHORT).show();
OkBus.getInstance().onEvent(EventTags.FLASH_INIT_UI);
} else if (v == mEditText) {
}
}
@Bus(EventTags.FLASH_INIT_UI)
public void initUI() {
AlphaAnimation anim = new AlphaAnimation(0.8f, 0.1f);
anim.setDuration(500);
anim.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
Log.d("jumpToMainPage","====onAnimationEnd");
OkBus.getInstance().onEvent(EventTags.JUMP_TO_MAIN);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
mEditText.startAnimation(anim);
}
@Bus(EventTags.JUMP_TO_MAIN)
public void jumpToMainPage() {
// TRouter.go(C.HOME);
SecondActivity.startInstance(this);
Log.d("jumpToMainPage","====jumpToMainPage");
finish();
}
}
經過編譯運行之後,class的代碼就會被修改爲:只列出生成的代碼及方法,其它不變的刪除了。如下
查看class路徑:sample\build\intermediates\classes\debug
protected void onCreate(Bundle savedInstanceState) {
OkBus.getInstance().register(1, (Event)this, -1);
OkBus.getInstance().register(2, (Event)this, -1);
}
public void call(Message var1) {
switch(var1.what) {
case 1:
this.initUI();
break;
case 2:
this.jumpToMainPage();
}
}
protected void onDestroy() {
super.onDestroy();
OkBus.getInstance().unRegister(1);
OkBus.getInstance().unRegister(2);
}
可以看見自動生成了call(msg)方法和註冊與發註冊的語句。這樣就完成了頻繁書寫註冊與反註冊麻煩事件。
javassit的用法就是這麼簡單,其它的可以查看javassit手冊或者https://blog.csdn.net/u011425751/article/details/51917895