使用新的定位API减少摩擦
原标题:Reduce friction with the new Location APIs
链接:https://android-developers.googleblog.com/2017/06/reduce-friction-with-new-location-apis.html
作者:Aaron Stacy (Google Play服务软件工程师)
翻译:arjinmc
11.0.0版Google Play服务SDK包含了一种访问LocationServices的新方式 。新的API不需要你的应用来手动管理与Google Play服务的连接GoogleApiClient。这减少了你的应用程序中的样板和常见陷阱。
请阅读下面的更多内容,或者直接访问GitHub上更新的位置示例。
为什么不使用GoogleApiClient?
LocationServices API允许你访问设备位置,设置geo(地理围栏),提示用户启用设备上的位置等。为了访问这些服务,该应用必须连接到Google Play服务,这可能涉及容易出错的连接逻辑。例如,你可以在下面的应用程序中发现崩溃吗?
注意:我们假设我们的应用程序具有 ACCESS_FINE_LOCATION使用LocationServices API获取用户确切位置所需的权限。
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GoogleApiClient client = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(LocationServices.API)
.build();
client.connect();
PendingResult result =
LocationServices.FusedLocationApi.requestLocationUpdates(
client, LocationRequest.create(), pendingIntent);
result.setResultCallback(new ResultCallback() {
@Override
public void onResult(@NonNull Status status) {
Log.d(TAG, "Result: " + status.getStatusMessage());
}
});
}
// ...
}
如果你指着requestLocationUpdates()的调用,你是对的!那个调用会抛出一个IllegalStateException,因为 GoogleApiClient还没有连接。调用connect()是异步的。
虽然上面的代码看起来应该起作用,但是它缺少一个ConnectionCallbacks参数给GoogleApiClient构建器。呼叫请求位置更新只能在onConnected回调触发后进行:
public class MainActivity extends AppCompatActivity implements
GoogleApiClient.OnConnectionFailedListener,
GoogleApiClient.ConnectionCallbacks {
private GoogleApiClient client;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
client = new GoogleApiClient.Builder(this)
.enableAutoManage(this, this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.build();
client.connect();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
PendingResult result =
LocationServices.FusedLocationApi.requestLocationUpdates(
client, LocationRequest.create(), pendingIntent);
result.setResultCallback(new ResultCallback() {
@Override
public void onResult(@NonNull Status status) {
Log.d(TAG, "Result: " + status.getStatusMessage());
}
});
}
// ...
}
现在的代码可以工作,但它不理想,由于以下几个原因:
- 如果你想要在多个Activity中访问位置服务,那么很难将其重构为共享类。
- onCreate即使在稍后(例如,在用户输入之后)不需要位置服务,应用程序也会乐观地连接。
- 它无法处理应用程序无法连接到Google Play服务的情况。
- 开始进行位置更新之前,有很多样板连接逻辑。
更好的开发者体验
新的LocationServicesAPI更简单,并且使你的代码更少出错。连接逻辑被自动处理,你只需要附加一个完成监听器:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FusedLocationProviderClient client =
LocationServices.getFusedLocationProviderClient(this);
client.requestLocationUpdates(LocationRequest.create(), pendingIntent)
.addOnCompleteListener(new OnCompleteListener() {
@Override
public void onComplete(@NonNull Task task) {
Log.d("MainActivity", "Result: " + task.getResult());
}
});
}
}
新的API可以通过以下几种方式改进代码:
- API调用自动等待服务连接建立,从而消除了onConnected在发出请求之前等待的需要。
- 它使用Task API,使编写异步操作变得更加容易。
- 代码是独立的,可以很容易地被移动到一个共享的实用程序类或类似的。
- 你不需要了解开始编码的底层连接过程。
所有回调发生了什么?
新的API会自动解决你的某些连接失败,因此你需要编写代码以提示用户更新Google Play服务。连接问题将失败任务回调到ApiException而不是在全局曝光的连接故障onConnectionFailed)方法:
client.requestLocationUpdates(LocationRequest.create(), pendingIntent)
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
if (e instanceof ApiException) {
Log.w(TAG, ((ApiException) e).getStatusMessage());
} else {
Log.w(TAG, e.getMessage());
}
}
});
自己尝试一下
在自己的应用程序中尝试使用新的LocationServicesAPI,或者转到GitHub上的Android paly位置示例,并查看更多示例,说明新客户端如何减少样板和简化逻辑。