【问题标题】:Wait for user permission等待用户权限
【发布时间】:2016-09-28 08:14:36
【问题描述】:

我构建了一个在启动时对 GPS 进行采样的应用程序。 您可能知道,Android M 及更高版本在运行时请求权限。

所以,就我而言,我首先检查是否需要权限,如下所示:

private void permissionForAndroidM()
{
    if (Build.VERSION.SDK_INT > 22) {
        String[] allPermissionNeeded = {
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO};

        List<String> permissionNeeded = new ArrayList<>();
        for (String permission : allPermissionNeeded)
            if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED)
                permissionNeeded.add(permission);
        if (permissionNeeded.size() > 0) {
            requestPermissions(permissionNeeded.toArray(new String[0]), 0);
        }
    }
}

但是 Android 继续运行代码并请求 GPS 数据(= 崩溃,因为用户没有接受权限请求)。

我找到了许多关于等待用户输入的解决方案(例如使用DialogInterface.OnClickListenerlink,但在这种情况下无法实现,因为我没有创建对话框)。

底线,问题是:我怎样才能等待来自 Android 权限对话框的用户回答?

【问题讨论】:

  • 只需覆盖 onRequestPermissionsResult()
  • 非常感谢,我不知道这个方法
  • 我不明白我们需要在覆盖的方法中做什么,有人可以解释一下吗?

标签: android android-permissions


【解决方案1】:

您可以处理用户响应覆盖方法

public void onRequestPermissionsResult(
    int requestCode,
    String[] permissions,
    int[] grantResults
)

来自您的活动。

【讨论】:

  • 我不明白如何将它添加到 onRequest 函数会停止线程,直到收到权限。你能澄清一下吗?
【解决方案2】:

Android 继续运行代码并请求 GPS 数据(= 崩溃,因为用户没有接受权限请求)。

像 Android 中的许多东西一样,requestPermissions() 是异步的。到此方法返回时,甚至还没有提示用户提供权限。

如何等待来自 Android 权限对话框的用户回答?

你没有。

如果你发现你已经拥有了权限,你就去做你的工作。如果你发现你必须请求许可,你会延迟做这项工作,直到你获得许可,在onRequestPermissionsResult()

【讨论】:

  • 如果我不做我的工作,那么以后没有用户命令我将无法做到。但我不想打扰我的用户。
【解决方案3】:

我的工作方式如下:

1- 创建了一个Boolean 助手来检查授予的权限:

public class UtilPermissions {
    public static boolean hasPermissions(Context context, String... allPermissionNeeded)
    {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
                && context != null && allPermissionNeeded != null) 
            for (String permission : allPermissionNeeded) 
                if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED)
                     return false;
        return true;
    }
}

2- 创建Splash 屏幕为:

public class Splash extends Activity {
    private static final int PERMISSION_ALL = 0;
    private Handler h;
    private Runnable r;
  /*  
    SharedPreferences mPrefs;
    final String settingScreenShownPref = "settingScreenShown";
    final String versionCheckedPref = "versionChecked";
  */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        h = new Handler();
        r = new Runnable() {
            @Override
            public void run() {
                Toast.makeText(Splash.this, "Runnable started", Toast.LENGTH_SHORT).show();

  /*          // (OPTIONAL) these lines to check if the `First run` ativity is required
                int versionCode = BuildConfig.VERSION_CODE;
                String versionName = BuildConfig.VERSION_NAME;

                mPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
                SharedPreferences.Editor editor = mPrefs.edit();

                Boolean settingScreenShown = mPrefs.getBoolean(settingScreenShownPref, false);
                int savedVersionCode = mPrefs.getInt(versionCheckedPref, 1);

                if (!settingScreenShown || savedVersionCode != versionCode) {
                    startActivity(new Intent(Splash.this, FirstRun.class));
                    editor.putBoolean(settingScreenShownPref, true);
                    editor.putInt(versionCheckedPref, versionCode);
                    editor.commit();
                }
                else
  */
                startActivity(new Intent(Splash.this, MainActivity.class));
                finish();    
            }
        };

