编译时注解框架

新增AndroidStudio插件

change log

新增 广播接收器支持permission

新增 广播接收器支持flag

新增 广播接收器支持priority

优化PermissionUtil

引用

implementation 'com.huangyuanlove:view-inject-api:1.1.1'
implementation 'com.huangyuanlove:view-inject-annotation:1.1.0'
annotationProcessor 'com.huangyuanlove:view-inject-compile:1.1.0'

混淆

如果开启了混淆,则需要在混淆文件中配置

-keep public class com.huangyuanlove.view_inject_annotation.**
-keep public class com.huangyuanlove.view_inject_api.**
-keep public class com.huangyuanlove.view_inject_compiler.**
-keep public class **$$Router
-keep public class **$ViewInjector {
**[] $VALUES;
public *;
}

view-inject-annotation1.1.1 变更

权限相关优化

1.1.1之前的版本(不包含1.1.1)在使用PermissionUtil时,从流程上来讲还是挺繁琐的:

先调用PermissionUtil.hasSelfPermissions来检测是否有权限

然后调用PermissionUtil.shouldShowRequestPermissionRationale判断是否需要弹出权限说明窗

最后调用ActivityCompat.requestPermissions来请求权限

然后在重写Activity的onRequestPermissionsResult方法,在该方法中通过PermissionUtil.onRequestPermissionsResult(this,requestCode,permissions,grantResults,new PermissionUtil.RequestPermissionResult())判断用户对权限的响应

优化之后,我们只需要new Permissions(this).requestPermissions(int requestCode, PermissionFragment.OnPermissionResult onPermissionResult, String... permissions)这个方法就好了,代码如下:

PermissionFragment.OnPermissionResult onPermissionResult = new PermissionFragment.OnPermissionResult() {
@Override
public void onPermissionResult(int requestCode, ArrayList grantPermission, ArrayList shouldShowRationalePermission, ArrayList neverAskAgainPermission) {
Log.e("huangyuan","grantPermission:"+grantPermission);
Log.e("huangyuan","shouldShowRationalePermission:"+shouldShowRationalePermission);
Log.e("huangyuan","neverAskAgainPermission:"+neverAskAgainPermission);
}
};

new Permissions(this).requestPermissions(AUDIO_PERMISSION, onPermissionResult, Manifest.permission.RECORD_AUDIO);

实现PermissionFragment.OnPermissionResult接口

创建Permissions

调用Permissions的实例方法requestPermissions,第一个参数为int类型requestCode,第二个参数为步骤1中的实现类,后面的不定长参数是需要申请的权限

Q:为什么在Activity和Fragment中同时重写了onRequestPermissionsResult方法,在Fragment中收不到回调?

A:在Activity中使用ActivityCompat.requestPermissions来申请权限,在Fragmen中直接使用requestPermissions申请权限;如果Fragment和Activity同时重写了onRequestPermissionsResult方法,则需要在Activity重写的方法中调用super.onRequestPermissionsResult,这样Fragment中才会收到回调。至于为什么,RTFSC。

以下是1.1.0版本说明

@BindView

使用方法:

在application module中

@BindView(id = R.id.xxx)
protected Button buttonOne;

在 library module中

@BindView(idStr = "xxx")
protected Button buttonTwo;

需要注意的是:字段的访问修饰符权限必须大于 protected,在字段使用前调用(一般是在OnCreate、onCreateView)ViewInjector.bind(this);

Activity示例: TestViewInjectActivity.java

Fragment示例: TestViewInjectFragment.java

Adapter示例: ListViewAdapter

@ClickResponder
在application module中
@ClickResponder(id = {R.id.xxx,R.id.yyy})
public void onClickButtonOne(View v) {
Toast.makeText(TestViewInjectActivity.this, "test_view_inject_one", Toast.LENGTH_SHORT).show();
}

在 library module中

@ClickResponder(idStr = {"xxx","yyy"})
public void onClickButtonTwo(View v) {
Toast.makeText(TestViewInjectActivity.this, "test_view_inject_two", Toast.LENGTH_SHORT).show();
}

需要注意的是:方法的访问修饰符权限必须大于 protected,在方法使用前调用(一般是在OnCreate、onCreateView)ViewInjector.bind(this);

支持同一个方法绑定到多个view

@LongClickResponder

在 application module中

@LongClickResponder(idStr = {"test_view_inject_two"})
public void onLongClickButtonTwo(View v){
Toast.makeText(TestViewInjectActivity.this, "long click button two", Toast.LENGTH_SHORT).show();
}

在 library module 中

