一直以来我对于权限申请这方面我都是在用着谷歌官方开源的EasyPermissions这个库,其实它的内部算是比较简单,内部是把一些Android SDK自带的权限方法封装了起来。如果只是想看关于这个库的使用,可以看一下我之前写的一篇博客App实战:动态申请权限以及为所欲为之终极扩展。这里首先我对这个库的流程做一个总结,如下图所示:
虽然说逻辑上比较简单,但是我们现在很多App都是在动态申请权限,所以说用到的地方多了还是回感觉到有一些繁琐的。所以我想给EasyPermissions进行二次封装,目的当然是为了简单易用。那么如何封装呢?
首先回到封装的定义:隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体。反正我是看到这个定义后我就明白了,封装就是你把程序需要的参数传进去,里面怎么处理外部不需要操心就能得到一个结果。所以第一步是要弄清楚权限申请需要什么参数,要想弄清楚需要什么参数就得知道EasyPermissions这一套下来调用那些方法。我们一一来理清楚:
/**
* Check if the calling context has a set of permissions.
*
* @param context the calling context.
* @param perms one ore more permissions, such as {@link Manifest.permission#CAMERA}.
* @return true if all permissions are already granted, false if at least one permission is not
* yet granted.
* @see Manifest.permission
*/
public static boolean hasPermissions(Context context, @NonNull String... perms)
需要context和你需要申请的权限。2个参数。
public static void requestPermissions(@NonNull Fragment host, @NonNull String rationale,
int requestCode, @NonNull String... perms) {
requestPermissions(host, rationale, android.R.string.ok, android.R.string.cancel,
requestCode, perms);
}
这里需要注意的是我申请权限的地方是在一个内部fragment,这个方案也是来自网络开源,据说最早使用的是Rxpermission库。需要一个fragment(不算,这个不是外部传进去的),一个rationale权限解释和一个requestCode请求码。2个参数。
/**
* Callback interface to receive the results of {@code EasyPermissions.requestPermissions()}
* calls.
*/
public interface PermissionCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback {
void onPermissionsGranted(int requestCode, List perms);
void onPermissionsDenied(int requestCode, List perms);
}
1个参数。
所以加起来一个有5个参数,如果按照正常的封装大概就是PermissionHelper.request(param1,param2,param3,param4,param5,);,但是很显然一个方法参数多了会导致调用者不太舒服的,所以我采用了builder建造者模式。这里面没有什么难点,需要注意的是空UI的Fragment的创建方法是如下所示的:
public static void addNoUiFgToActivity(@NonNull FragmentManager fragmentManager, @NonNull Fragment fragment,
String tag)
{
checkNotNull(fragmentManager);
checkNotNull(fragment);
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(fragment, tag);
transaction.commit();
}
并且我在里面利用的这个空Fragment来申请权限,所以这个Fragment需要实现EasyPermissions.PermissionCallbacks接口。还有一点EasyPermissions.PermissionCallbacks接口里面有3个方法,而我只需要其中两个,所以写了一个抽象类实现了其中一个空方法
public abstract static class PermissionListener implements EasyPermissions.PermissionCallbacks
{
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
grantResults)
{
}
}
我们传入的5个参数中的那个回调参数就是实现这个匿名内部类。这里记一下最开始犯的一个很zz的错误,就是我想把这个参数传递给Fragment的时候,我采用了setArgument的方式,然后很sb的让这个抽象类实现Serializable接口就是序列化,后面就有一直报错。请教了一下大佬,大佬也是说我是不是对序列化有什么误解,确实是自己对这块没理解深刻。Java序列化:Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。
图就不上了,可以看以前的那篇博客,效果都是一样的。最后针对录音权限代码调用如下,真的非常简单了,多权限申请也是一样的,因为权限参数是一个String数组:
public static final int RECORD_CODE = 1;
String[] recordPerm = {Manifest.permission.RECORD_AUDIO};
private void record()
{
PermissionHelper.init(this)
.permissions(recordPerm)
.rationale("录音权限")
.requestCode(RECORD_CODE)
.permissionListener(new PermissionHelper.PermissionListener()
{
@Override
public void onPermissionsGranted(int requestCode, List perms)
{
//权限已授予
}
@Override
public void onPermissionsDenied(int requestCode, List perms)
{
//权限被拒绝,或者点击解释框取消按钮时都会调用此方法
}
}).build().request();
}
整个帮助类的代码如下:
public class PermissionHelper
{
public static final String TAG = "PermissionHelper";
private Context mContext;
private String[] mPerms;
private PermissionListener mPermissionListener;
private String mRationale;
private int mRequestCode;
private PermissionFragment mPermissionFragment;
private List permsList;
public static Builder init(FragmentActivity context)
{
Builder mBuilder = new Builder(context);
return mBuilder;
}
private PermissionHelper(Builder builder)
{
mContext = builder.mContext;
mPerms = builder.mPerms;
mPermissionListener = builder.mPermissionListener;
mRationale = builder.mRationale;
mRequestCode = builder.mRequestCode;
mPermissionFragment = builder.mPermissionFragment;
permsList = builder.permsList;
}
public void request()
{
if (EasyPermissions.hasPermissions(mContext, mPerms))
{
mPermissionListener.onPermissionsGranted(mRequestCode, permsList);
} else
{
Observable.timer(50, TimeUnit.MILLISECONDS).subscribe(new Consumer()
{
@Override
public void accept(Long aLong) throws Exception
{
EasyPermissions.requestPermissions(mPermissionFragment, mRationale, mRequestCode, mPerms);
}
});
}
}
public static class Builder
{
private FragmentActivity mContext;
private String[] mPerms;
private PermissionListener mPermissionListener;
private String mRationale;
private int mRequestCode;
private PermissionFragment mPermissionFragment;
private List permsList = new ArrayList<>();
public Builder(FragmentActivity context)
{
this.mContext = context;
}
public Builder permissionListener(PermissionListener perssionListener)
{
this.mPermissionListener = perssionListener;
return this;
}
public Builder permissions(String[] pers)
{
this.mPerms = pers;
for (String perm : mPerms)
{
permsList.add(perm);
}
return this;
}
public Builder rationale(String rationale)
{
this.mRationale = rationale;
return this;
}
public Builder requestCode(int requestCode)
{
this.mRequestCode = requestCode;
return this;
}
public PermissionHelper build()
{
FragmentManager fragmentManager = mContext.getSupportFragmentManager();
mPermissionFragment = (PermissionFragment) fragmentManager.findFragmentByTag(TAG);
if (mPermissionFragment == null)
{
mPermissionFragment = PermissionFragment.newInstance();
mPermissionFragment.setPermissionListener(mPermissionListener);
ActivityUtils.addNoUiFgToActivity(fragmentManager, mPermissionFragment, TAG);
}
return new PermissionHelper(this);
}
}
public abstract static class PermissionListener implements EasyPermissions.PermissionCallbacks
{
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
grantResults)
{
}
}
public static class PermissionFragment extends Fragment implements EasyPermissions.PermissionCallbacks
{
PermissionListener mPermissionCallbacks;
public static PermissionFragment newInstance()
{
Bundle args = new Bundle();
PermissionFragment fragment = new PermissionFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
public void setPermissionListener(PermissionListener permissionListener)
{
this.mPermissionCallbacks = permissionListener;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
L.e("onActivityCreated(" + TAG + ".java:" + Thread.currentThread().getStackTrace()[2].getLineNumber() +
")" + "");
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
grantResults)
{
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, mPermissionCallbacks);
}
@Override
public void onPermissionsGranted(int requestCode, List perms)
{
mPermissionCallbacks.onPermissionsGranted(requestCode, perms);
}
@Override
public void onPermissionsDenied(int requestCode, List perms)
{
mPermissionCallbacks.onPermissionsDenied(requestCode, perms);
}
}
}
重温了下Android中对权限申请的机制,学习了空Fragment的使用,更加明白了封装的含义,也知道了Java序列化的基本机制。更加开心的是,每一次用着自己亲自动手封装的东西,真的那种愉悦感是很爽的啊。
Github Demo
如果对你有帮助,不要吝啬你的赞哦。
上一篇博客:
App实战:夜间模式实现方法一
下一篇博客:Android Studio一些使用技巧