        String[] PERMISSIONS = {
                READ_PHONE_STATE,
                MODIFY_AUDIO_SETTINGS,
                ACCESS_FINE_LOCATION,
                READ_SMS
        };

        if(!UtilPermissions.hasPermissions(this, PERMISSIONS)){
            ActivityCompat.requestPermissions(this, PERMISSIONS, PERMISSION_ALL);
        }
        else
            h.postDelayed(r, 1500);
    }

  // Put the below OnRequestPermissionsResult code here
}

3- 创建OnRequestPermissionsResult 如下:

@Override
public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {

    int index = 0;
    Map<String, Integer> PermissionsMap = new HashMap<String, Integer>();
    for (String permission : permissions){
        PermissionsMap.put(permission, grantResults[index]);
        index++;
    }

    if((PermissionsMap.get(ACCESS_FINE_LOCATION) != 0)
            || PermissionsMap.get(READ_SMS) != 0){
        Toast.makeText(this, "Location and SMS permissions are a must", Toast.LENGTH_SHORT).show();
        finish();
    }
    else
    {
        h.postDelayed(r, 1500);
    }
}

4- 在AndroidManifest.xml 中将Splash 屏幕定义为Launcher

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:theme="@style/AppTheme.NoActionBar">
</activity>

<activity
    android:name=".Splash"
    android:configChanges="orientation|keyboardHidden|screenSize"
    android:theme="@style/SplashTheme">

    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

5- 在styles.xml 中将SplashTheme 定义为:

<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
    <item name="android:windowBackground">@drawable/Splash</item>
</style>

6- @drawable/Splash.xmls 是:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:drawable="@color/lightgray"/>

    <item>
        <bitmap
            android:gravity="center"
            android:src="@mipmap/ic_launcher"/>
    </item>

</layer-list>

7- 在values/colors.xmls 中,lightgray 颜色定义如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="lightgray">#D3D3D3</color>
</resources>

【讨论】:

    【解决方案4】:

    我认为这已经晚了,但也许它会对某人有所帮助。 因此,假设您想在您的应用程序中启动一个位置侦听器,但您还没有注册侦听器的权限,但您希望在某个地方获得您的权限时立即收到通知。只听那个事件。

    object PermissionsHelper{
         private val listeners = ArrayList<PermissionListener>()
    
         fun addListener(listener: PermissionListener){ ... }
    
         fun notifyPermissionsGranted(list : ArrayList<String>) { ... }
         /** OR */
         fun notifyPermissionsStatusChanged() { ... } // and all of them will check again.
    }
    

    所以你想在哪里听位置,你会检查你的许可是否被授予,如果没有,你打电话给PermissionsHelper.getInstance().addListener(...) 在 UI 中,当 onRequestPermissionsResult 获得授予权限时,您将调用 ass follow PermissionsHelper.getInstance().notifyPermissionsGranted( ... ) 然后您继续注册到系统以获取位置。

    【讨论】:

      【解决方案5】:

      请求权限后,通过while循环,可以检查权限是否被连续授予,如果被授予,则可以更改值并退出while循环。

      Boolean isAnswered = true;
      
          while(isAnswered){
      
              if (ActivityCompat.checkSelfPermission(getApplication(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getApplication(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                  Log.d("isanswered", String.valueOf(isAnswered));
              }
              else{
                  isAnswered = false;
                  Log.d("isanswered", String.valueOf(isAnswered));
              }
          }
      

      【讨论】:

      • 不!这可能是一个肮脏的热修复。如果您将拥有 20 个对象并且所有对象都需要一个或多个权限,那么您将只为某些权限保持 20 个线程? + 没有延迟,因此每个线程都将处于满负荷状态..
      猜你喜欢
      • 2016-07-26
      • 1970-01-01
      • 2021-11-04
      • 2015-11-23
      • 2011-01-18
      • 1970-01-01
      • 2015-02-10
      • 1970-01-01
      相关资源
      最近更新 更多