@LongClickResponder(id = R.id.test_long_click)

public void onLongClick(View v){
Toast.makeText(TestViewInjectActivity.this, "test_long_click", Toast.LENGTH_SHORT).show();
}

需要注意的是:方法的访问修饰符权限必须大于 protected,在方法使用前调用(一般是在OnCreate、onCreateView)ViewInjector.bind(this);

支持同一个方法绑定到多个view

@IntentValue

用来代替 getIntent().getXXX 或者Fragment中的getArguments().getXXX

使用方式:

@IntentValue(key = "String")
String value = "default"
@IntentValue(key = "parcelableObject",type = IntentValue.PARCELABLE_OBJECT)
ParcelableObject parcelableObject;
@IntentValue(key = "parcelableObjects" ,type = IntentValue.PARCELABLE_ARRAY_OBJECT)
ParcelableObject[] parcelableObjects;
@IntentValue(key = "parcelableObjectArrayList",type = IntentValue.PARCELABLE_ARRAYLIST_OBJECT)
ArrayList parcelableObjectArrayList;
@IntentValue(key = "serializableObject",type = IntentValue.SERIALIZABLE_OBJECT)
UnParcelableObject serializableObject;

注意:

如果传递的是Parcelable对象,type声明为IntentValue.PARCELABLE_OBJECT

如果传递的是Parcelable对象数组,type声明为IntentValue.PARCELABLE_ARRAY_OBJECT

如果传递的是Parcelable对象ArrayList,type声明为IntentValue.PARCELABLE_ARRAYLIST_OBJECT

如果传递的是序列化对象(实现了Serializable接口),type声明为IntentValue.SERIALIZABLE_OBJECT

在字段使用前(一般是在Activity的onCreate或者Fragment的onCreateView方法中)调用ViewInjector.parseBundle(this);

@UriValue

只支持如下几种类型,并且只能在Activity中使用

@UriValue(key = "name")
String name;
@UriValue(key = "id")
int id;
@UriValue(key = "double")
double aDouble;
@UriValue(key = "float")
float aFloat;
@UriValue(key = "long")
long aLong;
@UriValue(key = "boolean")
boolean aBoolean;

在字段使用前(一般是在Activity的onCreate方法中)调用ViewInjector.parseBundle(this);

@BroadcastResponder

广播分为本地广播和全局广播,注解接收广播接收器之后,需要自己去解注册

使用方式

