必威体育Betway必威体育官网
当前位置:首页 > IT技术

更优雅的使用startActivityForResult及权限请求

时间:2019-08-14 00:44:26来源:IT技术作者:seo实验室小编阅读:78次「手机版」
 

startactivityforresult

一、问题所在

Android页面之前的数据回传我们一般使用startActivityForResult来处理,这没什么问题,但问题就在于我们所有的处理结果都放在onActivityResult中,在里面根据不同的requestcode作不同处理,这种方式看起来非常不优雅,因为有时候onActivityResult里面逻辑一大堆,而且跟调用方距离相差甚远,代码对应非常麻烦,找着找着就不知道找到哪里去了。

所以我们迫切的希望能够像setOnClickListener一样能直接设置回调,在调用的地方顺便处理调用后的逻辑,这样能够使得代码逻辑清晰明了,不用再一一去判断requestCode。

二、解决方式

1、使用辅助类方式(不完美)

新建OnResultManager类,用来管理获取结果的回调。

即在startActivityForResult的时候就传入Callback,实现要处理的逻辑,在管理类中将该Callback进行存储,跟requestCode一一对应,在处理结果回来之后根据requestCode取出相应的Callback进行回调,下面是详细代码

public class OnResultManager {
    //使用弱引用,减少内存泄漏
    private weakreference<Activity> mActivityWeakReference;
    //根据不同requestCode缓存callback
    private SparseArray<OnResultCallback> mCallbacks = new SparseArray<>();

    public OnResultManager(Activity activity) {
        mActivityWeakReference = new WeakReference<>(activity);
    }

    /**
     * 使用该方法去进行startActivityForResult
     *
     * @param requestCode
     * @param intent
     * @param callback
     */
    public void startActivityForResult(int requestCode, Intent intent, OnResultCallback callback) {
        Activity activity = getActivity();
        if (activity == null) {
            return;
        }
        addCallback(requestCode, callback);
        activity.startActivityForResult(intent, requestCode);
    }


    /**
     * 需要在Activity的onActivityResult中调用该方法,可以放在BaseActivity中
     *
     * @param requestCode
     * @param resultCode
     * @param data
     */
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Activity activity = getActivity();
        if (activity == null) {
            return;
        }
        OnResultCallback onResultCallback = findCallback(requestCode);
        if (onResultCallback != null) {
            onResultCallback.onActivityResult(requestCode, resultCode, data);
        }
    }

    /**
     * 添加callback
     *
     * @param requestCode
     * @param callback
     */
    private void addCallback(int requestCode, OnResultCallback callback) {
        mCallbacks.put(requestCode, callback);
    }

    private Activity getActivity() {
        return mActivityWeakReference.get();
    }

    /**
     * 查找callback,如果查找到就移除
     *
     * @param requestCode
     * @return
     */
    private OnResultCallback findCallback(int requestCode) {
        OnResultCallback onResultCallback = mCallbacks.get(requestCode);
        mCallbacks.remove(requestCode);
        return onResultCallback;
    }

    public interface OnResultCallback {
        void onActivityResult(int requestCode, int resultCode, Intent data);
    }

    public static class Requestconstants {
        public static final int REQUEST_CODE_1 = 1;
        public static final int REQUEST_CODE_2 = 2;
        public static final int REQUEST_CODE_3 = 3;
    }
}

上面逻辑很简单,就是根据不同requestCode缓存Callback,所以我们最终是使用该辅助类去调用startActivityForResult,那怎么触发取callback的操作呢,这个还是需要在对应的Activity的onActivityResult方法中调用该辅助类对应的onActivityResult方法,当然我们可以在BaseActivity中统一调用

public abstract class BaseActivity extends APPCompatActivity {
    protected context mContext;
    protected OnResultManager mOnResultManager;

    @Override
    protected void onCreate(@Nullable Bundle savedinstanceState) {
        super.onCreate(savedInstanceState);
        mContext = this;
        if (isNeedResultManager()) {
            mOnResultManager = new OnResultManager(this);
        }
    }

    //子类如果需要startActivity回传数据可重写该方法返回true
    protected boolean isNeedResultManager() {
        return false;
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //手动调用辅助类的onActivityResult方法
        if (mOnResultManager != null) {
            mOnResultManager.onActivityResult(requestCode, resultCode, data);
        }
    }
}

没错,就是这么Easy,下面来看使用吧

Intent intent = new Intent(this, ResultTestActivity.class);
                mOnResultManager.startActivityForResult(OnResultManager.RequestConstants.REQUEST_CODE_1, intent, new OnResultManager.OnResultCallback() {
                    @Override
                    public void onActivityResult(int requestCode, int resultCode, Intent data) {
                        //能够做到在当前代码处处理逻辑,就像setOnClickListener简单
                        if (resultCode == RESULT_OK) {
                            toastUtils.showToast("收到result");
                        }
                    }
                });

