Android 如何始终在后台运行服务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2566350/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to always run a service in the background?
提问by Thomas H
I am in the process of creating an app that is similar to the built-in SMS app.
我正在创建一个类似于内置短信应用程序的应用程序。
What I need:
我需要的:
- a service that is always running in the background
- every 5 min. the service checks the current location of the device and calls a web service
- if certain criteria are met, the service should generate a notification (just like the SMS app)
- when the notification is clicked, the user is taken to the app (just like the SMS app)
- when the app is installed the service should be started
- when the device is rebooted, the service should be started
- 始终在后台运行的服务
- 每 5 分钟。该服务检查设备的当前位置并调用网络服务
- 如果满足某些条件,该服务应生成通知(就像 SMS 应用程序一样)
- 当点击通知时,用户被带到应用程序(就像短信应用程序一样)
- 安装应用程序后,应启动服务
- 当设备重新启动时,应该启动服务
What I have tried:
- running a regular service which worked just fine until Android kills the service
- using the AlarmManager to make the 5 min. interval call to a service. But I was not able to make this work.
我尝试过的:
- 运行一个正常的服务,直到 Android
终止该服务- 使用 AlarmManager 进行 5 分钟。对服务的间隔调用。但我无法完成这项工作。
回答by CommonsWare
a service that is always running in the background
始终在后台运行的服务
This is not possiblein any real sense of the term, as you have discovered. It is also bad design.
正如您所发现的,这在该术语的任何真正意义上都是不可能的。这也是糟糕的设计。
every 5 min. the service checks the current location of the device and calls a web service
每 5 分钟。该服务检查设备的当前位置并调用网络服务
Use AlarmManager
.
使用AlarmManager
.
using the AlarmManager the make the 5 min. interval call to a service. But I was not able to make this work.
使用 AlarmManager 使 5 分钟。对服务的间隔调用。但我无法完成这项工作。
Here is a sample projectshowing how to use one, along with the use of WakefulIntentService
so you stay awake while trying to do the whole Web service thing.
这是一个示例项目,展示了如何使用它,以及如何使用 ,WakefulIntentService
以便您在尝试完成整个 Web 服务的同时保持清醒。
If you have continued problems with it, open up a new question about the specific things you are encountering with AlarmManager
that are giving you grief.
如果您仍然遇到问题,请提出一个关于您遇到AlarmManager
的让您感到悲伤的具体事情的新问题。
回答by Jim Blackler
One of my apps does something very similar. To wake the service after a given period I recommend postDelayed()
我的一个应用程序做了一些非常相似的事情。我建议在给定时间段后唤醒服务postDelayed()
Have a handler field:
有一个处理程序字段:
private final Handler handler = new Handler();
and a refresher Runnable
和复习 Runnable
private final Runnable refresher = new Runnable() {
public void run() {
// some action
}
};
You can fire your Notifications in the runnable.
您可以在 runnable 中触发您的通知。
On service construction, and after each execution start it like so:
在服务构建上,在每次执行后像这样启动它:
handler.postDelayed(refresher, /* some delay in ms*/);
In onDestroy()
remove the post
在onDestroy()
删除帖子
handler.removeCallbacks(refresher);
To start the service at boot time you need an auto starter. This goes in your manifest
要在启动时启动服务,您需要一个自动启动器。这在你的清单中
<receiver android:name="com.example.ServiceAutoStarter">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
and the ServiceAutoStarter
looks like this:
和ServiceAutoStarter
看起来像这样:
public class ServiceAutoStarter extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, UpdateService.class));
}
}
Stopping the OS from killing the service is tricky. Also your application can have a RuntimeException
and crash, or your logic can stall.
阻止操作系统终止服务是很棘手的。此外,您的应用程序可能会RuntimeException
崩溃,或者您的逻辑可能会停止。
In my case it seemed to help to always refresh the service on screen on with a BroadcastReceiver
. So if the chain of updates gets stalled it will be resurrected as the user uses their phone.
就我而言,总是使用BroadcastReceiver
. 因此,如果更新链停滞不前,它将在用户使用手机时重新启动。
In the service:
在服务中:
private BroadcastReceiver screenOnReceiver;
In your service onCreate()
为您服务 onCreate()
screenOnReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// Some action
}
};
registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
Then unregister your service on onDestroy()
with
然后注销您的服务上onDestroy()
与
unregisterReceiver(screenOnReceiver);
回答by Manoj Srivastava
You can do this by some simple implementation:
您可以通过一些简单的实现来做到这一点:
public class LocationTrace extends Service implements LocationListener{
// The minimum distance to change Updates in meters
private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
private static final int TWO_MINUTES = 100 * 10;
// The minimum time between updates in milliseconds
private static final long MIN_TIME_BW_UPDATES = 1000 * 10; // 30 seconds
private Context context;
double latitude;
double longitude;
Location location = null;
boolean isGPSEnabled = false;
boolean isNetworkEnabled = false;
protected LocationManager locationManager;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
this.context = this;
get_current_location();
// Toast.makeText(context, "Lat"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
return START_STICKY;
}
@Override
public void onLocationChanged(Location location) {
if((location != null) && (location.getLatitude() != 0) && (location.getLongitude() != 0)){
latitude = location.getLatitude();
longitude = location.getLongitude();
if (!Utils.getuserid(context).equalsIgnoreCase("")) {
Double[] arr = { location.getLatitude(), location.getLongitude() };
// DO ASYNCTASK
}
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
/*
* Get Current Location
*/
public Location get_current_location(){
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if(!isGPSEnabled && !isNetworkEnabled){
}else{
if (isGPSEnabled) {
if (location == null) {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(context, "Latgps"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
}
}
}
}
if (isNetworkEnabled) {
locationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER,
MIN_TIME_BW_UPDATES,
MIN_DISTANCE_CHANGE_FOR_UPDATES, this);
if (locationManager != null) {
if (location != null) {
latitude = location.getLatitude();
longitude = location.getLongitude();
// Toast.makeText(context, "Latgps1"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
}
}
}
}
return location;
}
public double getLatitude() {
if(location != null){
latitude = location.getLatitude();
}
return latitude;
}
public double getLongitude() {
if(location != null){
longitude = location.getLongitude();
}
return longitude;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
if(locationManager != null){
locationManager.removeUpdates(this);
}
super.onDestroy();
}
}
You can start service by this :
您可以通过以下方式启动服务:
/*--Start Service--*/
startService(new Intent(Splash.this, LocationTrace.class));
In manifest:
在清单中:
<service android:name=".LocationTrace">
<intent-filter android:priority="1000">
<action android:name="android.location.PROVIDERS_CHANGED"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
回答by MHSFisher
by these three steps, you can wake every 5 minutes most of the Android devices :
通过这三个步骤,您可以每 5 分钟唤醒大多数 Android 设备:
1. set your alternative AlarmManager for diffrent APIs :
1. 为不同的 API 设置您的替代 AlarmManager:
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);
if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
2. build your own static BroadcastReceiver :
2. 构建你自己的静态 BroadcastReceiver :
public static class OwnReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//do all of your jobs here
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(context, OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
}
}
3. add <receiver>
to AndroidManifest.xml
:
3.添加<receiver>
到AndroidManifest.xml
:
<receiver android:name=".OwnReceiver" />
回答by Siddhartho Dhar
According to me when you want your service to run always means that it shouldn't get stopped when the app is killed, because if your app is running or is in the background anyways your service will be running. When you kill the app while a service is running the onTaskRemoved function is triggered.
根据我的说法,当您希望您的服务运行时,意味着它不应在应用程序被终止时停止,因为如果您的应用程序正在运行或在后台,无论如何您的服务都将运行。当您在服务运行时终止应用程序时,将触发 onTaskRemoved 函数。
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.d(TAG, "onTaskRemoved: removed");
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis() + 10000);
((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), RegisterReceiverService.class), 0));
super.onTaskRemoved(rootIntent);
}
So basically once you kill the app the service will be started after 10 seconds. Note: In case you want to use
所以基本上一旦你杀死应用程序,服务将在 10 秒后启动。注意:如果您想使用
AlarmManager.ELAPSED_REALTIME_WAKEUP
the minimum time after which you'll be able to restart the service will be 15 minutes.
您可以重新启动服务的最短时间为 15 分钟。
Remember you also need to start the service on reboot using BroadcastReceiver.
请记住,您还需要在重新启动时使用 BroadcastReceiver 启动服务。