Android M请求权限结果在非Activity中的处理方法

35
我有一个应用程序需要查找用户的位置,位置信息会在不同的类中获取,因此我编写了一个单独的类(不是Activity类),使用位置服务来获取用户位置,在Android M下工作正常,但在Android M中需要运行时权限。我想在我的位置类中检查权限,我知道如何检查权限,但我无法在我的位置类中使用onRequestPermissionsResult方法,因为我的位置类没有从任何活动继承。
那么我应该怎么做才能实现这个功能呢?非常感谢您的帮助/提示!

1
你只需要在需要权限之前获取它。不一定要在你需要它的时候立即获取。只需在适当的Activity中向用户请求即可。 - Mike M.
@MikeM. 我需要在一些 Activity/Fragment 中检查权限吗?基本上我正在我的位置类中检查权限。 - Muhammad Husnain Tahir
@MikeM。是的,我确实有我的Location类上下文,但我该如何覆盖onRequestPermissionsResult方法? - Muhammad Husnain Tahir
1
你不会这样做的。onRequestPermissionsResult() 方法是在 requestPermissions() 调用后执行的,正如我们所说,你应该在你的 Activity 中调用它,而不是在 Location 类中。checkSelfPermission() 没有回调函数。 - Mike M.
没问题。是的,你应该听从CommonsWare的建议。在创建Location类实例之前,最好先检查权限,这样就没有必要从那里进行检查了。 - Mike M.
显示剩余5条评论
6个回答

21

因为public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)ActivityCompat.OnRequestPermissionsResultCallback 接口的一个抽象方法。 请参考文档

只需在所需的类中实现此接口即可完成。 例如

class location implements  ActivityCompat.OnRequestPermissionsResultCallback{ }

现在只需覆盖 onRequestPermissionsResult() 方法

 @Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
     // case Statements
    }
}

15
理论上是可以的,但 Android 系统似乎不会在非 Activity 类中调用 onRequestPermissionsResult 方法。 - mauron85
3
那不可能是真的,因为requestPermissions()需要作为参数的是Activity,而不仅仅是实现了OnRequestPermissionsResultCallback接口的类。 - Alexey Andronov
3
我做了这件事,但它没有起作用,所以这个答案是没有用的。 - mmdreza baqalpour
1
你正在创建一个实现与Activity相似接口的新对象,并期望它调用回调函数?操作系统只知道Activity实现了该接口,对其他对象一无所知。 - Ali Nem
2
当一个方法(A)调用接口(B)回调(C)时,如果A有一个参数引用到B,则回调C会被调用;否则C无法被调用。 对于方法requestPermissions(),它使用activity作为参数而不是ActivityCompat.OnRequestPermissionsResultCallback,因此根本无法使用此功能。 - Farido mastr
显示剩余2条评论

12

欢迎您从非UI类中调用checkSelfPermission(),因为只需要一些Context

但是,您必须在某个活动或片段上调用requestPermissions()。您要在该同一活动或片段上重写onRequestPermissionsResult()。这与调用startActivityForResult()并实现onActivityResult()没有区别。

思路是在涉及位置的非UI类处理之前请求权限。


1
谢谢你的回答,我知道这种方法,但我基本上想在非活动类中覆盖onRequestPermissionsResult()。现在我猜这是不可能的。 - Muhammad Husnain Tahir
@Tahir:没错。您可以让活动或片段调用非 UI 类来提供权限请求的结果。最好情况是,非活动类实例甚至不存在 -- 在创建 Location 实例并尝试使用位置数据之前,您应该先请求和确认权限。 - CommonsWare
@CommonsWare,在这种情况下,我能否以非UI类的方式获取onRequestPermissionsResult()中的上下文? - Noor Hossain
1
正如我在答案中所写的,“你需要在同一个活动或片段上重写onRequestPermissionsResult()。” 我将“非UI类”解释为指除了活动或片段之外的其他内容。如果您决定在“非UI类”上实现名为onRequestPermissionsResult()的方法,则需要自己调用该方法。因此,您可以传递任何您喜欢的参数,例如Context - CommonsWare
@CommonsWare,感谢您的快速和出色的回复。- 致意。 - Noor Hossain

5

1- 创建一个透明的活动

<activity android:name=".activity.activity.CheckStoragePermissionsActivity" android:theme="@style/Theme.Transparent">

<style name="Theme.Transparent" parent="Theme.AppCompat">
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>

2- 自定义您的活动

public class CheckStoragePermissionsActivity extends AppCompatActivity {