2、使用工具类方式 加 不可见的Fragment方式(完美)

上面第一种方式看起来似乎很友好,但是仍然不够优雅,为什么呢?我们的目的是让使用者使用起来更加方便,但显然上面的方式不仅需要处理当前Activity业务逻辑,还要new对象,还要侵入BaseActivity代码,要是使用者的activity没继承BaseActivity或者项目中根本没有BaseActivity的存在,那么难道需要在自己的Activity中一一配置吗?岂不是并没有达到简化代码和逻辑的目的。

所以接下来我们的目的是让使用者只关心自己要处理自己的业务逻辑就行,那么做法就是加一层不可见的Fragment,在这个不可见的Fragment中处理onActivityResult,其实很多第三方都是这样做的,减少了业务层的逻辑。

public class OnResultManagerByFragment {
    private static String TAG = "OnResultFragment";

    private static OnResultFragment getOnResultFragment(Activity activity) {
        OnResultFragment onResultFragment = findOnResultFragment(activity);
        if (onResultFragment == null) {
            onResultFragment = new OnResultFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager.begintransaction().add(onResultFragment, TAG).commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return onResultFragment;
    }

    private static OnResultFragment findOnResultFragment(Activity activity) {
        return (OnResultFragment) activity.getFragmentManager().findFragmentByTag(TAG);
    }

    public static void startActivityForResult(Fragment fragment, Intent intent, int requestCode, OnResultManager.OnResultCallback callback) {
        startActivityForResult(fragment.getActivity(), intent, requestCode, callback);
    }

    public static void startActivityForResult(Activity activity, Intent intent, int requestCode, OnResultManager.OnResultCallback callback) {
        getOnResultFragment(activity).startActivityForResult(intent, requestCode, callback);
    }

    public static Observable<ActivityResultInfo> startActivityForResult(Fragment fragment, Intent intent, int requestCode) {
        return startActivityForResult(fragment.getActivity(), intent, requestCode);
    }

    //这个是使用Rxjava方式,作为参考
    public static Observable<ActivityResultInfo> startActivityForResult(Activity activity, Intent intent, int requestCode) {
        return getOnResultFragment(activity).startActivityForResultRx(intent, requestCode);
    }
}

对应的fragment类

public class OnResultFragment extends Fragment {
    private SparseArray<OnResultManager.OnResultCallback> mCallbacks = new SparseArray<>();
    private SparseArray<Publishsubject<ActivityResultInfo>> mSubjects = new SparseArray<>();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置fragment保留,已保留的fragment(在异常情况下)不会随着activity一起销毁,相反,它会一直保留(进程不消亡的前提下)
        //比如在设备旋转的情况下,该fragment可暂时与Activity分离,等activity重新创建后,会将该fragment与activity重新绑定,fragment数据不会丢失
        //如果在恰好在分离的那段时间使用Context信息,就可能会出错,这时可以使用isAdded()判断Fragment是否绑定到Activity
        
        //如果Activity正常销毁,fragment也会销毁
        setRetainInstance(true);
    }

    public void startActivityForResult(Intent intent, int requestCode, OnResultManager.OnResultCallback callback) {
        mCallbacks.put(requestCode, callback);
        startActivityForResult(intent, requestCode);
    }

    public Observable<ActivityResultInfo> startActivityForResultRx(final Intent intent, final int requestCode) {
        PublishSubject<ActivityResultInfo> publishSubject = PublishSubject.create();
        mSubjects.put(requestCode, publishSubject);
        return publishSubject.doOnSubscribe(new consumer<Disposable>() {
            @Override
            public void accept(Disposable disposable) throws Exception {
                startActivityForResult(intent, requestCode);
            }
        });
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        PublishSubject<ActivityResultInfo> subject = mSubjects.get(requestCode);
        if (subject != null) {
            mSubjects.remove(requestCode);
            subject.onNext(new ActivityResultInfo(requestCode, resultCode, data));
            subject.onComplete();
        }

        //callback方式的处理
        OnResultManager.OnResultCallback onResultCallback = mCallbacks.get(requestCode);
        if (onResultCallback != null) {
            mCallbacks.remove(requestCode);
            onResultCallback.onActivityResult(requestCode, resultCode, data);
        }
    }
}

使用方式类似,非常简单

 Intent intent = new Intent(this, OthersActivity.class);                XStartActivityForResult.startActivityForResult(this, intent, 1, new OnResultCallback() {
                    @Override
                    public void onActivityResult(int requestCode, int resultCode, Intent data) {
                        if (resultCode == RESULT_OK) {
                            toast.maketext(MainActivity.this, "收到数据", Toast.LENGTH_SHORT).show();
                        }
                    }
                });

