前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >优雅的监听onActivityResult

优雅的监听onActivityResult

原创
作者头像
Clayman Twinkle
发布2019-09-09 14:43:53
2.1K0
发布2019-09-09 14:43:53
举报
文章被收录于专栏:Android原创

一、思考

当Activity A启动一个Activity B后,B finish,我们可能需要处理B返回的值,此时,我们可能就需要用到了onActivityResult,需要在Activity A中重写实现。 当然,在这种前提是我们处理逻辑都是放在Activity A类中,那么假如我们是在一个其他类,不是Activity或者Fragment的情况呢?

image.png
image.png

此时,我们可能会用到EventBus这种全局分发事件的方式来处理,但种感觉不够优雅。

当我看到Google的开源的lifecycle库中的HolderFragment的做法,感觉眼前一亮。在Activity或者Fragment中添加一个空壳的Fragment,作为一个生命周期的监听。

同样的,开源库Glide也有相似的设计。

image.png
image.png

这种方法挺好的。

所以我产生以下思路:通过给当前的Activity添加一个空壳的Fragment,往空壳的Fragment中传入Listener,然后由该Fragment去启动新的Activity,最终在这个空壳的FragmentonActivityResult中将结果传到Listener返回出去。

二、撸码

1、 首先,我们对外暴露一个Fragment需要实现的接口,让外部使用这个接口,而不是直接使用这个Fragment,做接口隔离。

代码语言:txt
复制
public interface ListenActivityResultRequest {
    void startActivity(Intent intent, int requestCode, OnActivityResultCallBack callBack);

    interface OnActivityResultCallBack {
        void onActivityResult(int resultCode, Intent data);
    }
}

该接口的方法提供一个startActivity,让外部传入intentrequestCode,还有处理onActivityReuslt的回调OnActivityResultCallBack

2、空壳Fragment的实现

(1)创建空壳Fragment

代码语言:txt
复制
    private static ListenActivityResultFragment createHolderFragment(FragmentManager fragmentManager) {
        ListenActivityResultFragment holder = new ListenActivityResultFragment();
        fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitNowAllowingStateLoss(); // need quickly
        return holder;
    }

(2)可能会已经存在有一个空壳Fragment,所以需要加一个查找的逻辑

代码语言:txt
复制
    private static ListenActivityResultFragment findHolderFragment(FragmentManager manager) {
        if (manager.isDestroyed()) {
            throw new IllegalStateException("Can't access FragmentManager from onDestroy");
        }

        Fragment fragmentByTag = manager.findFragmentByTag(HOLDER_TAG);
        if (fragmentByTag != null && !(fragmentByTag instanceof ListenActivityResultFragment)) {
            throw new IllegalStateException("Unexpected fragment instance was returned by HOLDER_TAG");
        }
        return (ListenActivityResultFragment) fragmentByTag;
    }

所以最终调用以上两个方法的方式是:

代码语言:txt
复制
    public static ListenActivityResultRequest holderFragmentFor(FragmentActivity activity) {
        return holderFragmentFor(activity.getSupportFragmentManager());
    }

    public static ListenActivityResultRequest holderFragmentFor(Fragment fragment) {
        return holderFragmentFor(fragment.getChildFragmentManager());
    }

    private static ListenActivityResultFragment holderFragmentFor(FragmentManager fm) {
        ListenActivityResultFragment holder = findHolderFragment(fm);
        if (holder == null) {
            holder = createHolderFragment(fm);
        }
        return holder;
    }

支持ActivityFragment两种情况,先执行查询,找不到再创建空壳Fragment

(3)实现ListenActivityResultRequest接口

代码语言:txt
复制
    private SparseArray<OnActivityResultCallBack> mCallBackMap = new SparseArray<>();

    @Override
    public void startActivity(Intent intent, int requestCode, OnActivityResultCallBack callBack) {
        mCallBackMap.put(requestCode, callBack);
        startActivityForResult(intent, requestCode);
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        OnActivityResultCallBack callBack = mCallBackMap.get(requestCode);
        if (callBack != null) {
            callBack.onActivityResult(resultCode, data);
        }
    }

这里使用一个字典SparseArray保存requestCode对应的OnActivityResultCallBack,根据实际需求情况,可以任意更改,这里只是举个栗子。

3、暴露给外提供的类

代码语言:txt
复制
public class ListenActivityProviders {
    public static ListenActivityResultRequest listenActivityResult(FragmentActivity activity) {
        return ListenActivityResultFragment.holderFragmentFor(activity);
    }

    public static ListenActivityResultRequest listenActivityResult(Fragment fragment) {
        return ListenActivityResultFragment.holderFragmentFor(fragment);
    }
}

名字随便取的,见谅见谅~

三、最终使用方式

代码语言:txt
复制
int requestCode = 1;
Intent intent = new Intent(context, XXActivity.class);
ListenActivityProviders.listenActivityResult(activity).startActivity(intent, requestCode, new OnActivityResultCallBack() {
	public void onActivityResult(int resultCode, Intent data) {
	// to handle result....
	}
});
image.png
image.png

四、结合Rxjava

可能需求逻辑会比较复杂,可能需要连续的处理,为了避免各种异步接口带了的“回调地狱”,我们可能可以在这里将接口改成RxjavaObservable

在以上实现的基础上,在ListenActivityResultRequest增加一个返回Observable的方法。

代码语言:txt
复制
Observable<ActivityResult> startActivity(Intent intent, int requestCode);

class ActivityResult {
    public final int resultCode;
    public final Intent data;
    ActivityResult(int resultCode, Intent data) {
        this.resultCode = resultCode;
        this.data = data;
    }
}

然后在空壳Fragment中实现:

代码语言:txt
复制
@Override
public Observable<ActivityResult> startActivity(Intent intent, int requestCode) {
    startActivityForResult(intent, requestCode);
    return Observable.create(emitter -> mCallBackMap.put(requestCode, new OnActivityResultCallBack() {
        @Override
        public void onActivityResult(int resultCode, Intent data) {
            emitter.onNext(new ActivityResult(resultCode, data));
            emitter.onComplete();
        }
    }));
}

五、拓展

同理,对于Android处理运行时权限,也可同样适用这样的思路。

有个开源库有这么实现

最终使用的方法:

代码语言:txt
复制
Activity that = this; // or fragment

String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};  // permissions

KPermission.of(that).requestPermissions(permissions, new IPermissionRequest.IPermissionCallback() { // request 
    @Override
    public void onResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // callback
        StringBuilder stringBuilder = new StringBuilder("onResult\n");
        for (int i = 0; i < permissions.length; i++) {
            stringBuilder.append(permissions[i].replaceFirst("android.permission.", ""))
                    .append(" is ")
                    .append(grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied");
        }
        Log.d("KPermission", stringBuilder.toString());
        Toast.makeText(getApplicationContext(), stringBuilder.toString(), Toast.LENGTH_SHORT).show();
    }
});
image.png
image.png

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、思考
  • 二、撸码
  • 三、最终使用方式
  • 四、结合Rxjava
  • 五、拓展
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档