转载请表明出处:http://blog.youkuaiyun.com/q_probably/article/details/53906994
昨天早上上班的时候看郭婶儿的公众号,发现他居然要直播写代码,本着对大神的膜拜之情,迅速的报了名。下午下班以后,急匆匆的赶回家,在电脑面前静静的等待。昨天晚上讲的是Android 6.0 动态权限的处理已经封装,讲解的很详细,如果有需要的盆友可以去优快云上找相应的视频(应该是有的,因为昨天直播的时候,有优快云的管理人员说会有录像)。看完以后觉得,嗯,很不错。于是呢,今天早上来到公司以后就迫不及待的按照他的思路来自己去封装一下,还是很不错的。其实我们写代码就是这样了,看到好的东西一定要自己去动手尝试一下,这样我们才可以进步。
好了,不扯那么多废话了。下面就进入到我们的正题,首先呢,跟大家说一下,Android从6.0开始,在涉及到一些危险的权限,比如打电话,短信了之类 的,就不能只是在我们的AndroidManifest中简单配置一下就可以使用相应的功能了,这个相信大家都知道。那么,我们要怎么样来封装呢,首先,封装的目的是为了使用更加简洁,所以呢,最后的结果一定是使用起来很简单的。然后在用户操作完以后呢,我们还需要知道用户到底是授权了呢还是拒绝了呢,因为我们要根据这些来进行往后的操作。那么说道这里,不知道大家有没有想到一个机制,没错,就是回调机制。这个就不用多少了吧。我就直接贴代码了,然后根据代码来跟大家说
/** * Created by QQY on 2016/12/28 0028. * 权限申请的回调接口 */ public interface RequestPermissionListener { /** * 申请成功的回调方法 * */ void onSuccess(); /** * 用户拒绝的回调方法 * @param permissons 用户拒绝了哪些回调的数组 * */ void onDenies(String[] permissons); }
大家看到,我们定义了一个RequestPermissionListener的回调接口,在这个接口中有两个回调方法:
onSuccess(); 这是用户在授权了我们所有申请的权限以后会调用的
onDenies(String[] permissions); 这是用户拒绝了我们申请的某一个或者其中的几个或者全部的权限以后走的回调,这样说,只要用户不是对我们申请的所有的权限都允许,就会走这个方法,然后将用户拒绝的权限以String 数组的形式传回给我们。
我们知道,在申请权限的时候需要用到一个activity的上下文,下面我贴出一个我做项目中用到的一个Activity的管理器
import android.app.Activity; import java.util.ArrayList; import java.util.List; /** * Created by QQY on 2016/12/28 0028. * */ public class ActivityCollector { /**用于存放activity的集合*/ public static List<Activity> activities = new ArrayList<>(); /** * 将activity添加到集合中的方法 * @param activity * */ public static void addActivity(Activity activity) { activities.add(activity); } /** * 将activity移除集合的方法 * @param activity * */ public static void removeActivity(Activity activity) { activities.remove(activity); } /** * 获取栈顶activity的方法 * @return activity * */ public static Activity getTopActivity() { if (activities.isEmpty()) { return null; } return activities.get(activities.size() -1); } /** * 销毁掉所有在集合中的activity的方法 * */ public static void finishAllActivity() { for (Activity activity : activities) { if (!activity.isFinishing()) { activity.finish(); } } } }大家可以看到,里面的方法很简单。那么大家可能会有疑问,为什么要有一个获取栈顶activity的方法呢,原因是这样的,因为我们不能保证我们每次申请权限都是在activity中去做的,如果我们是在一个实体类中呢?那么就可以通过这个方法来获取到当前的avtivity的实例,从而调用相应的方法来申请权限。另外,我们还可以用这个来管理我们的activity,方便我们随时随地退出程序,只要我们在想要退出的时候调用finishAllActivity()方法就可以。当然了,前提是我们将我们所有的activity都加入到了这个集合中,也就是在所有的activity中都用了addActivity()方法。那么我们肯定不会在每个Activity中去写了,相信大家每个人的项目中都有一个BaseActivity吧,如果没有的话,那我估计你们老大就会找你单聊了。我们可以在我们BaseActivity的onCreate()方法中
ActivityCollector.addActivity(this);这样写,那么我们所有的Activity继承BaseActivity,就会自动执行这一行操作,就把我们的所有Activity添加到管理器中了。具体代码,一会儿会跟权限处理一起贴出来。那么看到这里,相信大家已经有眉目了,对啊,既然我们有BaseActivity,为什么不在BaseActivity中去处理权限呢,这样我们所有的activity就都可以使用了啊。是不是有一种恍然大悟的感觉。下面我将代码贴出:
** * Created by QQY on 2016/12/28 0028. * Activity的基类 */ public class BaseActivity extends AppCompatActivity { private static List<String> permissionLists = new ArrayList<>(); private static RequestPermissionListener requestlistener; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityCollector.addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); ActivityCollector.removeActivity(this); } /** * 动态申请权限的方法 * @param permissions 要申请的权限的数组,数组中的元素是要申请的权限的名字 * */ public static void requestRuntimePermissions(String[] permissions, RequestPermissionListener listener) { requestlistener = listener; if (permissions.length > 0) { for (String permission : permissions) { //如果当前应用没有此权限,就添加到集合中 if (ContextCompat.checkSelfPermission(ActivityCollector.getTopActivity(), permission) != PackageManager.PERMISSION_GRANTED) { permissionLists.add(permission); } } if (permissionLists.size() > 0) { //根据没有的权限集合去申请 ActivityCompat.requestPermissions(ActivityCollector.getTopActivity(), permissionLists.toArray(new String[permissionLists.size()]), 1); }else { return; } }else { return; } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); permissionLists.clear(); if (requestCode == 1 && grantResults.length > 0) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { Log.e("----->用户同意权限",permissions[i]); }else if (grantResults[i] == PackageManager.PERMISSION_DENIED){ Log.e("----->用户拒绝权限",permissions[i]); permissionLists.add(permissions[i]); } } if (permissionLists.size() == 0) { requestlistener.onSuccess(); }else { requestlistener.onDenies(permissionLists.toArray( new String[permissionLists.size()])); } } } }在这里大家可以看到,我新建了一个RequestRuntimePermissions()的方法,方法中接收两个参数,第一个是一个数组,即我们要申请的权限的数组。第二个是我们自定义的回调。
其次,我们还新建了一个集合,用来存放权限。还有一个全局的RequestPermissionListener回调接口,用来将我们请求的结果传递给调用者。
在进入方法后,首先给全局的listener赋值,然后我们需要判断传入的数组的长度,如果是大于0的,那么就执行下面的代码。那么有人问了,为什么还要加一个判断啊,那我只能告诉你,避免数组越界异常,因为这个异常跟空指针是一样的,会导致程序的崩溃,所以我们还是要加一个判断的。如果是长度是0,直接return即可。如果不是0,
for (String permission : permissions) { //如果当前应用没有此权限,就添加到集合中 if (ContextCompat.checkSelfPermission(ActivityCollector.getTopActivity(), permission) != PackageManager.PERMISSION_GRANTED) { permissionLists.add(permission); }
在这里,我们对传入的权限的数组进行了遍历,并且判断当前应用有没有该权限,没有的话就添加到集合中。
if (permissionLists.size() > 0) { //根据没有的权限集合去申请 ActivityCompat.requestPermissions(ActivityCollector.getTopActivity(), permissionLists.toArray(new String[permissionLists.size()]), 1); }else { return;
然后我们就去判断,集合的长度,如果大于0说明我们有要申请的权限,那么我们就调用对应的API去申请权限。
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); permissionLists.clear(); if (requestCode == 1 && grantResults.length > 0) { for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { Log.e("----->用户同意权限",permissions[i]); }else if (grantResults[i] == PackageManager.PERMISSION_DENIED){ Log.e("----->用户拒绝权限",permissions[i]); permissionLists.add(permissions[i]); } } if (permissionLists.size() == 0) { requestlistener.onSuccess(); }else { requestlistener.onDenies(permissionLists.toArray( new String[permissionLists.size()])); } } }接着,我们重新了onRequestPermissionsResult方法,该方法中有三个参数,第一个是requestcode,这个参数对应我们申请权限时候的requestcode。第二个是权限的数组,第三个是申请结果的数组,每一个权限对应一个结果。然后我们将上面提到的集合清空。接着,我们去遍历返回的结果,如果用户同意了,就不做处理,如果用户拒绝了,就将用户拒绝的权限放到集合中。等到循环完毕以后,再判断集合的长度,如果是0,说明用户对我们所有的申请的权限都同意了,那么我们调用我们自定义接口中的onSuccess方法。如果大于0,说明用户拒绝了某些权限,并且我们已经将这些拒绝的权限放到了集合中,那么我们就调用onDenies方法,并将集合转成数组,传回给调用者。
至此,就已经封装完毕,我们现在只需要在需要申请权限的地方这样调用:
String[] permissions = {Manifest.permission.CALL_PHONE,Manifest.permission. WRITE_EXTERNAL_STORAGE,Manifest.permission.SEND_SMS}; requestRuntimePermissions(permissions, new RequestPermissionListener() { @Override public void onSuccess() { } @Override public void onDenies(String[] permissons) { } });
当然了,这是在Activity中用。如果我们想要在一个实体类中调用,也很简单,我们先获取到当前栈顶的Activity
BaseActivity activity = ActivityCollector.getTopActivity();
activity.requestRuntimePermissions();
即可。
最后提醒一下:虽然我们动态申请权限,但是要申请的权限还是要在AndroidManifest中去声明一下的。切记。
好了,就写到这里了。还是那句话,不喜勿喷。
转载请表明出处,谢谢。