等待用户许可
Wait for user permission
我构建了一个在启动时对 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.OnClickListener
、link,但在这种情况下无法实现,因为我没有创建对话框)。
底线,问题:我如何等待用户从 Android 权限对话框中回答?
您可以处理用户响应覆盖方法
public void onRequestPermissionsResult(
int requestCode,
String[] permissions,
int[] grantResults
)
来自你的activity。
Android continuing running the code and asking for GPS data ( = crash, because the user didn't accept the permission request).
与 Android 中的许多事情一样,requestPermissions()
是异步的。到此方法 returns.
时,用户甚至还没有收到权限提示
How can I wait for user answer from the Android permission dialog ?
你不知道。
如果您发现自己已经获得许可,那么您就可以开始工作了。如果您发现必须请求许可,您可以延迟完成这项工作,直到获得许可,在 onRequestPermissionsResult()
.
我按以下方式工作:
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>
请求一个权限后,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));
}
}
我认为这已经晚了,但也许它会对某人有所帮助。
因此,假设您想在您的应用程序中启动一个位置侦听器,但您还没有注册侦听器的权限,但您希望在您的权限被授予后立即收到通知。只听那个事件。
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 following PermissionsHelper.getInstance().notifyPermissionsGranted( ... )
然后您继续向系统注册位置。
我构建了一个在启动时对 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.OnClickListener
、link,但在这种情况下无法实现,因为我没有创建对话框)。
底线,问题:我如何等待用户从 Android 权限对话框中回答?
您可以处理用户响应覆盖方法
public void onRequestPermissionsResult(
int requestCode,
String[] permissions,
int[] grantResults
)
来自你的activity。
Android continuing running the code and asking for GPS data ( = crash, because the user didn't accept the permission request).
与 Android 中的许多事情一样,requestPermissions()
是异步的。到此方法 returns.
How can I wait for user answer from the Android permission dialog ?
你不知道。
如果您发现自己已经获得许可,那么您就可以开始工作了。如果您发现必须请求许可,您可以延迟完成这项工作,直到获得许可,在 onRequestPermissionsResult()
.
我按以下方式工作:
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>
请求一个权限后,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));
}
}
我认为这已经晚了,但也许它会对某人有所帮助。 因此,假设您想在您的应用程序中启动一个位置侦听器,但您还没有注册侦听器的权限,但您希望在您的权限被授予后立即收到通知。只听那个事件。
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 following PermissionsHelper.getInstance().notifyPermissionsGranted( ... )
然后您继续向系统注册位置。