大胸弟 requestCode还在困扰你嘛

开发中遇到的问题

呀哟 大胸弟

界面传值

在开发中,当在一个A界面(Activity)中打开B界面(Activity),如果想要B->A传值的情况有很多。但是这种所有获取到的结果都需要到onActivityResult中处理的方式实在令人蛋疼。

15697582283234

界面 A

int mRequestCode = xxx;//定义 requestCode 
context.startActivityForResult(intent, requestCode);

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == mRequestCode){ //判断 requestCode
        //执行
    }
}

界面 B

Intent intent = Intent()
intent.putExtra("text",text.text.toString())
setResult(Activity.RESULT_OK,intent)
finish();

打开相册

要写如下的代码,先要权限检查,又要监听界面的回调。

private final static int REQUEST_CODE = 100;
private final static int PERMISSION_REQUEST_CODE = 200;

//打开相册
private void openPic(){
  //1.检查权限,并请求权限
  checkPermission();
}

private void checkPermission(){
    //首先进行权限判断,和请求
    //先  check
    //然后 requestPermissions
    ...
}

//处理权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    //判断请求码
    if(requestCode==PERMISSION_REQUEST_CODE){
         if(有权限){
            //在拥有权限的情况下:打开系统的选择图片界面
            Intent intentToPickPic = new Intent(Intent.ACTION_PICK, null);
            intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg");
            startActivityForResult(intentToPickPic, REQUEST_CODE);
        }
    }
}

//当拍摄照片完成时会回调到onActivityResult 在这里处理照片的裁剪或其他的操作
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (resultCode == RESULT_OK) {
        switch (requestCode) {
            case REQUEST_CODE: {
               //处理图片逻辑
               ...
               break;
            }
        }
    }
    super.onActivityResult(requestCode, resultCode, data);
}

还有一些判断等等,写起来特别麻烦。需要自己定义requestCode,然后重写onRequestPermissionsResult 和 onActivityResult 方法,然后在处理一堆逻辑!

风好大我好冷

试想一下,我们敲着代码唱着歌。突然,半路上跳出一群马匪,让我们到另一个页面获取一点数据,获取后还不让在当前代码位置处理逻辑,要去onActivityResult添加一个requestCode分支处理结果,处理完才让回来,等这一切都做完回来难免就会陷入这样的思考:我是谁,我在哪,我在干什么,我刚才写到哪了……

那么有没有一种解决方法呢?

终极解决方案 AvoidOnResultHelper

我们先来看看怎么使用,然后在讲解原理!

使用方法

在子项目中的 build.gradle 文件中添加

dependencies {
    implementation 'vip.ruoyun.helper:avoid-onresult-helper:1.0.3'
}

开启 Activity

Intent intent = new Intent();
AvoidOnResultHelper.startActivityForResult(this, intent, new AvoidOnResultHelper.ActivityCallback() {
    @Override
    public void onActivityResult(int resultCode, Intent data) {
        //处理操作
    }
});

请求权限

String[] permissions = {};
AvoidOnResultHelper.requestPermissions(this, permissions, new AvoidOnResultHelper.PermissionsCallBack() {
    @Override
    public void onRequestPermissionsResult(@NonNull String[] permissions, @NonNull int[] grantResults) {
        //处理逻辑
    }
});

介绍到此处是不是感觉减少了好多代码?连requestCode 都不需要定义!~~

框架内部定义好了连requestCode,如果在开发中感觉和现有的 requestcode 冲突的话,可以设置 RequestCodeRange 范围,轻松解决问题,设置代码如下:

AvoidOnResultHelper.setRequestCodeRange(65000, 65535);

除了上面这些功能外,还有那些好用的功能?

可以监听当前 activity 的生命周期.

public interface LifecycleListener {

    void onStart();//开始

    void onStop();//结束

    void onDestroy();//销毁
}

LifecycleListenerWrapper 是此接口的空实现.

//添加监听事件
LifecycleListener lifecycleListener = new LifecycleListener.LifecycleListenerWrapper() {
    @Override
    public void onStart() {
    }
};
//添加监听事件
AvoidOnResultHelper.addLifecycleListener(this, lifecycleListener);

//粘性通知,当第一次添加的时候,就执行相应的回调方法
AvoidOnResultHelper.addLifecycleListener(this, lifecycleListener, true);

可选操作

//移除监听事件,默认可以不用移除lifecycleListener,除非在当前界面存在时候,想要不让某些类监听,那么可以手动进行移除(removeLifecycleListener)
AvoidOnResultHelper.removeLifecycleListener(this, lifecycleListener);

源码地址

https://github.com/bugyun/AvoidOnResultHelper

看到此处,是不是感觉不过瘾?原理讲解来了~~

大家都停下,听我说我要开始装逼了

原理

我们先来分下一下 FragmentActivity 的源码,在 onStart、onStop、onPause、onActivityResult、onRequestPermissionsResult等方法的时候,都会执行FragmentManagerImpl mFragments 对象的dispatchCreate、dispatchStart、dispatchStop方法,还会执行对应 fragment 的onActivityResult和onRequestPermissionsResult方法。

final FragmentManagerImpl mFragments = new FragmentManagerImpl();