    private String[] permissions;
    private int pCode = 12321;
    public static PermissionListener permissionListener;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        checkPermissions();
    }

    private void checkPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

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

            boolean flag = false;
            for (String s : permissions)
                if (checkSelfPermission(s) != PackageManager.PERMISSION_GRANTED)
                    flag = true;

            if (flag) {
                requestPermissions(permissions, pCode);
            } else {
                permissionListener.permissionResult(true);
                finish();
            }
        }else
            finish();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == pCode) {
            boolean flag = true;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
                for (int i = 0, len = permissions.length; i < len; i++)
                    if (grantResults[i] != PackageManager.PERMISSION_GRANTED)
                        flag = false;
            if (flag) {
                if (permissionListener != null)
                    permissionListener.permissionResult(true);
            } else if (permissionListener != null)
                permissionListener.permissionResult(false);
            finish();
        }
    }
}

3- permissionListener 是一个静态接口,可以直接在 context.startActivity(...) 前设置,或者使用您的计划来查找权限结果。

public interface PermissionListener extends Serializable {
    void permissionResult(boolean hasPermission);
}

4- 最后调用 context.startActivity(new Intent(context, CheckStoragePermissionsActivity.class));

CheckStoragePermissionsActivity 将执行所有必需的操作,直到用户允许或拒绝操作。


1
只是提供信息,Activity中检查权限并不是强制性的。您仍然可以使用ContextCompat类从任何地方仅使用上下文实例来执行此操作。如果使用ContextCompat类,甚至可以避免许多版本检查。 - Ayyappa
1
如果我们不在Activity中执行,onRequestPermissionsResult将不会被调用。 - Amit Hooda

4

您不能覆盖它。这个方法仅适用于Activity和Fragments。但是,您可以在您的位置类中创建一个静态方法,并从您的活动/片段的重写onRequestPermissionResult方法中调用它。

我已经为Location结合权限制作了一个自定义实现。您也可以使用一个名为“Let”的库来获取权限。


1
感谢您的回答,阅读了所有的答案/评论后,我现在知道我必须在某个Activity/Fragment中使用这个onRequestPermissionResult()。 - Muhammad Husnain Tahir

0

你可以创建一个继承Activity的类(最好是AppCompactActivity),实现所有必要的位置代码,并在需要使用它的所有活动中扩展此类。


-1

使用这个类:

public class permissionModule {

final public static int STORAGE_PERMISSION_CODE = 23;
private Activity activity;

public permissionModule(Activity activity) {
    this.activity = activity;
}

public void startGetPermission(){
    if (isStorageReadable()){
        Toast.makeText(activity,"you Already have the permission to access storage",Toast.LENGTH_SHORT).show();
    }else {
        requestStoragePermission();
    }
}

private void requestStoragePermission() {
    ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, STORAGE_PERMISSION_CODE);
}

private boolean isStorageReadable() {
    int result = ContextCompat.checkSelfPermission(activity, 

Manifest.permission.READ_EXTERNAL_STORAGE);
        return result == PackageManager.PERMISSION_GRANTED;
    }
}

在你的活动中调用:

new permissionModule(MainActivity.this).startGetPermission();

最终的结果,请在您的活动中覆盖此方法:

@TargetApi(Build.VERSION_CODES.M)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == permissionModule.STORAGE_PERMISSION_CODE) {
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Snackbar permissionWarning = Snackbar.make(rootLayout, "tnk", Snackbar.LENGTH_INDEFINITE);
            permissionWarning.setAction("ok", new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //...
                }
            });
            permissionWarning.show();
        } else {
            boolean showRationale = shouldShowRequestPermissionRationale(Manifest.permission.READ_EXTERNAL_STORAGE);
            if (showRationale) {
                Snackbar permissionWarning = Snackbar.make(rootLayout, "Permission Required to access storage", Snackbar.LENGTH_INDEFINITE);
                permissionWarning.setAction("ok", new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        //requestStoragePermission();
                    }
                });
                permissionWarning.show();
            } else {
                Snackbar snackbar = Snackbar.make(rootLayout, "you denied the permission for ever pleas fix it in setting", Snackbar.LENGTH_INDEFINITE);
                snackbar.setAction("setting", new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Intent intent = new Intent();
                        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                        Uri uri = Uri.fromParts("package", MainActivity.this.getPackageName(), null);
                        intent.setData(uri);
                        MainActivity.this.startActivity(intent);
                    }
                });
                snackbar.show();
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接