The preface
We know that when you start an Activity For Result in Android, the callback goes back to the Activity’s OnActivityResult. Isn’t that awkward if you’re writing another component and you can’t rely on the Activity directly? And when we write a gallery component, found to request permissions, right after the request in the operation, but still access request callback onRequestPermissionsResult in the Activity, what do we do? Today we introduce ActivityResultPermission, an open source library that helps uncouple OnActivityResult and PermissionRequest without relying on callbacks in activities.
The principle of
There are two ways to uncouple callbacks in an Activity
- One is starting a new Activity to determine permissions, get ActivityForResult results. (you can refer to RxAcitityResult, RxPermission implementation) as follows:
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.IntentSender;
import android.os.Bundle;
import io.reactivex.functions.Action;
public class HolderActivity extends Activity {
private static Request request;
private OnPreResult onPreResult;
private OnResult onResult;
private int resultCode;
private int requestCode;
private Intent data;
private static int FAILED_REQUEST_CODE = -909;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (request == null) {
finish();
return;
}
onPreResult = request.onPreResult();
onResult = request.onResult();
if(savedInstanceState ! =null) return;
if (request instanceof RequestIntentSender) {
RequestIntentSender requestIntentSender = (RequestIntentSender) request;
if (requestIntentSender.getOptions() == null) startIntentSender(requestIntentSender);
else startIntentSenderWithOptions(requestIntentSender);
} else {
try {
startActivityForResult(request.intent(), 0);
} catch (ActivityNotFoundException e) {
if(onResult ! =null) { onResult.error(e); }}}}private void startIntentSender(RequestIntentSender requestIntentSender) {
try {
startIntentSenderForResult(requestIntentSender.getIntentSender(), 0,
requestIntentSender.getFillInIntent(), requestIntentSender.getFlagsMask(),
requestIntentSender.getFlagsValues(), requestIntentSender.getExtraFlags());
} catch (IntentSender.SendIntentException exception) {
exception.printStackTrace();
onResult.response(FAILED_REQUEST_CODE, RESULT_CANCELED, null); }}private void startIntentSenderWithOptions(RequestIntentSender requestIntentSender) {
try {
startIntentSenderForResult(requestIntentSender.getIntentSender(), 0,
requestIntentSender.getFillInIntent(), requestIntentSender.getFlagsMask(),
requestIntentSender.getFlagsValues(), requestIntentSender.getExtraFlags(), requestIntentSender.getOptions());
} catch (IntentSender.SendIntentException exception) {
exception.printStackTrace();
onResult.response(FAILED_REQUEST_CODE, RESULT_CANCELED, null); }}@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
this.resultCode = resultCode;
this.requestCode = requestCode;
this.data = data;
if (this.onPreResult ! =null) {
this.onPreResult.response(requestCode, resultCode, data)
.doOnComplete(new Action() {
@Override
public void run(a) throws Exception {
finish();
}
})
.subscribe();
} else{ finish(); }}@Override
protected void onDestroy(a) {
super.onDestroy();
if(onResult ! =null)
onResult.response(requestCode, resultCode, data);
}
static void setRequest(Request aRequest) { request = aRequest; }}Copy the code
- One is to add a Fragment, get a callback in the Fragment, and decouple it. The code for the library mentioned in this article is shown below
import android.app.Fragment;
import android.content.Intent;
import androidx.annotation.NonNull;
/** * author:DingDeGao * time:2019-07-16-14:30 * function: ReplaceFragment */
public class ReplaceFragment extends Fragment {
static final int ACTIVITY_REQUEST_CODE = 100;
static final int PERMISSION_REQUEST_CODE = 101;
private IHandle iHandle;
public void setIHandle(IHandle iHandle) {
this.iHandle = iHandle;
}
public IHandle getIHandle(a){
return iHandle;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode ! = ACTIVITY_REQUEST_CODE)return;
if(iHandle ! =null){ iHandle.onActivityResultHandle(resultCode,data); }}@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode ! = PERMISSION_REQUEST_CODE)return;
if(iHandle ! =null){ iHandle.onRequestPermissionsResultHandle(getActivity(),permissions,grantResults); }}}Copy the code
RxActivityResult, RxPermission is the former, and here the latter is the Fragment.
How is it different from RxActivityResult and RxPermission?
- There is no need to rely on RxJava, but chained calls are also supported.
- The function is richer, the combination of the two, the use is more convenient, and support part of the domestic Rom permission judgment, jump permission setting page.
- Small amount of code, you can choose to copy the code directly into the project (less than 400 lines of core code).
- Fragment takes up fewer resources.
Start using (minSdkVersion >= 14)
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
implementation 'com. Making. DingProg: ActivityResultPermission: v0.0.1'
}
Copy the code
OnActivityResult
Intent intent = new Intent(this, OnActivityResultActivity.class);
/ / by ActivityResultPermissionUtils to start the Activity, and register the callback
ActivityResultPermissionUtils.startActivityForResult(this, intent).activityResult(new Listener.ResultListener() {
@Override
public void onResult(Intent data) {
if(data ! =null) {
String testStr = data.getStringExtra("test");
Toast.makeText(MainActivity.this."openActivity with result is:"+ testStr, Toast.LENGTH_SHORT).show(); }}@Override
public void onCancel(a) {
Toast.makeText(MainActivity.this."openActivity with result cancel", Toast.LENGTH_SHORT).show(); }});Copy the code
Permissions to handle
ActivityResultPermissionUtils.requestPermissions(this, Manifest.permission.CAMERA).permissions(new Listener.PermissionResultListener() {
@Override
public void permissionDenied(String permission, boolean rationale) {
// Rationale if true just clicked prohibit
if(rationale){
Toast.makeText(MainActivity.this."Denied permission", Toast.LENGTH_SHORT).show();
}else{
// Click Disable permissions, do not allow in pop-up
Toast.makeText(MainActivity.this."Denied permission with ask never", Toast.LENGTH_SHORT).show();
PermissionGoSettingsPageUtils.go(MainActivity.this); }}@Override
public void permissionGranted(a) {
releaseCamera();
try{
camera = Camera.open(0);
camera.setPreviewDisplay(surfaceView.getHolder());
camera.startPreview();
}catch(Exception e){ e.printStackTrace(); }}});Copy the code
If for some abnormal Rom (such as oppo, vivo mobile phone), you can call PermissionUtils. CheckSelfPermissionsWhitNoNoramal (context, permissions).
Right, call ActivityResultPermissionUtils. RequestPermissions (this, permission). PermissionsWithoutCheck ();
See sample ActivityResultPermission for more information