如何正确暂停应用程序,直到权限请求完成?

时间:2018-09-18 03:41:43

标签: java android asynchronous android-permissions

我正在编写一个应用程序,该应用程序的唯一功能是充当低功耗蓝牙的接收器。如果用户不允许BLE,则该应用程序无用。首次启动该应用程序时,我希望它向用户询问位置权限(因为Android要求BLE使用它)。我打开了权限对话框,但在用户阅读对话框时,应用程序的其余部分继续,启动BLEScanner等。我希望应用程序在用户阅读对话框并决定要做什么时暂停。这是我的设置:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);
        }

        //More UI preparation stuff

    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE: {
                if (permissions[0].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                    if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                        PermissionDialog newDialog = new PermissionDialog();
                        newDialog.show(getSupportFragmentManager(), "Request Location Permission");
                }
            }
        }
    }

其中的“ PermissionDialog”是一个不同的类,该类使用DialogFragment解释为什么应用程序需要该权限,然后关闭/重新启动该应用程序。在这种情况下,该应用程序的其余部分将继续,在用户仍在阅读弹出的权限对话框的同时尝试做蓝牙工作!天真的,我认为我可以使用同步锁来做到这一点,如下所示,但是在这种情况下,永远不会调用回调:

private final Object initLock = new Object();
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);
        }

        Log.i("Lock", "At the lock!");

        try {
            synchronized (initLock) {
                initLock.wait();
            }
        }
        catch (InterruptedException e) {
            //TODO find out what to do here
        }

        Log.i("Lock", "Past the lock!");


    @Override
    public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
        switch (requestCode) {
            case REQUEST_CODE: {
                if (permissions[0].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        synchronized (initLock){
                            initLock.notify();
                        }
                    }
                    else{
                        PermissionDialog newDialog = new PermissionDialog();
                        newDialog.show(getSupportFragmentManager(), "Request Location Permission");
                    }
                }
            }
        }
    }

执行此操作的正确方法是什么?我有一些想法,但它们都涉及范围。我是否需要制作另一个继承AppCompatActivity的类来获得权限并将其称为线程?但是,我怎么知道onRequestPermissionResult回调会去哪里呢?我很茫然。

3 个答案:

答案 0 :(得分:1)

//More UI preparation stuff中的代码放入新方法。授予权限后,说“ init()

private void init(){
    //More UI preparation stuff
}

然后在onCreate内,如果已经授予许可,则调用init();,否则请求许可。

@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);

    } else {
        init();
    }
}

现在在onRequestPermissionsResult内部处理用户的响应-如果用户已授权,则初始化UI,否则阻止功能和/或将问题通知用户。

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case REQUEST_CODE: {
            if (permissions[0].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    init();

                } else{
                    PermissionDialog newDialog = new PermissionDialog();
                    newDialog.show(getSupportFragmentManager(), "Request Location Permission");
                }
            }
        }
    }
}

PS:出于相同的目的,我准备了一个库,该库使此过程更加容易。看看my library.

答案 1 :(得分:0)

您可以使用EasyPermissions并实现EasyPermissions.PermissionCallbacks来解决它。 并在要运行的方法之前添加此注释:@AfterPermissionGranted 例如:

AfterPermissionGranted(PERMISSION_REQUESTCODE_BASE)
private void requestPerminssions(){
    if(EasyPermissions.hasPermissions(this,PERMISSIONS)){
        int hasCityData=config.getInt("isDataEmpty",0);
        if(hasCityData==0){
            new CountryInfoThread().execute();
        }else {
            new LocalPositionThread().execute();
        }
    }
}

答案 2 :(得分:0)

我最终使用了一个私有变量:

private boolean readyToStart = false;

通过这种方式:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE);
        }
        else{
            readyToStart = true;
        }
    }



@Override
    protected void onResume() {
        super.onResume();
        if (readyToStart) {
            startBluetooth();
        }
    }

@Override
    public void onRequestPermissionsResult(int requestCode, String permissions[],
                                           int[] grantResults) {
        Log.i("Permission", "Callback made");
        switch (requestCode) {
            case REQUEST_CODE: {
                if (permissions[0].equals(Manifest.permission.ACCESS_COARSE_LOCATION)) {
                    if (grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                        PermissionDialog newDialog = new PermissionDialog();
                        newDialog.show(getSupportFragmentManager(), "Request Location Permission");
                    }
                    else{
                        startBluetooth();
                    }
                }
            }
        }
    }