编译时注解框架
新增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
相关博客
TODO
@BindView 代替 findViewById
@ClickResponder 代替 setOnClickListener
@LongClickResponder 代替 setOnLongClickListener
@IntentValue 代替 getIntent().getXXX
@UriValue 代替 getQueryParameter
@BroadcastResponder 代替 registerReceiver
@RouterModule、@RouterPath 来进行反依赖传递调用
PermissionUtil 申请权限