Android 6.0の稼働時間の適正化を迅速に実現するクラス

9929 ワード

前言
今、Android 6.0の運行時限が適切で、時代遅れと言えるのですが、なぜ書くのでしょうか.一つは、現在のGitHubで上位にランクされているオープンソースプロジェクトを試してみると、確かに素晴らしいですが、使いやすさでは満足できず、自分で1つの考えが芽生えました.二つ目は、現在の国内の主流の応用を見てみると、Android 6.0に適していないことが多いので、この文章には意味があると思います.
使用
使いやすさについて述べた以上、まず、申請権限が必要な場所で使用方法を呼び出してみましょう.
PermissionReq.with(this) // Activity or Fragment
        .permissions(Manifest.permission.CAMERA,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) //        
        .result(new PermissionReq.Result() { //       
            @Override
            public void onGranted() { //     
                // do something
            }
            @Override
            public void onDenied() { //     
                // do something
            }
        })
        .request();
ActivityベースクラスとFragmentベースクラスに次のコードを追加します.
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    PermissionReq.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
APIのデザインは比較的ポピュラーなストリーム呼び出しを採用しており、皆さんが見てどんな感じなのか分かりませんが、使用するのは簡単で、元のコード構造を破壊することはないと思います.ここまで言うと、今では多くのオープンソースフレームワークが注釈方式で申請結果をコールバックしているので、この方式ではコード階層が少なくなったが、可読性が悪くなり、元のコード構造を破壊する可能性があると思います.
ここにはもう一つのハイライトがありますが、皆さんが気づいたかどうか分かりません.私たちはRequestCodeを使っていません.RequestCodeはどこへ行きましたか.次の内容で教えてあげます.これも私の大好きな場所で、申請権限ごとにRequestCodeを定義する必要はありません.RequestCodeが繰り返される心配はありません.PermissionReqはすでに処理されているからです.
ソース解析
使用方法を見た後、内部実装を見てみましょう.プロセス別に見てみましょう.
まず、Appに登録されている権限を確認します.申請する権限がManifestに登録されていない場合は、失敗します.
initManifestPermission(activity);
for (String permission : mPermissions) {
    if (!sManifestPermissionSet.contains(permission)) {
        if (mResult != null) {
            mResult.onDenied();
        }
        return;
    }
}

private static Set sManifestPermissionSet;
private static synchronized void initManifestPermission(Context context) {
    if (sManifestPermissionSet == null) {
        sManifestPermissionSet = new HashSet<>();
        try {
            PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
            String[] permissions = packageInfo.requestedPermissions;
            Collections.addAll(sManifestPermissionSet, permissions);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}
スレッドのセキュリティのためにsynchronized修飾子を追加しました.
申請する権限がすでにManifestに登録されている場合は、次にシステムのバージョンを区別します.システムのバージョンが26未満であれば、直接成功に戻ります.そうしないと、申請権限が必要になります.このコードは簡単です.貼らないでください.
システムバージョン>=26であれば、本格的な申請プロセスが開始され、申請する権限が許可されているかどうかを確認し、許可されている場合は、これ以上申請する必要はありません.
List deniedPermissionList = getDeniedPermissions(activity, mPermissions);
if (deniedPermissionList.isEmpty()) {
    if (mResult != null) {
        mResult.onGranted();
    }
    return;
}

private static List getDeniedPermissions(Context context, String[] permissions) {
    List deniedPermissionList = new ArrayList<>();
    for (String permission : permissions) {
        if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
            deniedPermissionList.add(permission);
        }
    }
    return deniedPermissionList;
}
申請する権限がすべて許可されていない場合は、RequestCodeの生成をシステムに送信する必要があります.
int requestCode = genRequestCode();

private static AtomicInteger sRequestCode = new AtomicInteger(0);
private static int genRequestCode() {
    return sRequestCode.incrementAndGet();
}
RequestCodeを定義する必要はありません.これで、RequestCodeはついに浮上しました.内部で静的に増加したAtomicIntegerをRequestCodeとして使用し、RequestCodeが重複しないことを保証します.AtomicIntegerを使用してintを直接使用しないのはスレッドの安全のためです.
システムへの申請の送信
String[] deniedPermissions = deniedPermissionList.toArray(new String[deniedPermissionList.size()]);
requestPermissions(mObject, deniedPermissions, requestCode);
sResultArray.put(requestCode, mResult);

@TargetApi(Build.VERSION_CODES.M)
private static void requestPermissions(Object object, String[] permissions, int requestCode) {
    if (object instanceof Activity) {
        ((Activity) object).requestPermissions(permissions, requestCode);
    } else if (object instanceof Fragment) {
        ((Fragment) object).requestPermissions(permissions, requestCode);
    }
}
申請時に出所を区別し、申請後にResultをArrayに入れて保存し、申請結果の到着を待つ
申請結果が到着した後に申請者に通知する
public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Result result = sResultArray.get(requestCode);
    if (result == null) {
        return;
    }
    sResultArray.remove(requestCode);
    for (int grantResult : grantResults) {
        if (grantResult != PackageManager.PERMISSION_GRANTED) {
            result.onDenied();
            return;
        }
    }
    result.onGranted();
}
ここまで私たちの申請権限の流れはもう終わりました.ソースも読み終わりました.
完全なコード
皆さんが使いやすいように、私は完全なコードを貼ります.
public class PermissionReq {
    private static AtomicInteger sRequestCode = new AtomicInteger(0);
    private static SparseArray sResultArray = new SparseArray<>();
    private static Set sManifestPermissionSet;