public static final String NORMAL_LOCAL = "normal_local";
public static final String NORMAL_GLOBAL = "normal_global";
public static final String PERMISSION_GLOBAL = "permission_global";
public static final String BROADCAST_PERMISSION = "com.huangyuanlove.permission_broadcast";
//在 OnCreate 中注册广播接收器
HashMap> integerArrayListHashMap = ViewInjector.registerReceiver(this);
//使用注解定义接收广播的action 以及对应的回调方法
@BroadcastResponder(action = NORMAL_LOCAL)
void onReceiveNormalLocalBroadcast(Context context, Intent intent) {
showAction.setText("onReceiveNormalLocalBroadcast:"+intent.getAction());
}
@BroadcastResponder(action = NORMAL_GLOBAL,type = BroadcastResponder.GLOBAL_BROADCAST)
void onReceiveNormalGlobalBroadcast(Context context, Intent intent) {
showAction.setText("onReceiveNormalGlobalBroadcast:"+intent.getAction());
}
@BroadcastResponder(action = PERMISSION_GLOBAL,permission = BROADCAST_PERMISSION,type = BroadcastResponder.GLOBAL_BROADCAST)
void onReceivePermissionGlobalBroadcast(Context context, Intent intent) {
showAction.setText("onReceivePermissionGlobalBroadcast"+intent.getAction());
}
//在 onDestroy 中解注册
@Override
protected void onDestroy() {
super.onDestroy();
if(integerArrayListHashMap!=null){
ArrayList localReceiverList = integerArrayListHashMap.get(BroadcastResponder.LOCAL_BROADCAST);
if(localReceiverList!=null && localReceiverList.size()>0){
for(BroadcastReceiver receiver : localReceiverList){
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
ArrayList globalReceiverList = integerArrayListHashMap.get(BroadcastResponder.GLOBAL_BROADCAST);
if(globalReceiverList!=null && globalReceiverList.size()>0){
for(BroadcastReceiver receiver : globalReceiverList){
unregisterReceiver(receiver);
}
}
}
}
//发送广播
@ClickResponder(id= R.id.send_normal_local_broadcast)
public void sendNormalLocalBroadcast(View v){
Intent intent = new Intent();
intent.setAction(TestBroadcastActivity.NORMAL_LOCAL);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
@ClickResponder(id= R.id.send_normal_global_broadcast)
public void sendNormalGlobalBroadcast(View v){
Intent intent = new Intent();
intent.setAction(TestBroadcastActivity.NORMAL_GLOBAL);
sendBroadcast(intent);
}
@ClickResponder(id= R.id.send_permisson_global_broadcast)
public void sendPermissonGlobalBroadcast(View v){
Intent intent = new Intent();
intent.setAction(TestBroadcastActivity.PERMISSION_GLOBAL);
sendBroadcast(intent,TestBroadcastActivity.BROADCAST_PERMISSION);
}

以下是0.1.0版本的说明

//在 OnCreate 中注册广播接收器

HashMap broadcastReceiverHashMap = ViewInjector.registerReceiver(this);

//使用注解定义接收广播的action 以及对应的回调方法

@BroadcastResponder(action = {"com.huangyuanblog","com.huangyuanblog.www"})
public void onReceiveBroadcast(Context context, Intent intent){
Toast.makeText(context,intent.getAction(),Toast.LENGTH_SHORT).show();
}
//type默认本地广播,接收全局广播需要指定type = BroadcastResponder.GLOBAL_BROADCAST
@BroadcastResponder(action = {"com.huangyuanlove",Intent.ACTION_AIRPLANE_MODE_CHANGED},type = BroadcastResponder.GLOBAL_BROADCAST)
public void onReceiveBroadcastOther(Context context, Intent intent){
Toast.makeText(context,intent.getAction(),Toast.LENGTH_SHORT).show();
}

//在 onDestroy 中解注册

@Override
protected void onDestroy() {
super.onDestroy();
if(broadcastReceiverHashMap!=null){
if(broadcastReceiverHashMap.get(BroadcastResponder.GLOBAL_BROADCAST) !=null){
unregisterReceiver(broadcastReceiverHashMap.get(BroadcastResponder.GLOBAL_BROADCAST));
}
if(broadcastReceiverHashMap.get(BroadcastResponder.LOCAL_BROADCAST) !=null){
LocalBroadcastManager.getInstance(this).unregisterReceiver(broadcastReceiverHashMap.get(BroadcastResponder.LOCAL_BROADCAST));
}
}
}

需要注意的是,默认的广播接收器是本地广播,如果需要接收全局广播,比如打开飞行模式等,需要指定type = BroadcastResponder.GLOBAL_BROADCAST

千万别忘记解注册

@RouterModule and @RouterPath

相同的 schema 和 host 中不要有相同的path及path对应的方法名

相同的 schema 和 host 中不要有相同的path及path对应的方法名

相同的 schema 和 host 中不要有相同的path及path对应的方法名

在不同的Provider中提供相同的schema和host会导致Router被覆盖,无法保证路由目标的正确性。

一般以App的名字做schema,模块(module)的名字做host,目标Activity的类名做方法名及path。

比如App的名字为jandan,模块(module)名为 account,目标Activity的类名为LoginActivity

则对应Provider推荐这样写

@RouterModule(schema = "Jandan",host = "account")
public class AccountModuleRouterProvider {
@RouterPath(value = "login")
public void toLoginActivity(Context context, String userName){
Intent intent = new Intent(context,LoginActivity.class);
intent.put("userName",userName);
context.startActivity(intent);
}
}

//在其他类中使用

Router.to("Jandan://account/login").addParam(this,"userName").done(new Router.InvokeResultListener() {
@Override
public void onError(Exception e) {
Toast.makeText(EXT_MainActivity.this,e.toString(),Toast.LENGTH_SHORT).show();
}
@Override
public void onSuccess(Object o) {
}
});

Router的本质上是进行的方法调用,可以反依赖调用。就像工程中的app模块依赖example_lib模块,我们仍然可以在example_lib调用app中的方法。

当然正向调用也是可以的。

具体示例可以看example_lib中的EXT_MainActivity类调用app中MainProvider类方法

PermissionUtil

将要进行的动作,需要某项危险权限时,我们需要先校验权限 PermissionUtil.hasSelfPermissions

如果有权限,则进行动作。

如果没有权限,校验是否需要提示 PermissionUtil.shouldShowRequestPermissionRationale;如果需要提示,则弹出提示框,用户点了允许之后再申请权限。如果不需要提示,则直接申请权限;

申请权限的结果有三种:

授权onGrant

禁止onDenied

禁止并不在提示 onNeverAskAgain