避免 onActivityResult 和 onRequestPermissionsResult 煩惱requestCode的問題,幫助快速開發~~

在開發中,當在一個A的Activity中打開B的Activity界面,若是想要B->A傳值的狀況有不少。可是這種全部獲取到的結果都須要到onActivityResult中處理的方式實在使人蛋疼。java

試想一下,咱們敲着代碼唱着歌。忽然,半路上跳出一羣馬匪,讓咱們到另外一個頁面獲取一點數據,獲取後還不讓在當前代碼位置處理邏輯,要去onActivityResult添加一個requestCode分支處理結果,處理完才讓回來,等這一切都作完回來不免就會陷入這樣的思考:我是誰,我在哪,我在幹什麼,我剛纔寫到哪了……git

分析流程

A 界面須要調用以下方法:github

//定義 requestCode 
int mRequestCode = xxx;
context.startActivityForResult(intent, requestCode);
複製代碼

而後A 界面須要在onActivityResult方法中添加以下代碼:服務器

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == mRequestCode){ //判斷 requestCode
        //執行
    }
}
複製代碼

在 B 界面中,須要定義以下的代碼:app

//新界面
Intent intent = Intent()
intent.putExtra("text",text.text.toString())
setResult(Activity.RESULT_OK,intent)
finish();
複製代碼

這樣 B->A 界面傳遞參數。框架

打開相冊

好比打開相冊,要寫以下的代碼。ide

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

private void checkPermission(){
    //首先進行權限判斷,和請求
    //先 check
    //而後 requestPermissions
    ...
}

//當拍攝照片完成時會回調到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);
}
//處理權限
@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);
            // 若是限制上傳到服務器的圖片類型時能夠直接寫如:"image/jpeg 、 image/png等的類型" 全部類型則寫 "image/*"
            intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/jpeg");
            startActivityForResult(intentToPickPic, REQUEST_CODE);
        }
    }
}
複製代碼

還有一些判斷等等,寫起來特別麻煩。那麼有沒有不須要本身定義requestCode,而後不用重寫onRequestPermissionsResult 和 onActivityResult 方法呢?this

那麼就介紹下此框架spa

AvoidOnResultHelper

開啓 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 都不須要定義!~~code

框架內部定義好了連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);
複製代碼

看到此處,是否是感受不過癮?原理講解來了~~

原理

分析 FragmentActivity 源碼

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;
}
複製代碼

那麼,咱們就能夠建立一個沒有界面的 fragment 添加到 activity 中,就能夠完美監聽界面的聲明週期和回調方法。到此原理講解結束。

知識拓展

好比咱們如今 不少第三方的庫,glide 、Android Architecture Component 等等這些庫都是使用這些原理。有興趣的小夥伴能夠立馬去閱讀源碼~~

github地址

github: github.com/bugyun/Avoi… 歡迎star~

順便安利下權限庫:github.com/bugyun/Miss… 簡單好用~

相關文章
相關標籤/搜索