Skip to content

Commit

Permalink
增加切换线程注解
Browse files Browse the repository at this point in the history
  • Loading branch information
LinuxPara authored and LinuxPara committed Dec 7, 2019
1 parent 8728e16 commit 546b39b
Show file tree
Hide file tree
Showing 17 changed files with 365 additions and 34 deletions.
19 changes: 15 additions & 4 deletions MVP-Plugin/src/com/mvp/plugin/MvpCodeAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class MvpCodeAction extends AnAction {
public static final String MVP_V_Key = "key";
public static final String MVP_V_Presenters = "presenters";
public static final String MVP_Itr = "com.mvp.plugin.dependent.annotation.MVP_Itr";
public static final String Execute_On = "com.mvp.plugin.dependent.annotation.ExecuteOn";

public static final String MVP_DIALOG_TITLE = "Mvp-Code";

Expand Down Expand Up @@ -81,6 +82,10 @@ public void actionPerformed(AnActionEvent e) {
Messages.showMessageDialog(psiClazz.getName() + " 类中被@MVP_Itr注解的函数不能被static修饰!", MVP_DIALOG_TITLE, null);
return;
}
if (PsiMethodTool.isNotReturnVoidByExecuteOn(extractViewPsiMethods)) {
Messages.showMessageDialog(psiClazz.getName() + " 类中被@ExecuteOn注解的函数返回值必须是void!", MVP_DIALOG_TITLE, null);
return;
}
//=============================================生成View接口==============================================
PsiElementFactory psiElementFactory = JavaPsiFacade.getElementFactory(psiClazz.getProject());
List<PsiMethod> viewItrMethods = PsiMethodTool.generateItrPsiMethods(extractViewPsiMethods, psiElementFactory);
Expand All @@ -89,11 +94,13 @@ public void actionPerformed(AnActionEvent e) {

MvpClazz mvpManagerClazz = new MvpClazz(_Mvp_V_Packaged + ".manager", _Mvp_V_Key + "MvpManager");
PsiImportStatement proxyPsiImport = psiElementFactory.createImportStatement(psiElementFactory.createTypeByFQClassName("java.lang.reflect.Proxy").resolve());
PsiImportStatement viewInvocationHandlerPsiImport = psiElementFactory.createImportStatement(psiElementFactory.createTypeByFQClassName("com.mvp.plugin.dependent.delegate.ViewDelegateInvocationHandler").resolve());
PsiImportStatement presenterInvocationHandlerPsiImport = psiElementFactory.createImportStatement(psiElementFactory.createTypeByFQClassName("com.mvp.plugin.dependent.delegate.PresenterDelegateInvocationHandler").resolve());
PsiImportStatement invocationHandlerPsiImport = psiElementFactory.createImportStatement(psiElementFactory.createTypeByFQClassName("com.mvp.plugin.dependent.delegate.DelegateInvocationHandler").resolve());
// PsiImportStatement viewInvocationHandlerPsiImport = psiElementFactory.createImportStatement(psiElementFactory.createTypeByFQClassName("com.mvp.plugin.dependent.delegate.ViewDelegateInvocationHandler").resolve());
// PsiImportStatement presenterInvocationHandlerPsiImport = psiElementFactory.createImportStatement(psiElementFactory.createTypeByFQClassName("com.mvp.plugin.dependent.delegate.PresenterDelegateInvocationHandler").resolve());
mvpManagerClazz.addPsiImort(proxyPsiImport);
mvpManagerClazz.addPsiImort(viewInvocationHandlerPsiImport);
mvpManagerClazz.addPsiImort(presenterInvocationHandlerPsiImport);
mvpManagerClazz.addPsiImort(invocationHandlerPsiImport);
// mvpManagerClazz.addPsiImort(viewInvocationHandlerPsiImport);
// mvpManagerClazz.addPsiImort(presenterInvocationHandlerPsiImport);
mvpManagerClazz.addPsiMethod(PsiMethodTool.createManagerPsiMethodView(psiElementFactory, "createViewDelegate", viewItrType));

List<MvpClazz> presenterItrClazzList = new ArrayList<>();
Expand All @@ -108,6 +115,10 @@ public void actionPerformed(AnActionEvent e) {
Messages.showMessageDialog(mvp_v_presenter.getName() + "中被@MVP_Itr注解的函数不能被static修饰!", MVP_DIALOG_TITLE, null);
return;
}
if (PsiMethodTool.isNotReturnVoidByExecuteOn(extractPresenterPsiMethods)) {
Messages.showMessageDialog(psiClazz.getName() + " 类中被@ExecuteOn注解的函数返回值必须是void!", MVP_DIALOG_TITLE, null);
return;
}

mvpManagerClazz.addPsiImort(psiElementFactory.createImportStatement(mvp_v_presenter));
//=============================================生成Presenter接口==============================================
Expand Down
36 changes: 30 additions & 6 deletions MVP-Plugin/src/com/mvp/plugin/tools/PsiMethodTool.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mvp.plugin.tools;

import com.intellij.psi.*;
import com.mvp.plugin.MvpCodeAction;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
Expand All @@ -16,6 +17,21 @@ public static boolean isModifierByStatic(@NotNull List<PsiMethod> psiMethods) {
return false;
}

public static boolean isNotReturnVoidByExecuteOn(List<PsiMethod> psiMethods) {
for (PsiMethod psiMethod : psiMethods) {
for (PsiElement psiElement : psiMethod.getModifierList().getChildren()) {
if (psiElement instanceof PsiAnnotation) {
if (((PsiAnnotation) psiElement).getQualifiedName().equals(MvpCodeAction.Execute_On)) {
if (((PsiPrimitiveType) psiMethod.getReturnType()).getKind() != PsiType.VOID.getKind()) {
return true;
}
}
}
}
}
return false;
}

public static List<PsiMethod> generateItrPsiMethods(@NotNull List<PsiMethod> psiMethods, @NotNull PsiElementFactory psiElementFactory) {
List<PsiMethod> _psiMethods = new ArrayList<>();
for (PsiMethod psiMethod : psiMethods) {
Expand All @@ -32,9 +48,13 @@ public static List<PsiMethod> generateItrPsiMethods(@NotNull List<PsiMethod> psi
return _psiMethods;
}

private static PsiMethod createStaticMethod(@NotNull PsiElementFactory psiElementFactory, @NotNull String methodName, @NotNull PsiType returnType) {
private static PsiMethod createStaticMethod(@NotNull PsiElementFactory psiElementFactory, @NotNull String methodName, @NotNull PsiType returnType, boolean isPublic) {
PsiMethod psiMethod = psiElementFactory.createMethod(methodName, returnType);
psiMethod.getModifierList().setModifierProperty(PsiModifier.PUBLIC, true);
if (isPublic) {
psiMethod.getModifierList().setModifierProperty(PsiModifier.PUBLIC, true);
} else {
psiMethod.getModifierList().setModifierProperty(PsiModifier.PRIVATE, true);
}
psiMethod.getModifierList().setModifierProperty(PsiModifier.STATIC, true);

PsiParameter psiParameter = psiElementFactory.createParameter("view", psiElementFactory.createTypeByFQClassName("java.lang.Object"));
Expand All @@ -44,25 +64,27 @@ private static PsiMethod createStaticMethod(@NotNull PsiElementFactory psiElemen
}

public static PsiMethod createManagerPsiMethodView(@NotNull PsiElementFactory psiElementFactory, @NotNull String methodName, @NotNull PsiType returnType) {
PsiMethod psiMethod = createStaticMethod(psiElementFactory, methodName, returnType);
PsiMethod psiMethod = createStaticMethod(psiElementFactory, methodName, returnType, false);

String createDelegateText = "return (%s) Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{%s.class}, new ViewDelegateInvocationHandler(view));";
// String createDelegateText = "return (%s) Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{%s.class}, new ViewDelegateInvocationHandler(view));";
String createDelegateText = "return (%s) Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{%s.class}, new DelegateInvocationHandler(view));";
PsiStatement psiStatement = psiElementFactory.createStatementFromText(String.format(createDelegateText, returnType.getCanonicalText(), returnType.getCanonicalText()), null);
psiMethod.getBody().add(psiStatement);

return psiMethod;
}

public static PsiMethod createManagerPsiMethodPresenter(@NotNull PsiElementFactory psiElementFactory, @NotNull String methodName, @NotNull PsiType returnType, @NotNull PsiType viewItrType, @NotNull PsiType presenterType) {
PsiMethod psiMethod = createStaticMethod(psiElementFactory, methodName, returnType);
PsiMethod psiMethod = createStaticMethod(psiElementFactory, methodName, returnType, true);

String callMethodText = "%s viewDelegate = createViewDelegate(view);";
PsiStatement callMethodStatement = psiElementFactory.createStatementFromText(String.format(callMethodText, viewItrType.getCanonicalText()), null);

String varPresenterText = "%s presenter = new %s(viewDelegate);";
PsiStatement varPresenterStatement = psiElementFactory.createStatementFromText(String.format(varPresenterText, presenterType.getCanonicalText(), presenterType.getCanonicalText()), null);

String createDelegateText = "return (%s) Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{%s.class}, new PresenterDelegateInvocationHandler(presenter));";
// String createDelegateText = "return (%s) Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{%s.class}, new PresenterDelegateInvocationHandler(presenter));";
String createDelegateText = "return (%s) Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{%s.class}, new DelegateInvocationHandler(presenter));";
PsiStatement createDelegateStatement = psiElementFactory.createStatementFromText(String.format(createDelegateText, returnType.getCanonicalText(), returnType.getCanonicalText()), null);

psiMethod.getBody().add(callMethodStatement);
Expand All @@ -71,4 +93,6 @@ public static PsiMethod createManagerPsiMethodPresenter(@NotNull PsiElementFacto

return psiMethod;
}


}
2 changes: 1 addition & 1 deletion MvpPluginTest/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 34 additions & 4 deletions MvpPluginTest/MvpPluginDependent/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
apply plugin: 'java-library'
apply plugin: 'com.android.library'

android {
compileSdkVersion 29
buildToolsVersion "29.0.2"


defaultConfig {
minSdkVersion 15
targetSdkVersion 29
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}

sourceCompatibility = "7"
targetCompatibility = "7"
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
2 changes: 2 additions & 0 deletions MvpPluginTest/MvpPluginDependent/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mvp.plugin.dependent" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.mvp.plugin.dependent.annotation;

import com.mvp.plugin.dependent.thread.ThreadMode;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExecuteOn {
ThreadMode thread();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package com.mvp.plugin.dependent.delegate;

import com.mvp.plugin.dependent.annotation.ExecuteOn;
import com.mvp.plugin.dependent.thread.ThreadTool;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class DelegateInvocationHandler implements InvocationHandler {

private final WeakReference<Object> mWrTarget;

public DelegateInvocationHandler(Object target) {
mWrTarget = new WeakReference<>(target);
}


@Override
public Object invoke(Object proxy, Method method, Object[] args) {
if (mWrTarget.get() != null) {
try {
//被代理的方法
Method delegateMethod = mWrTarget.get().getClass().getMethod(method.getName(), method.getParameterTypes());
delegateMethod.setAccessible(true);
if (!needThreadHandle(delegateMethod, args)) {
return invokeMethod(delegateMethod, mWrTarget.get(), args);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} else {
Exception e = new Exception("View的被代理对象被回收了!代理的方法:" + method.getName() + " 参数:" + Arrays.toString(method.getParameterTypes()));
e.printStackTrace();
}
return null;
}

private boolean needThreadHandle(Method method, Object[] args) {
ExecuteOn executeOnAnno = method.getAnnotation(ExecuteOn.class);
if (executeOnAnno != null) {
if (method.getReturnType() != Void.TYPE) {
throw new RuntimeException("ExecuteOn注解修饰的函数" + method.getName() + "返回值必须是void!");
}
switch (executeOnAnno.thread()) {
case MAIN:
ThreadTool.executeOnMainThread(new Runnable() {
@Override
public void run() {
invokeMethod(method, mWrTarget.get(), args);
}
});
return true;
case ASYNC:
ThreadTool.executeOnAsyncThread(new Runnable() {
@Override
public void run() {
invokeMethod(method, mWrTarget.get(), args);
}
});
return true;
}
}
return false;
}

private Object invokeMethod(Method method, Object target, Object[] args) {
try {
return method.invoke(target, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.mvp.plugin.dependent.delegate;

import com.mvp.plugin.dependent.annotation.ExecuteOn;
import com.mvp.plugin.dependent.thread.ThreadTool;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class PresenterDelegateInvocationHandler implements InvocationHandler {
Expand All @@ -17,9 +21,50 @@ public Object invoke(Object proxy, Method method, Object[] args) {
try {
Method delegateMethod = mTarget.getClass().getMethod(method.getName(), method.getParameterTypes());
delegateMethod.setAccessible(true);
return delegateMethod.invoke(mTarget, args);
} catch (Exception e) {
if (!needThreadHandle(delegateMethod,args)) {
return invokeMethod(delegateMethod, mTarget, args);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}

private boolean needThreadHandle(Method method,Object[] args){
ExecuteOn executeOnAnno = method.getAnnotation(ExecuteOn.class);
if (executeOnAnno != null) {
if (method.getReturnType() != Void.TYPE) {
throw new RuntimeException("ExecuteOn注解修饰的函数" + method.getName() + "返回值必须是void!");
}
switch (executeOnAnno.thread()) {
case MAIN:
ThreadTool.executeOnMainThread(new Runnable() {
@Override
public void run() {
invokeMethod(method, mTarget, args);
}
});
return true;
case ASYNC:
ThreadTool.executeOnAsyncThread(new Runnable() {
@Override
public void run() {
invokeMethod(method, mTarget, args);
}
});
return true;
}
}
return false;
}

private Object invokeMethod(Method method, Object target, Object[] args) {
try {
return method.invoke(target, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return null;
}
Expand Down
Loading

0 comments on commit 546b39b

Please sign in to comment.