//rxjava方式
 Intent intent2 = new Intent(this, OthersActivity.class);
                XStartActivityForResult.startActivityForResultRx(this, intent2, 2)
                        .filter(new Predicate<ActivityResultInfo>() {
                            @Override
                            public boolean test(ActivityResultInfo activityResultInfo) throws Exception {
                                return activityResultInfo.resultCode == RESULT_OK;
                            }
                        })
                        .subscribe(new Consumer<ActivityResultInfo>() {
                            @Override
                            public void accept(ActivityResultInfo activityResultInfo) throws Exception {
                                Toast.makeText(MainActivity.this, "收到数据", Toast.LENGTH_SHORT).show();
                            }
                        });
                break;

三、以此类推

在android中很多情况下都是请求和响应都是异步的,需要在不同地方进行处理,那么我们也可以按照这种方式处理,比如权限申请,权限申请我这边也写了类似的代码,思路相同

public class permissionManagerByFragment {
    private static String TAG = "PermissionManagerByFragment";

    private static OnPermissionFragment getOnPermissionFragment(Activity activity) {
        OnPermissionFragment onPermissionFragment = findOnPermissionFragment(activity);
        if (onPermissionFragment == null) {
            onPermissionFragment = new OnPermissionFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager.beginTransaction().add(onPermissionFragment, TAG).commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return onPermissionFragment;
    }

    private static OnPermissionFragment findOnPermissionFragment(Activity activity) {
        return (OnPermissionFragment) activity.getFragmentManager().findFragmentByTag(TAG);
    }

    private static boolean checkPermission(Activity activity, String[] permissions) {
        for (String permission : permissions) {
            int permissionCheck = ContextCompat.checkSelfPermission(activity, permission);
            if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    private static String shouldShowRequestPermissionRationale(Activity activity, String[] permissions) {
        for (String permission : permissions) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                return permission;
            }
        }
        return null;
    }

    public static void permissionRequest(Fragment fragment, int requestCode, OnPermissionCallback callback) {
        permissionRequest(fragment.getActivity(), requestCode, callback);
    }

    public static void permissionRequest(Activity activity, int requestCode, OnPermissionCallback callback) {
        String[] permissions = PermissionSparseArray.getInstance().get(requestCode);
        if (checkPermission(activity, permissions) || build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            callback.onPermissionGranted(requestCode);
        } else {
            String requestPermissionRationale = shouldShowRequestPermissionRationale(activity, permissions);
            if (requestPermissionRationale != null) {
                Dialog hintDialog = callback.makeHintDialog(requestPermissionRationale, requestCode);
                if (hintDialog != null) {
                    hintDialog.show();
                }
            } else {
                getOnPermissionFragment(activity).permissionRequest(requestCode, callback);
            }
        }
    }


    public interface OnPermissionCallback {
        void onPermissionGranted(int reqCode);

        void onPermissiondenied(String deniedPermission, int reqCode);

        Dialog makeHintDialog(String requestPermissionRationale, int reqCode);
    }

}
public class OnPermissionFragment extends Fragment {
    private SparseArray<PermissionManagerByFragment.OnPermissionCallback> mCallbacks = new SparseArray<>();

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置fragment保留,已保留的fragment(在异常情况下)不会随着activity一起销毁,相反,它会一直保留(进程不消亡的前提下)
        //比如在设备旋转的情况下,该fragment可暂时与Activity分离,等activity重新创建后,会将该fragment与activity重新绑定,fragment数据不会丢失
        //如果在恰好在分离的那段时间使用Context信息,就可能会出错,这时可以使用isAdded()判断Fragment是否绑定到Activity
        setretainInstance(true);
    }

    @requiresApi(api = Build.VERSION_CODES.M)
    public void permissionRequest(int requestCode, PermissionManagerByFragment.OnPermissionCallback callback) {
        mCallbacks.put(requestCode, callback);
        String[] permissions = PermissionSparseArray.getInstance().get(requestCode);
        requestPermissions(permissions, requestCode);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        PermissionManagerByFragment.OnPermissionCallback callback = findCallback(requestCode);
        if (callback != null) {
            boolean granted = true;
            String deniedPermission = "";
            for (int i = 0; i < grantResults.length; i++) {
                int grantResult = grantResults[i];
                granted = grantResult == PackageManager.PERMISSION_GRANTED;
                if (!granted) {
                    deniedPermission = permissions[i];
                    break;
                }
            }
            if (granted) {
                callback.onPermissionGranted(requestCode);
            } else {
                callback.onPermissionDenied(deniedPermission, requestCode);
            }
        }
    }