    public interface Result {
        void onGranted();

        void onDenied();
    }

    private Object mObject;
    private String[] mPermissions;
    private Result mResult;

    private PermissionReq(Object object) {
        mObject = object;
    }

    public static PermissionReq with(@NonNull Activity activity) {
        return new PermissionReq(activity);
    }

    public static PermissionReq with(@NonNull Fragment fragment) {
        return new PermissionReq(fragment);
    }

    public PermissionReq permissions(@NonNull String... permissions) {
        mPermissions = permissions;
        return this;
    }

    public PermissionReq result(@Nullable Result result) {
        mResult = result;
        return this;
    }

    public void request() {
        Activity activity = getActivity(mObject);
        if (activity == null) {
            throw new IllegalArgumentException(mObject.getClass().getName() + " is not supported");
        }

        initManifestPermission(activity);
        for (String permission : mPermissions) {
            if (!sManifestPermissionSet.contains(permission)) {
                if (mResult != null) {
                    mResult.onDenied();
                }
                return;
            }
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            if (mResult != null) {
                mResult.onGranted();
            }
            return;
        }

        List deniedPermissionList = getDeniedPermissions(activity, mPermissions);
        if (deniedPermissionList.isEmpty()) {
            if (mResult != null) {
                mResult.onGranted();
            }
            return;
        }

        int requestCode = genRequestCode();
        String[] deniedPermissions = deniedPermissionList.toArray(new String[deniedPermissionList.size()]);
        requestPermissions(mObject, deniedPermissions, requestCode);
        sResultArray.put(requestCode, mResult);
    }

    public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        Result result = sResultArray.get(requestCode);

        if (result == null) {
            return;
        }

        sResultArray.remove(requestCode);

        for (int grantResult : grantResults) {
            if (grantResult != PackageManager.PERMISSION_GRANTED) {
                result.onDenied();
                return;
            }
        }
        result.onGranted();
    }

    @TargetApi(Build.VERSION_CODES.M)
    private static void requestPermissions(Object object, String[] permissions, int requestCode) {
        if (object instanceof Activity) {
            ((Activity) object).requestPermissions(permissions, requestCode);
        } else if (object instanceof Fragment) {
            ((Fragment) object).requestPermissions(permissions, requestCode);
        }
    }

    private static List getDeniedPermissions(Context context, String[] permissions) {
        List deniedPermissionList = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                deniedPermissionList.add(permission);
            }
        }
        return deniedPermissionList;
    }

    private static synchronized void initManifestPermission(Context context) {
        if (sManifestPermissionSet == null) {
            sManifestPermissionSet = new HashSet<>();
            try {
                PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
                String[] permissions = packageInfo.requestedPermissions;
                Collections.addAll(sManifestPermissionSet, permissions);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    private static Activity getActivity(Object object) {
        if (object != null) {
            if (object instanceof Activity) {
                return (Activity) object;
            } else if (object instanceof Fragment) {
                return ((Fragment) object).getActivity();
            }
        }
        return null;
    }

    private static int genRequestCode() {
        return sRequestCode.incrementAndGet();
    }
}
まとめ
本文では、Android 6.0の実行時権限を迅速かつ簡単に適合させる方法を紹介しました.もしあなたが本文を読む時に何か問題や漏れを発見したり、異なる見方をしたりしたら、指摘を歓迎します.