我的部分应用需要定位服务,所以如果定位当前处于关闭状态,应用会提示用户启用它.
然后,如果用户点击否,结果会从 Activity 传递到 Fragment,其中显示一个 Toast:
当用户点击是,但结果是成功,并且启用了定位模式时,情况相同:
请注意,最好将所有这些功能保留在 Activity 中,然后在结果到来时调用 Fragment 中的公共方法.
这是用于在 Activity 中保留功能的完整工作代码.当然,在这个解决方案中,您需要在调用 onActivityResult()
之后,在 Fragment 中添加一个调用来更新 Location Mode 的状态.
公共类 MainActivity 扩展 AppCompatActivity实现 GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener {LocationRequest 位置请求;GoogleApiClient mGoogleApiClient;待定结果<位置设置结果>结果;最终静态 int REQUEST_LOCATION = 199;@覆盖protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mGoogleApiClient = new GoogleApiClient.Builder(this).addApi(LocationServices.API).addConnectionCallbacks(这个).addOnConnectionFailedListener(this).build();mGoogleApiClient.connect();}@覆盖公共无效 onConnected(捆绑包){mLLocationRequest = LocationRequest.create();mLLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);mLocationRequest.setInterval(30 * 1000);mLocationRequest.setFastestInterval(5 * 1000);LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder().addLocationRequest(mLocationRequest);builder.setAlwaysShow(true);结果 = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());result.setResultCallback(new ResultCallback<LocationSettingsResult>() {@覆盖公共无效 onResult(LocationSettingsResult 结果){最终状态状态 = result.getStatus();//final LocationSettingsStates state = result.getLocationSettingsStates();开关 (status.getStatusCode()) {案例 LocationSettingsStatusCodes.SUCCESS://满足所有位置设置.客户端可以初始化位置//在这里请求.//...休息;案例 LocationSettingsStatusCodes.RESOLUTION_REQUIRED://位置设置不满足.但可以通过向用户展示来修复//一个对话框.尝试 {//通过调用 startResolutionForResult() 显示对话框,//并在 onActivityResult() 中检查结果.status.startResolutionForResult(MainActivity.this,请求位置);} 捕捉(SendIntentException e){//忽略错误.}休息;案例 LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE://位置设置不满足.但是,我们没有办法修复//设置所以我们不会显示对话框.//...休息;}}});}@覆盖public void onActivityResult(int requestCode, int resultCode, Intent data){Log.d(onActivityResult()", Integer.toString(resultCode));//final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);开关(请求代码){案例 REQUEST_LOCATION:开关(结果代码){案例活动.RESULT_OK:{//所有需要的更改都已成功进行Toast.makeText(MainActivity.this, "位置由用户启用!", Toast.LENGTH_LONG).show();休息;}案例活动.RESULT_CANCELED:{//要求用户更改设置,但选择不更改Toast.makeText(MainActivity.this, "Location not enabled, user cancelled.", Toast.LENGTH_LONG).show();休息;}默认:{休息;}}休息;}}@覆盖公共无效 onConnectionSuspended(int i) {}@覆盖公共无效 onConnectionFailed(ConnectionResult connectionResult) {}}
Part of my app requires location services, so if location is currently turned off, the app will prompt the user to enable it. Here is how I am doing it: (Also seen in this Stack Overflow answer)
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
PendingResult<LocationSettingsResult> result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>()
{
@Override
public void onResult(LocationSettingsResult result)
{
final Status status = result.getStatus();
final LocationSettingsStates = result.getLocationSettingsStates();
switch (status.getStatusCode())
{
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
...
Log.d("onResult", "SUCCESS");
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
Log.d("onResult", "RESOLUTION_REQUIRED");
try
{
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(OuterClass.this, REQUEST_LOCATION);
}
catch (SendIntentException e)
{
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
...
Log.d("onResult", "UNAVAILABLE");
break;
}
}
});
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
// This log is never called
Log.d("onActivityResult()", Integer.toString(resultCode));
final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode)
{
case REQUEST_LOCATION:
switch (resultCode)
{
case Activity.RESULT_OK:
{
// All required changes were successfully made
break;
}
case Activity.RESULT_CANCELED:
{
// The user was asked to change settings, but chose not to
break;
}
default:
{
break;
}
}
break;
}
}
This code works well, however, onActivityResult()
is always skipped. Whether or not the user presses Yes
, No
, or back
from the Dialog
, onActivityResult()
doesn't run.
I need Android to call onActivityResult()
so if the user chooses not to turn on location services, I can handle it appropriately.
Google's developer page (and the code above) explicitly says that onActivityResult()
should be called. Anyone know why it's being skipped?
I also don't know what the purpose of this line is:
final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
Thanks!
Edit: Basic information on the structure of my app:
onResume()
method of a Fragment
which implements GoogleApiClient.ConnectionCallbacks
, GoogleApiClient.OnConnectionFailedListener
, and LocationListener
to receive location updates. Example seen here.onLocationChanged()
the Fragment
will have a custom View
call invalidate()
and re-draw itself with updated information.UPDATE
The original answer below is using Java and the now deprecated SettingsApi.
Here is a more modern approach using Kotlin and SettingsClient:
fun showEnableLocationSetting() {
activity?.let {
val locationRequest = LocationRequest.create()
locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(locationRequest)
val task = LocationServices.getSettingsClient(it)
.checkLocationSettings(builder.build())
task.addOnSuccessListener { response ->
val states = response.locationSettingsStates
if (states.isLocationPresent) {
//Do something
}
}
task.addOnFailureListener { e ->
if (e is ResolvableApiException) {
try {
// Handle result in onActivityResult()
e.startResolutionForResult(it,
MainActivity.LOCATION_SETTING_REQUEST)
} catch (sendEx: IntentSender.SendIntentException) { }
}
}
}
}
In MainActivity, define the constant:
companion object {
const val LOCATION_SETTING_REQUEST = 999
}
ORIGINAL ANSWER:
It looks like the main issue is that you have all of the code in a Fragment, and since startResolutionForResult()
needs an Activity passed into it, the Activity is what gets the onActivityResult()
callback.
One way to get around that is to use the technique described here, manually call the Fragment's onActivityResult()
method from the Activity when the result comes in.
I just got this simple example working.
First, the Activity, which adds the Fragment, and also has functionality to pass along the result of onActivityResult()
to the Fragment:
public class MainActivity extends AppCompatActivity{
LocationFragment lFrag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lFrag = LocationFragment.newInstance();
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, lFrag).commit();
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LocationFragment.REQUEST_LOCATION){
lFrag.onActivityResult(requestCode, resultCode, data);
}
else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
Here is the Fragment, which contains all of the functionality to show the dialog, and handle the result. In this simple example I just used Toast messages to verify that it is working as expected. Note that the main change that I've made here from the code in your question is the use of getActivity()
to get the Activity reference needed for the call to startResolutionForResult()
.
public class LocationFragment extends Fragment
implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
PendingResult<LocationSettingsResult> result;
final static int REQUEST_LOCATION = 199;
public static LocationFragment newInstance() {
LocationFragment fragment = new LocationFragment();
return fragment;
}
public LocationFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_location, container, false);
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(30 * 1000);
mLocationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
//final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
//...
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(
getActivity(),
REQUEST_LOCATION);
} catch (IntentSender.SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
//...
break;
}
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.d("onActivityResult()", Integer.toString(resultCode));
//final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode)
{
case REQUEST_LOCATION:
switch (resultCode)
{
case Activity.RESULT_OK:
{
// All required changes were successfully made
Toast.makeText(getActivity(), "Location enabled by user!", Toast.LENGTH_LONG).show();
break;
}
case Activity.RESULT_CANCELED:
{
// The user was asked to change settings, but chose not to
Toast.makeText(getActivity(), "Location not enabled, user cancelled.", Toast.LENGTH_LONG).show();
break;
}
default:
{
break;
}
}
break;
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
Here are the results visually, first the dialog is shown if Location Mode is disabled:
Then, if the user clicks No, the result is passed from the Activity to the Fragment, which shows a Toast:
Same thing when the user clicks Yes, but with a success result, and Location Mode is enabled:
Note that it might be a better option to just keep all of this functionality in the Activity, and then call into a public method in the Fragment when the result comes in.
Here is fully working code for keeping the functionality in the Activity.
Of course in this solution, you would need to add a call into the Fragment to update the state of Location Mode after onActivityResult()
is called.
public class MainActivity extends AppCompatActivity
implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
PendingResult<LocationSettingsResult> result;
final static int REQUEST_LOCATION = 199;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
mGoogleApiClient.connect();
}
@Override
public void onConnected(Bundle bundle) {
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setInterval(30 * 1000);
mLocationRequest.setFastestInterval(5 * 1000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest);
builder.setAlwaysShow(true);
result = LocationServices.SettingsApi.checkLocationSettings(mGoogleApiClient, builder.build());
result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
@Override
public void onResult(LocationSettingsResult result) {
final Status status = result.getStatus();
//final LocationSettingsStates state = result.getLocationSettingsStates();
switch (status.getStatusCode()) {
case LocationSettingsStatusCodes.SUCCESS:
// All location settings are satisfied. The client can initialize location
// requests here.
//...
break;
case LocationSettingsStatusCodes.RESOLUTION_REQUIRED:
// Location settings are not satisfied. But could be fixed by showing the user
// a dialog.
try {
// Show the dialog by calling startResolutionForResult(),
// and check the result in onActivityResult().
status.startResolutionForResult(
MainActivity.this,
REQUEST_LOCATION);
} catch (SendIntentException e) {
// Ignore the error.
}
break;
case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE:
// Location settings are not satisfied. However, we have no way to fix the
// settings so we won't show the dialog.
//...
break;
}
}
});
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.d("onActivityResult()", Integer.toString(resultCode));
//final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode)
{
case REQUEST_LOCATION:
switch (resultCode)
{
case Activity.RESULT_OK:
{
// All required changes were successfully made
Toast.makeText(MainActivity.this, "Location enabled by user!", Toast.LENGTH_LONG).show();
break;
}
case Activity.RESULT_CANCELED:
{
// The user was asked to change settings, but chose not to
Toast.makeText(MainActivity.this, "Location not enabled, user cancelled.", Toast.LENGTH_LONG).show();
break;
}
default:
{
break;
}
}
break;
}
}
@Override
public void onConnectionSuspended(int i) {
}
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
}
这篇关于启用 GPS 的 LocationSettingsRequest 对话框 - 跳过了 onActivityResult()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!