    private PermissionManagerByFragment.OnPermissionCallback findCallback(int requestCode) {
        PermissionManagerByFragment.OnPermissionCallback onPermissionCallback = mCallbacks.get(requestCode);
        mCallbacks.remove(requestCode);
        return onPermissionCallback;
    }
}
public class PermissionSparseArray extends SparseArray<String[]> {
// 权限请求标识
    public static final int PERMISSION_STORAGE = 1;
    public static final int PERMISSION_CAMERA = 2;
    public static final int PERMISSION_CONTACTS = 3;
    public static final int PERMISSION_calendar = 4;
    public static final int PERMISSION_LOCATION = 5;
    public static final int PERMISSION_MICROPHONE = 6;
    public static final int PERMISSION_PHONE = 7;
    public static final int PERMISSION_SENSORS = 8;
    public static final int PERMISSION_SMS = 9;


    @IntDef({PERMISSION_STORAGE, PERMISSION_CAMERA, PERMISSION_CONTACTS, PERMISSION_CALENDAR, PERMISSION_LOCATION, PERMISSION_MICROPHONE, PERMISSION_PHONE, PERMISSION_SENSORS, PERMISSION_SMS})
    @Retention(RetentionPolicy.SOURCE)
    public @interface PermissionRequestCode {

    }

    private static PermissionSparseArray sPermissionArray = new PermissionSparseArray();

    private PermissionSparseArray() {
        //Storage
        String[] storage = {
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE};
        this.put(PERMISSION_STORAGE, storage);

        String[] camera = {Manifest.permission.CAMERA};
        this.put(PERMISSION_CAMERA, camera);

        String[] contacts = {
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.WRITE_CONTACTS,
                Manifest.permission.GET_ACCOUNTS};
        this.put(PERMISSION_CONTACTS, contacts);

        String[] calendar = {
                Manifest.permission.READ_CALENDAR,
                Manifest.permission.WRITE_CALENDAR};
        this.put(PERMISSION_CALENDAR, calendar);


        String[] location = {
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION};
        this.put(PERMISSION_LOCATION, location);

        String[] microphone = {Manifest.permission.RECORD_AUDIO};
        this.put(PERMISSION_MICROPHONE, microphone);


        String[] phone = {
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.CALL_PHONE,
                Manifest.permission.READ_CALL_LOG,
                Manifest.permission.WRITE_CALL_LOG,
                Manifest.permission.ADD_VOICEMAIL,
                Manifest.permission.USE_SIP,
                Manifest.permission.PROCESS_OUTGOING_CALLS};
        this.put(PERMISSION_PHONE, phone);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
            String[] sensors = {Manifest.permission.BODY_SENSORS};
            this.put(PERMISSION_SENSORS, sensors);
        }

        String[] sms = {
                Manifest.permission.SEND_SMS,
                Manifest.permission.RECEIVE_SMS,
                Manifest.permission.READ_SMS,
                Manifest.permission.RECEIVE_WAP_PUSH,
                Manifest.permission.RECEIVE_MMS};
        this.put(PERMISSION_SMS, sms);
    }

    public static PermissionSparseArray getInstance() {
        return sPermissionArray;
    }

    public static String[] mergePermissionArrays(@PermissionRequestCode int... requestCode) {
        int totalLength = 0;
        int length = requestCode.length;
        for (int i = 0; i < length; i++) {
            totalLength += getInstance().get(requestCode[i]).length;
        }
        String[] newArray = new String[totalLength];
//        public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
        int lastIndex = 0;
        for (int i = 0; i < length; i++) {
            int i1 = requestCode[i];
            String[] strings = getInstance().get(i1);
            System.arraycopy(strings, 0, newArray, lastIndex, strings.length);
            lastIndex = strings.length;
        }
        return newArray;
    }

使用

if (mStoragePermissionCallback == null) {
                    mStoragePermissionCallback = new OnPermissionCallback() {
                        @Override
                        public void onPermissionGranted(int reqCode) {
                            Toast.makeText(MainActivity.this, "存储权限请求成功", Toast.LENGTH_SHORT).show();
                        }

                        @Override
                        public void onPermissionDenied(String deniedPermission, int reqCode) {
                            Toast.makeText(MainActivity.this, "存储权限请求失败", Toast.LENGTH_SHORT).show();
                        }

                        @Override
                        public void shouldShowRequestPermissionTip(String requestPermissionRationale, int reqCode) {
                            XPermission.showTipDialog(MainActivity.this, "设置权限", "提示用户权限的作用");
                        }
                    };
                }
                XPermission.permissionRequest(MainActivity.this, PermissionSparseArray.PERMISSION_STORAGE, mStoragePermissionCallback);

延伸:可以将本文讲的看成一种处理问题的一种方式,以后遇到类似问题可以类似处理,优化代码方式,写着方便,看着方便。比如权限问题也跟这个类似,可以按照类似方式处理。

目前该项目代码已上传至github,上面博客的代码跟github代码可能有些出入,需要查看详细代码请移步我的github

XstartActivityForResultAndXPermission

相关阅读

分享到:

栏目导航

推荐阅读

热门阅读