更新
下面的原始答案是使用 Java 和现已弃用的 SettingsApi。
这是使用 Kotlin 和 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) { }
}
}
}
}
在MainActivity中,定义常量:
companion object {
const val LOCATION_SETTING_REQUEST = 999
}
原始答案:
看起来主要问题是您将所有代码都放在了 Fragment 中,并且由于 startResolutionForResult() 需要将 Activity 传递给它,因此 Activity 是获得 onActivityResult() 回调的原因。
解决这个问题的一种方法是使用here 描述的技术,当结果进来时,从 Activity 手动调用 Fragment 的 onActivityResult() 方法。
我刚刚完成了这个简单的示例。
首先是Activity,它添加了Fragment,并且还具有将onActivityResult()的结果传递给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);
}
}
}
这是片段,它包含显示对话框和处理结果的所有功能。在这个简单的示例中,我只是使用 Toast 消息来验证它是否按预期工作。请注意,我在这里对您问题中的代码所做的主要更改是使用getActivity() 来获取调用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) {
}
}
以下是视觉结果,如果位置模式被禁用,则首先显示对话框:
然后,如果用户点击否,结果会从 Activity 传递到 Fragment,其中显示一个 Toast:
当用户点击是,但结果是成功,并且启用了定位模式时,情况相同:
请注意,最好将所有这些功能保留在 Activity 中,然后在结果到来时调用 Fragment 中的公共方法。
这是用于在 Activity 中保留功能的完整工作代码。
当然在这个解决方案中,你需要在调用onActivityResult()之后,在Fragment中添加一个调用来更新Location Mode的状态。
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) {
}
}