protected void onCreate(@Nullable Bundle savedInstanceState) {
    this.mFragments.attachHost((Fragment)null);
    super.onCreate(savedInstanceState);
    ...//省略不必要的代码
    
    this.mFragments.dispatchCreate();
}

protected void onStart() {
    super.onStart();
    ...//省略不必要的代码

    this.mFragments.noteStateNotSaved();
    this.mFragments.execPendingActions();
    this.mFragments.dispatchStart();
}

protected void onStop() {
    super.onStop();
    ...//省略不必要的代码
    this.mFragments.dispatchStop();
}


protected void onPause() {
    super.onPause();
    ...//省略不必要的代码
    
    this.mFragments.dispatchPause();
}

protected void onDestroy() {
    super.onDestroy();
    ...//省略不必要的代码

    this.mFragments.dispatchDestroy();
}

public void onLowMemory() {
    super.onLowMemory();
    this.mFragments.dispatchLowMemory();
}

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    ...//省略不必要的代码
    Fragment targetFragment = mFragments.findFragmentByWho(who);
    targetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);
    ...//省略不必要的代码
}

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
        @NonNull int[] grantResults) {
        ...//省略不必要的代码
        final List<Fragment> activeFragments =
                mFragments.getActiveFragments(new ArrayList<Fragment>(activeFragmentsCount));
        Fragment frag = activeFragments.get(index);
        if (frag == null) {
            Log.w(TAG, "Activity result no fragment exists for index: 0x"
                    + Integer.toHexString(requestCode));
        } else {
            frag.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
        }
        ...//省略不必要的代码
    }
}

我们在来看 FragmentManagerImpl 的源码,就知道 FragmentActivity 的声明周期方法在执行的时候,都会执行包含的 fragment 的声明周期方法。代码如下:

public void dispatchCreate() {
    mStateSaved = false;
    moveToState(Fragment.CREATED, false);
}

public void dispatchActivityCreated() {
    mStateSaved = false;
    moveToState(Fragment.ACTIVITY_CREATED, false);
}

public void dispatchStart() {
    mStateSaved = false;
    moveToState(Fragment.STARTED, false);
}

void moveToState(int newState, boolean always) {
    moveToState(newState, 0, 0, always);
}

void moveToState(int newState, int transit, int transitStyle, boolean always) {
    ...//省略不必要的代码
    if (mActive != null) {
        boolean loadersRunning = false;
        for (int i=0; i<mActive.size(); i++) {
            Fragment f = mActive.get(i);
            if (f != null) {
                moveToState(f, newState, transit, transitStyle, false);// 执行声明周期方法
                ...//省略不必要的代码
            }
        }
        ...//省略不必要的代码
    }
}

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
        boolean keepActive) {
        ...//省略不必要的代码
        switch (f.mState) {
            case Fragment.INITIALIZING:
                ...//省略不必要的代码
                f.onAttach(mActivity);
                ...//省略不必要的代码
                if (f.mFromLayout) {
                    ...//省略不必要的代码
                    if (f.mView != null) {
                        ...//省略不必要的代码
                        f.onViewCreated(f.mView, f.mSavedFragmentState);
                    } else {
                        f.mInnerView = null;
                    }
                }
            case Fragment.CREATED:
                    ...//省略不必要的代码
                    f.onViewCreated(f.mView, f.mSavedFragmentState);
                    ...//省略不必要的代码
            case Fragment.ACTIVITY_CREATED:
            case Fragment.STOPPED:
                ...//省略不必要的代码
                f.performStart();
            case Fragment.STARTED:
                ...//省略不必要的代码
                f.performResume();
        }
    } else if (f.mState > newState) {
        switch (f.mState) {
            case Fragment.RESUMED:
                ...//省略不必要的代码
                    f.performPause();
            case Fragment.STARTED:
                    f.performStop();
            case Fragment.STOPPED:
                    f.performReallyStop();
            case Fragment.ACTIVITY_CREATED:
                    f.performDestroyView();
            case Fragment.CREATED:
                ...//省略不必要的代码
        }
    }
    f.mState = newState;
}

通过上面的代码,可以看出都会执行moveToState 方法,在moveToState方法中,通过 for 循环执行activity 中所有的 fragment 的生命周期方法。

那么,我们就可以创建一个没有界面的 fragment 添加到 activity 中,就可以完美监听界面的声明周期和回调方法。到此原理讲解结束。

打完收工!

知识拓展

比如我们现在 很多第三方的库,glide 、Android Architecture Component 等等这些库都是使用这些原理。有兴趣的小伙伴可以立马去阅读源码~~

福利

安利下权限库,超级简单好用~

https://github.com/bugyun/MissPermission

慢走不送!

如果你喜欢我的文章,可以关注我的掘金、公众号、博客、简书或者Github!

简书: https://www.jianshu.com/u/a2591ab8eed2

GitHub: https://github.com/bugyun

Blog: https://ruoyun.vip

掘金: https://juejin.im/user/56cbef3b816dfa0059e330a8/posts

CSDN: https://blog.csdn.net/zxloveooo

欢迎关注微信公众号

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359

推荐阅读更多精彩内容