Error: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION
Error: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION
我在另一个应用程序中使用了一个模块。在我实现模块之前,我将它设置为 API 级别 23(编译和目标),就像我的主项目一样
这工作正常,除了这个错误。问题是,Google 自 marshmellow 以来更改了权限管理。最后,我不知道应该如何以及在哪里设置权限。
我在启动应用程序时遇到的错误:
java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any operations location.
能否请您帮我简单解释一下(我需要什么样的代码以及在哪里插入)以避免这个错误?
来自模块的清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cs.android.weminder">
<!--
android:versionCode="3"
android:versionName="1.2.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
-->
<!-- Grant the network access permission -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- Grant the location access permission -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Permission required to use Alarm Manager -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:allowBackup="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- android:name="com.cs.android.weminder.MyApplication"
android:label="@string/app_name">-->
<!-- This meta-data tag is required to use Google Play Services. -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!-- Required for creating dialog of the ACRA report -->
<activity
android:name="org.acra.CrashReportDialog"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:theme="@style/AcraDialog" />
<activity
android:name="com.cs.android.weminder.MainActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</activity>
<activity android:name="com.cs.android.weminder.BaseScreen" />
<activity android:name="com.cs.android.weminder.LocationBaseScreen" />
<activity android:name="com.cs.android.weminder.SettingsActivity" />
<activity android:name="com.cs.android.weminder.WeminderApplication" />
<!-- Required by the AdMob Ads SDK -->
<activity
android:name="com.google.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
<!-- Include the AdActivity configChanges and theme. -->
<activity
android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.Translucent" />
<receiver
android:name="com.cs.android.weminder.AlarmReceiver"
android:process=":remote" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.cs.android.weminder.AlarmService" >
</service>
</application>
主要 Activity 来自模块:
public class MainActivity extends SettingsActivity implements ActionTypes,
ResultType {
private TextView tvLocation, tvHTemp, tvLTemp, tvCurrentTemp, tvTimestamp,
tvDate, tvWindSpeed, tvPressure;
private ImageView ivCurrentWeather, ivRefresh, ivUnit, ivSearch, ivRemind,
ivMyLocation;
private HorizontalViewGallery forecastGallery;
// Search field
private MyCustomEditText etSearch;
// holding different weather icons presenting weather condition
// alternatively.
private IconFinder mIconFinder;
private ApiCallQueue requestsQueue = new ApiCallQueue();
// Ads View
private AdView adView;
private void setupUI(View view) {
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// Hide the search field if the user is touching anywhere
// except the search field
if (etSearch.isShown()) {
etSearch.startDeflation();
return true;
}
return false;
}
});
}
// If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
/**
* Initial the UI of current screen Initial variables;
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initialActivity() {
setupUI(findViewById(R.id.parent));
// display the name of location
tvLocation = (TextView) findViewById(R.id.tvLocation);
// Set the location icon
tvLocation.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_marker), null, null, null);
// display today highest temperature
tvHTemp = (TextView) findViewById(R.id.tvHTemp);
// Set the highest temperature icon
tvHTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_highest), null, null, null);
// display today lowest temperature
tvLTemp = (TextView) findViewById(R.id.tvLTemp);
// Set the lowest temperature icon
tvLTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_lowest), null, null, null);
// display the current temperature
tvCurrentTemp = (TextView) findViewById(R.id.tvCurrentTemp);
// display the update time stamp
tvTimestamp = (TextView) findViewById(R.id.tvTimestamp);
// display the date of today
tvDate = (TextView) findViewById(R.id.tvDate);
// display the wind speed
tvWindSpeed = (TextView) findViewById(R.id.tvWindSpeed);
// Set wind speed icon
tvWindSpeed.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_wind), null, null, null);
// display the pressure
tvPressure = (TextView) findViewById(R.id.tvPressure);
// Set wind speed icon
tvPressure.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_pressure), null, null, null);
// visualize the current weather condition
ivCurrentWeather = (ImageView) findViewById(R.id.ivCurrentWeather);
// Scrollable forecast
forecastGallery = (HorizontalViewGallery) findViewById(R.id.gForcast);
// Search city button
ivSearch = (ImageView) findViewById(R.id.ivSearch);
// Setting button
ivRemind = (ImageView) findViewById(R.id.ivRemind);
// My location button
ivMyLocation = (ImageView) findViewById(R.id.ivMyLocation);
// Temp unit setting Button
ivUnit = (ImageView) findViewById(R.id.ivUnit);
if (getTempUnit().equals(PARAM_TEMP_UNIT_C))
ivUnit.setImageDrawable(getResources().getDrawable(
R.drawable.button_unit_f));
else if (getTempUnit().equals(PARAM_TEMP_UNIT_F))
ivUnit.setImageDrawable(getResources().getDrawable(
R.drawable.button_unit_c));
// Refresh button
ivRefresh = (ImageView) findViewById(R.id.ivRefresh);
// Search field
etSearch = (MyCustomEditText) findViewById(R.id.etSearch);
// set the animation of search field
// Animation Duration in milliseconds;
int duration = 500;
// Inflate animation
final AnimationSet inflate = new AnimationSet(true);
ScaleAnimation scaleIn = new ScaleAnimation(0f, 1.0f, 1.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
0.5f);
scaleIn.setDuration(duration);
inflate.addAnimation(scaleIn);
inflate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
etSearch.setVisibility(View.VISIBLE);
etSearch.requestFocus();
showSoftKeyboard(etSearch);
}
});
// Deflate animation
final AnimationSet deflate = new AnimationSet(true);
ScaleAnimation scaleDe = new ScaleAnimation(1.0f, 0f, 1.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
0.5f);
scaleDe.setDuration(duration);
deflate.addAnimation(scaleDe);
deflate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
etSearch.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
hideSoftKeyboard(etSearch);
}
});
etSearch.setInflation(inflate);
etSearch.setDeflation(deflate);
// Running the change of digital clock on separate UI thread
// to avoid any delay of other action on UI.
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!Utils.androidMinimum(API_JELLY_BEAN_MR1)) {
// Using the widget class {@code DigitalClock} if the
// android api is less than 17
DigitalClock dcClock = (DigitalClock) findViewById(R.id.dcClock);
dcClock.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s,
int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
// Removed seconds
if (s.length() >= 5) {
if (s.charAt(4) == ':') {
s.delete(4, s.length());
} else if (s.length() >= 6
&& s.charAt(5) == ':') {
s.delete(5, s.length());
}
}
}
});
} else {
// Using the widget class {@code TextClock} if the android
// api is greater than or equal to 17
TextClock dcClock = (TextClock) findViewById(R.id.dcClock);
dcClock.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s,
int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
// Removed seconds
if (s.length() >= 5) {
if (s.charAt(4) == ':') {
s.delete(4, s.length());
} else if (s.length() >= 6
&& s.charAt(5) == ':') {
s.delete(5, s.length());
}
}
}
});
}
}
});
mIconFinder = new IconFinder(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
mLocationClient = new LocationClient(this, this, this);
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
setContentView(R.layout.activity_main);
.
.
.
请您解释一下,管理新权限系统的最佳方式是什么。请用简单的方式给我解释一下
粗略和精细的位置被认为是危险的权限。必须在 Android 6 及更高版本上明确请求这些权限。这是一种解决方法:
public void checkPermission(){
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
){//Can add more as per requirement
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},
123);
}
}
并调用:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkPermission();
}
您可以在任何地方实施它。您可以在第一次启动时请求它,也可以在需要时请求它。
尽管如此,始终记得在使用前检查您是否有权限。该权限也可以在运行时撤销,这将绕过您在启动时进行的任何检查。
这是一种方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
This is called before initializing the map because the map needs permissions(the cause of the crash)
*/
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M ) {
checkPermission();
}
// Re-check before enabling. You can add an else statement to warn the user about the lack of functionality if it's disabled.
// "or" is used instead of "and" as per the error. If it requires both, flip it over to &&. (I'm not sure, I haven't used GPS stuff before)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
mLocationClient = new LocationClient(this, this, this);
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
setContentView(R.layout.activity_main);
.
.
.
这是我推荐的方法。还有其他处理权限的方法,但无论您选择什么,请确保在访问依赖于危险权限的 API 之前检查您是否拥有该权限。可以在运行时撤销权限,而不会触发 destroy 生命周期事件,因此可以绕过启动时进行的任何检查以确保您拥有权限。因此,在使用 APIs 之前进行检查非常重要。
还有其他方法可以实现权限请求。如果您正在寻找这种超级基本启动检查的替代方法,这里有一些想法:
- 如果您有设置 activity,请向其添加权限请求。
- 不要在启动时请求权限,而是在需要时请求权限
- 如果权限检查在启动时失败
,请将权限请求 activity 添加到您的启动流程
还有比我知道的更多的方法来解决这个问题。我已经有几年没碰过 Android 了,而且我对所有请求权限的方式都不熟悉。另请参阅 the documentation 以获取可能更新的建议。
我在另一个应用程序中使用了一个模块。在我实现模块之前,我将它设置为 API 级别 23(编译和目标),就像我的主项目一样 这工作正常,除了这个错误。问题是,Google 自 marshmellow 以来更改了权限管理。最后,我不知道应该如何以及在哪里设置权限。
我在启动应用程序时遇到的错误:
java.lang.SecurityException: Client must have ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to perform any operations location.
能否请您帮我简单解释一下(我需要什么样的代码以及在哪里插入)以避免这个错误?
来自模块的清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cs.android.weminder">
<!--
android:versionCode="3"
android:versionName="1.2.0" >
<uses-sdk
android:minSdkVersion="9"
android:targetSdkVersion="19" />
-->
<!-- Grant the network access permission -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<!-- Grant the location access permission -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Permission required to use Alarm Manager -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:allowBackup="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- android:name="com.cs.android.weminder.MyApplication"
android:label="@string/app_name">-->
<!-- This meta-data tag is required to use Google Play Services. -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<!-- Required for creating dialog of the ACRA report -->
<activity
android:name="org.acra.CrashReportDialog"
android:excludeFromRecents="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
android:theme="@style/AcraDialog" />
<activity
android:name="com.cs.android.weminder.MainActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait" >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</activity>
<activity android:name="com.cs.android.weminder.BaseScreen" />
<activity android:name="com.cs.android.weminder.LocationBaseScreen" />
<activity android:name="com.cs.android.weminder.SettingsActivity" />
<activity android:name="com.cs.android.weminder.WeminderApplication" />
<!-- Required by the AdMob Ads SDK -->
<activity
android:name="com.google.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
<!-- Include the AdActivity configChanges and theme. -->
<activity
android:name="com.google.android.gms.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
android:theme="@android:style/Theme.Translucent" />
<receiver
android:name="com.cs.android.weminder.AlarmReceiver"
android:process=":remote" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service android:name="com.cs.android.weminder.AlarmService" >
</service>
</application>
主要 Activity 来自模块:
public class MainActivity extends SettingsActivity implements ActionTypes,
ResultType {
private TextView tvLocation, tvHTemp, tvLTemp, tvCurrentTemp, tvTimestamp,
tvDate, tvWindSpeed, tvPressure;
private ImageView ivCurrentWeather, ivRefresh, ivUnit, ivSearch, ivRemind,
ivMyLocation;
private HorizontalViewGallery forecastGallery;
// Search field
private MyCustomEditText etSearch;
// holding different weather icons presenting weather condition
// alternatively.
private IconFinder mIconFinder;
private ApiCallQueue requestsQueue = new ApiCallQueue();
// Ads View
private AdView adView;
private void setupUI(View view) {
// Set up touch listener for non-text box views to hide keyboard.
if (!(view instanceof EditText)) {
view.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// Hide the search field if the user is touching anywhere
// except the search field
if (etSearch.isShown()) {
etSearch.startDeflation();
return true;
}
return false;
}
});
}
// If a layout container, iterate over children and seed recursion.
if (view instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
View innerView = ((ViewGroup) view).getChildAt(i);
setupUI(innerView);
}
}
}
/**
* Initial the UI of current screen Initial variables;
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void initialActivity() {
setupUI(findViewById(R.id.parent));
// display the name of location
tvLocation = (TextView) findViewById(R.id.tvLocation);
// Set the location icon
tvLocation.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_marker), null, null, null);
// display today highest temperature
tvHTemp = (TextView) findViewById(R.id.tvHTemp);
// Set the highest temperature icon
tvHTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_highest), null, null, null);
// display today lowest temperature
tvLTemp = (TextView) findViewById(R.id.tvLTemp);
// Set the lowest temperature icon
tvLTemp.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_lowest), null, null, null);
// display the current temperature
tvCurrentTemp = (TextView) findViewById(R.id.tvCurrentTemp);
// display the update time stamp
tvTimestamp = (TextView) findViewById(R.id.tvTimestamp);
// display the date of today
tvDate = (TextView) findViewById(R.id.tvDate);
// display the wind speed
tvWindSpeed = (TextView) findViewById(R.id.tvWindSpeed);
// Set wind speed icon
tvWindSpeed.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_wind), null, null, null);
// display the pressure
tvPressure = (TextView) findViewById(R.id.tvPressure);
// Set wind speed icon
tvPressure.setCompoundDrawablesWithIntrinsicBounds(getResources()
.getDrawable(R.drawable.icon_pressure), null, null, null);
// visualize the current weather condition
ivCurrentWeather = (ImageView) findViewById(R.id.ivCurrentWeather);
// Scrollable forecast
forecastGallery = (HorizontalViewGallery) findViewById(R.id.gForcast);
// Search city button
ivSearch = (ImageView) findViewById(R.id.ivSearch);
// Setting button
ivRemind = (ImageView) findViewById(R.id.ivRemind);
// My location button
ivMyLocation = (ImageView) findViewById(R.id.ivMyLocation);
// Temp unit setting Button
ivUnit = (ImageView) findViewById(R.id.ivUnit);
if (getTempUnit().equals(PARAM_TEMP_UNIT_C))
ivUnit.setImageDrawable(getResources().getDrawable(
R.drawable.button_unit_f));
else if (getTempUnit().equals(PARAM_TEMP_UNIT_F))
ivUnit.setImageDrawable(getResources().getDrawable(
R.drawable.button_unit_c));
// Refresh button
ivRefresh = (ImageView) findViewById(R.id.ivRefresh);
// Search field
etSearch = (MyCustomEditText) findViewById(R.id.etSearch);
// set the animation of search field
// Animation Duration in milliseconds;
int duration = 500;
// Inflate animation
final AnimationSet inflate = new AnimationSet(true);
ScaleAnimation scaleIn = new ScaleAnimation(0f, 1.0f, 1.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
0.5f);
scaleIn.setDuration(duration);
inflate.addAnimation(scaleIn);
inflate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
etSearch.setVisibility(View.VISIBLE);
etSearch.requestFocus();
showSoftKeyboard(etSearch);
}
});
// Deflate animation
final AnimationSet deflate = new AnimationSet(true);
ScaleAnimation scaleDe = new ScaleAnimation(1.0f, 0f, 1.0f, 1.0f,
Animation.RELATIVE_TO_SELF, 1.0f, Animation.RELATIVE_TO_SELF,
0.5f);
scaleDe.setDuration(duration);
deflate.addAnimation(scaleDe);
deflate.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation animation) {
etSearch.setVisibility(View.INVISIBLE);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationStart(Animation animation) {
hideSoftKeyboard(etSearch);
}
});
etSearch.setInflation(inflate);
etSearch.setDeflation(deflate);
// Running the change of digital clock on separate UI thread
// to avoid any delay of other action on UI.
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!Utils.androidMinimum(API_JELLY_BEAN_MR1)) {
// Using the widget class {@code DigitalClock} if the
// android api is less than 17
DigitalClock dcClock = (DigitalClock) findViewById(R.id.dcClock);
dcClock.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s,
int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
// Removed seconds
if (s.length() >= 5) {
if (s.charAt(4) == ':') {
s.delete(4, s.length());
} else if (s.length() >= 6
&& s.charAt(5) == ':') {
s.delete(5, s.length());
}
}
}
});
} else {
// Using the widget class {@code TextClock} if the android
// api is greater than or equal to 17
TextClock dcClock = (TextClock) findViewById(R.id.dcClock);
dcClock.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
}
@Override
public void beforeTextChanged(CharSequence s,
int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
// Removed seconds
if (s.length() >= 5) {
if (s.charAt(4) == ':') {
s.delete(4, s.length());
} else if (s.length() >= 6
&& s.charAt(5) == ':') {
s.delete(5, s.length());
}
}
}
});
}
}
});
mIconFinder = new IconFinder(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
mLocationClient = new LocationClient(this, this, this);
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
setContentView(R.layout.activity_main);
.
.
.
请您解释一下,管理新权限系统的最佳方式是什么。请用简单的方式给我解释一下
粗略和精细的位置被认为是危险的权限。必须在 Android 6 及更高版本上明确请求这些权限。这是一种解决方法:
public void checkPermission(){
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
){//Can add more as per requirement
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION},
123);
}
}
并调用:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
checkPermission();
}
您可以在任何地方实施它。您可以在第一次启动时请求它,也可以在需要时请求它。
尽管如此,始终记得在使用前检查您是否有权限。该权限也可以在运行时撤销,这将绕过您在启动时进行的任何检查。
这是一种方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*
This is called before initializing the map because the map needs permissions(the cause of the crash)
*/
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M ) {
checkPermission();
}
// Re-check before enabling. You can add an else statement to warn the user about the lack of functionality if it's disabled.
// "or" is used instead of "and" as per the error. If it requires both, flip it over to &&. (I'm not sure, I haven't used GPS stuff before)
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
ContextCompat.checkSelfPermission(this,Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED){
/*
* Create a new location client, using the enclosing class to handle
* callbacks.
*/
mLocationClient = new LocationClient(this, this, this);
// Create the LocationRequest object
mLocationRequest = LocationRequest.create();
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the update interval to 5 seconds
mLocationRequest.setInterval(UPDATE_INTERVAL);
// Set the fastest update interval to 1 second
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
}
setContentView(R.layout.activity_main);
.
.
.
这是我推荐的方法。还有其他处理权限的方法,但无论您选择什么,请确保在访问依赖于危险权限的 API 之前检查您是否拥有该权限。可以在运行时撤销权限,而不会触发 destroy 生命周期事件,因此可以绕过启动时进行的任何检查以确保您拥有权限。因此,在使用 APIs 之前进行检查非常重要。
还有其他方法可以实现权限请求。如果您正在寻找这种超级基本启动检查的替代方法,这里有一些想法:
- 如果您有设置 activity,请向其添加权限请求。
- 不要在启动时请求权限,而是在需要时请求权限
- 如果权限检查在启动时失败 ,请将权限请求 activity 添加到您的启动流程
还有比我知道的更多的方法来解决这个问题。我已经有几年没碰过 Android 了,而且我对所有请求权限的方式都不熟悉。另请参阅 the documentation 以获取可能更新的建议。