我已经尝试了很多不同的方法来运行后台服务来获取用户的位置,但Android系统在一段时间后自动终止服务。 虽然它适用于某些设备,但不适用于大多数设备。 我正在构建类似于优步的应用程序。我希望在一段时间后更新驱动程序的位置,即使应用程序处于后台或前台,直到用户未将状态设置为脱机
您可以使用前台服务,它只是一个普通服务,前台中有一个持续的通知,它会停止操作系统以停止/终止您的服务进程。
顺便说一下,这并不能保证当设备进入低电耗模式或应用程序待机模式时,您的服务将提供 CPU/处理时间。
虽然您无法绕过这些打瞌睡、待机和电池优化,但我已经测试了一个技巧,通过在前台服务中创建唤醒锁并在单独的进程中启动该服务来避免这些优化。
希望对您有所帮助。
您可以使用Android提供的一些机制。
- 对于运行pre-Oreo的设备,您可以按原样使用后台服务,它应该大部分时间都存在,通过在清单文件中声明它来将其保留在单独的进程中。您还可以注册到设备启动完成广播,因此您将在设备重新启动时收到回调,然后您将有机会重新启动后台服务。对于运行 oreo+ 的设备,最可靠的方法是使用前台服务。确保您的服务在任何情况下都具有粘性。
- 设置 Fire 基地计划作业以在服务停止时重新启动服务
- 地理围栏策略以获取其他反馈
- 与警报管理器一起安排在服务停止时重新启动服务
- 使用谷歌活动识别API,您还可以获得回调,以获得更多机会提取更多位置信息
- 推送通知
我建议将所有策略与针对您的应用程序量身定制的策略结合使用,它们一起应该随时为您提供足够的用户位置。
是的,你可以这样做,但也许它会消耗更多的电池电量。 找到下面的代码,它会帮助你,
还有另一种使用移动位置的方法,Google发布了融合位置提供商,这对您的情况更有帮助。
1.在您的构建.gradle文件中添加Google位置分级线
实现 'com.google.android.gms:play-services-location:15.0.1'
2.使用定位服务获取用户位置
import android.Manifest;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationAvailability;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.uffizio.taskeye.BuildConfig;
import com.uffizio.taskeye.R;
import com.uffizio.taskeye.extra.Constants;
import com.uffizio.taskeye.ui.activity.MainActivity;
/**
* Created by Kintan on 16/8/18.
*/
public class LocationServiceDemo extends Service implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
public static LocationServiceDemo locationService;
private static GoogleApiClient mGoogleApiClient;
private static LocationRequest mLocationRequest;
private FusedLocationProviderClient mFusedProviderClient;
private MyLocationCallback mMyLocationCallback;
private Location curLocation;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
showNotificationAndStartForegroundService();
locationService = this;
init();
}
//Google location Api build
protected synchronized void buildGoogleApiClient() {
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
mGoogleApiClient.connect();
}
protected void createLocationRequest() {
mMyLocationCallback = new MyLocationCallback();
mLocationRequest = LocationRequest.create();
mLocationRequest.setInterval(5000);
mLocationRequest.setFastestInterval(3000);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
mLocationRequest.setSmallestDisplacement(5.0f);
requestUpdate();
}
//Start Foreground Service and Show Notification to user for Android O and higher Version
private void showNotificationAndStartForegroundService() {
final String CHANNEL_ID = BuildConfig.APPLICATION_ID.concat("_notification_id");
final int REQUEST_CODE = 1;
PendingIntent pendingIntent = PendingIntent.getActivity(this,
REQUEST_CODE, new Intent(this, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this,
CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setAutoCancel(false)
.setContentIntent(pendingIntent);
startForeground(Constants.NOTIFICATION_ID, notificationBuilder.build());
}
public void requestUpdate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
mFusedProviderClient.requestLocationUpdates(mLocationRequest, mMyLocationCallback,
Looper.myLooper());
}
public void removeUpdate() {
mFusedProviderClient.removeLocationUpdates(mMyLocationCallback);
}
@Override
public void onConnected(@Nullable Bundle bundle) {
createLocationRequest();
}
@Override
public void onConnectionSuspended(int i) {
buildGoogleApiClient();
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
buildGoogleApiClient();
}
private void init() {
buildGoogleApiClient();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mFusedProviderClient = LocationServices.getFusedLocationProviderClient(LocationServiceDemo.this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
return START_STICKY;
}
mFusedProviderClient.getLastLocation().addOnSuccessListener(location -> {
if (location != null) {
curLocation = location;
}
});
if (mGoogleApiClient.isConnected()) {
createLocationRequest();
} else {
buildGoogleApiClient();
}
return START_STICKY;
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
startService();
}
@Override
public void onLowMemory() {
super.onLowMemory();
startService();
}
@Override
public void onDestroy() {
super.onDestroy();
startService();
}
public void startService() {
startService(new Intent(LocationServiceDemo.this, LocationServiceDemo.class));
}
public class MyLocationCallback extends LocationCallback {
@Override
public void onLocationResult(LocationResult locationResult) {
//get your location here
if (locationResult.getLastLocation() != null) {
for (Location location : locationResult.getLocations()) {
curLocation = location;
}
}
}
@Override
public void onLocationAvailability(LocationAvailability locationAvailability) {
super.onLocationAvailability(locationAvailability);
}
}
private class MyBinder extends Binder {
LocationServiceDemo getService() {
return LocationServiceDemo.this;
}
}
}
3.最终授予访问权限的管理员权限,因此Android系统不会在一段时间后自动终止服务。
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class LocationHome extends AppCompatActivity {
private static final int REQUEST_CODE = 0;
private DevicePolicyManager mDPM;
private ComponentName mAdminName;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mAdminName = new ComponentName(this, DeviceAdmin.class);
Button button = new Button();
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Grant Admin Permission
if (mDPM.isAdminActive(mAdminName)) {
startService(new Intent(this, LocationService.class));
} else {
adminPermission();
}
}
});
}
public void adminPermission() {
try {
if (!mDPM.isAdminActive(mAdminName)) {
try {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION, "Click on Activate button to secure your application.");
startActivityForResult(intent, REQUEST_CODE);
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//Check Permission is granted or not
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_OK) {
startService(new Intent(this, LocationService.class));
} else {
if (!mDPM.isAdminActive(mAdminName)) {
adminPermission();
}
}
}
}
}
创建 XMl 文件夹添加device_admin.xml
<device-admin>
<uses-policies>
</uses-policies>
</device-admin>
并最终修改您的清单并享受。
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".common.MyApplication"
android:theme="@style/AppTheme">
<receiver
android:name=".ui.DeviceAdmin"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>
</application>