[英]Android service not restarting in lollipop
In my application, I use location based service in background. 在我的应用程序中,我在后台使用基于位置的服务。 So I need to restart my service when it gets destroyed.
因此我需要在销毁时重新启动我的服务。
But I got this message in logcat 但是我在logcat中收到了这条消息
Spurious death for ProcessRecord{320afaf6 20614:com.odoo.crm:my_odoo_gps_service/u0a391}, curProc for 20614: null ProcessRecord的虚假死亡{320afaf6 20614:com.odoo.crm:my_odoo_gps_service / u0a391},curProc for 20614:null
My service onTaskRemoved
我的服务
onTaskRemoved
@Override
public void onTaskRemoved(Intent rootIntent) {
System.out.println("onTaskRemoved called");
Intent restartServiceIntent = new Intent(App.getAppContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent =
PendingIntent.getService(App.getAppContext(), 1, restartServiceIntent,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService =
(AlarmManager) App.getAppContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
}
My service onDestroy 我的服务onDestroy
@Override
public void onDestroy() {
System.out.println("destroy service");
super.onDestroy();
wakeLock.release();
}
My service onStartCommand 我的服务onStartCommand
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
I don`t know what is the error. 我不知道错误是什么。 I searched both in google & stackoverflow.
我在google和stackoverflow中都进行了搜索。 All of them refer Service.START_STICKY .
所有这些都引用了Service.START_STICKY 。 but I already used it.
但我已经用过了。
Same service restart works in KitKat, but with some delay(~5 mins). 相同的服务重启在KitKat中有效,但有一些延迟(约5分钟)。
Any help is appreciated. 任何帮助表示赞赏。
You can restart it by using a BroadcasteReceiver
which handles the broadcast sent from onDestroy()
of your service. 您可以使用
BroadcasteReceiver
重新启动它, BroadcasteReceiver
处理从您的服务的onDestroy()
发送的广播。
How to do this: 这个怎么做:
StickyService.java StickyService.java
public class StickyService extends Service
{
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
sendBroadcast(new Intent("IWillStartAuto"));
}
@Override
public void onDestroy() {
super.onDestroy();
sendBroadcast(new Intent("IWillStartAuto"));
}
}
RestartServiceReceiver.java RestartServiceReceiver.java
public class RestartServiceReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context.getApplicationContext(), StickyService.class));
}
}
Declare the components in manifest file: 声明清单文件中的组件 :
<service android:name=".StickyService" >
</service>
<receiver android:name=".RestartServiceReceiver" >
<intent-filter>
<action android:name="IWillStartAuto" >
</action>
</intent-filter>
</receiver>
Hope this will help you. 希望这会帮助你。
Your code in onTaskRemoved
is preventing the system to run the killProcess
commands. onTaskRemoved
代码阻止系统运行killProcess
命令。 The delay on Kitkat
is caused by using alarmService.set
, which is inexact from API 19. Use setExact instead. 该延迟
Kitkat
通过使用引起alarmService.set
,这是不精确的从API 19. setExact代替。
If you have a service
that you want to keep alive, it is recommended that you attach a notification
to it and make it foreground
. 如果您有一个要保持活动的
service
,建议您向其附加notification
并使其成为foreground
。 That way the likeliness of it being killed would be lowered. 这样,被杀的可能性就会降低。
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.support.v7.app.NotificationCompat;
import java.io.File;
import java.io.IOException;
import activity.MainActivity;
import activity.R;
import fragment.MainFragment;
public class MyService extends Service {
public static final int NOTIFICATION_CODE = 1;
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(NOTIFICATION_CODE, getNotification());
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
stopForeground(true);
super.onDestroy();
}
@Override
public boolean stopService(Intent name) {
return super.stopService(name);
}
/**
* Create and return a simple notification.
*/
private Notification getNotification() {
Notification notification;
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setColor(getResources()
.getColor(R.color.material_deep_teal_500))
.setAutoCancel(true);
notification = builder.build();
notification.flags = Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_AUTO_CANCEL;
return notification;
}
}
You can modify this code to accomodate your needs but this is the basic structure to start foreground service. 您可以修改此代码以满足您的需求,但这是启动前台服务的基本结构。 Which restarts if gets killed.
如果被杀,会重新启动。
how you check issocketalive that socket is connected or not ? 你如何检查套接字是否连接的issocketalive? if sockettimeoutexception is generated then try to on set getinputstream and getoutputstream.
如果生成了sockettimeoutexception,则尝试设置getinputstream和getoutputstream。 other issue that may be socket not closed properly.
其他问题可能是套接字未正确关闭。 So if possible then put your socket code here
所以,如果可能的话,请将套接字代码放在这
this worked for me 这对我有用
Add this attribute in android:allowBackup="false" in manifest file in application tag. 在应用程序标记的清单文件中的android:allowBackup =“false”中添加此属性。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="false"
tools:replace="android:allowBackup">
</application>
</manifest>
The idea of having a service ALWAYS running in background in Android is just wrong 99% of the times. 在Android中让服务始终在后台运行的想法在99%的时候都是错误的。
The system need to "shut down" CPU, and switch to a low battery usage profile. 系统需要“关闭” CPU,并切换到低电池使用情况。
You are saying you have a location based service. 您说您有基于位置的服务。 I assume you are using Google Play Services
FusedLocationProvider
, if not you should . 我假设您正在使用Google Play服务
FusedLocationProvider
,如果不是, 您应该使用 。
The FusedLocationProvider
allow you to register for location changes using a PendingIntent
. FusedLocationProvider
允许您使用PendingIntent
注册位置更改。 Meaning your services doesn't need to run all the time, it just need to register for location changes and then react when a new location come and do its stuff. 这意味着您的服务不需要一直运行,只需要注册位置更改,然后在新位置进行时做出反应并执行其操作。
See the FusedLocationProviderApi
official documentation . 请参阅
FusedLocationProviderApi
官方文档 。
To start listening for location updates 开始侦听位置更新
GoogleClient
using the LocationServices.API
API LocationServices.API
API连接到GoogleClient
LocationRequest
according to your needs (see the doc ) LocationRequest
(请参阅文档 ) requestLocationUpdates()
using the PendingIntent
version PendingIntent
版本调用requestLocationUpdates()
To stop listening 停止听
GoogleClient
using the LocationServices.API
API LocationServices.API
API连接到GoogleClient
removeLocationUpdates()
using the same PendingIntent
PendingIntent
调用removeLocationUpdates()
Your PendingIntent can launch another service to handle the new location. 您的PendingIntent可以启动另一个服务来处理新位置。
For example doing this from a service: 例如,从服务中执行此操作:
public void startMonitoringLocation(Context context) {
GoogleApiClient client = new GoogleApiClient.Builder(context)
.addApi(LocationServices.API)
.build()
ConnectionResult connectionResult = mApiClient.blockingConnect();
if (connectionResult.isSuccess()) {
LocationServices.FusedLocationApi
.requestLocationUpdates(client, buildLocationRequest(), buildPendingIntent(context));
} else {
handleConnectionFailed(context);
}
}
Then the service can immediately stop. 然后服务可以立即停止。
The first time this code run it WILL fail. 第一次运行此代码将失败。 The connection to the google client usually require the user to take some actions.
与谷歌客户端的连接通常要求用户采取一些行动。 The
ConnectionResult.hasResolution()
method will return true if this is the case. 如果是这种情况,
ConnectionResult.hasResolution()
方法将返回true。 Otherwise the reason is something else and you can't recover from it. 否则原因是别的,你无法从中恢复。 Meaning the only thing you can do is inform the user the feature will not work or have a nice fallback.
这意味着您唯一能做的就是通知用户该功能不起作用或有一个很好的后备。
The ConnectionResult.getResolution()
give you a PendingIntent
you need to use an Activity
and startIntentSenderForResult()
method on the Activity
to resolve this intent. 该
ConnectionResult.getResolution()
给你PendingIntent
,你需要使用一个Activity
和startIntentSenderForResult()
方法的Activity
,以解决这一意图。 So you would create a Notification
starting your Activity
to resolve that, and in the end call your Service
again. 因此,您将创建一个
Notification
启动您的Activity
以解决该问题,并最终再次调用您的Service
。
I usually just start an Activity
dedicated to do all the work. 我通常只是开始一项致力于完成所有工作的
Activity
。 It's lot easier but you don't want to call connectBlocking()
in it. 它更容易,但你不想在其中调用
connectBlocking()
。 Check out this on how to do it. 看看这个怎么做。
You may ask why not requesting location updates directly in the Activity
. 您可能会问为什么不直接在
Activity
请求位置更新。 That's actually perfectly fine, unless you need the location monitor to automatically start with the device, even if the user didn't explicitly opened the App. 这实际上非常好,除非你需要位置监视器自动启动设备,即使用户没有明确打开应用程序。
<receiver android:name=".BootCompletedBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
This way you can just run your service to connect and request location updates when the device is rebooted. 这样,您可以在重新启动设备时运行服务以连接并请求位置更新。
Example on how you can build your location request: 有关如何构建位置请求的示例:
public LocationRequest buildLocationRequest() {
LocationRequest locRequest = LocationRequest.create();
// Use high accuracy
locRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// how often do you need to check for the location
// (this is an indication, it's not exact)
locRequest.setInterval(REQUIRED_INTERVAL_SEC * 1000);
// if others services requires the location more often
// you can still receive those updates, if you do not want
// too many consider setting this lower limit
locRequest.setFastestInterval(FASTEST_INTERVAL_SEC * 1000);
// do you care if the user moved 1 meter? or if he move 50? 1000?
// this is, again, an indication
locRequest.setSmallestDisplacement(SMALLEST_DISPLACEMENT_METERS);
return locRequest;
}
And your pending intent: 你未决的意图:
public PendingIntent buildPendingIntent(Context context) {
Intent intent = new Intent(context, LocationUpdateHandlerService.class);
intent.setAction(ACTION_LOCATION_UPDATE);
intent.setPackage(context.getPackageName());
return PendingIntent.getService(context, REQUEST_CODE, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
Your LocationUpdateHandlerService
can be an IntentService
if you need to do work in background: 如果您需要在后台工作,您的
LocationUpdateHandlerService
可以是IntentService
:
@Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(FusedLocationProviderApi.KEY_LOCATION_CHANGED)) {
Location location = extras.getParcelable(FusedLocationProviderApi.KEY_LOCATION_CHANGED);
handleLocationChanged(location);
} else {
Log.w(TAG, "Didn't receive any location update in the receiver");
}
}
}
But can also be a Broadcast or anything that suits you. 但也可以是广播或任何适合你的东西。
Finally I achieved with help of Evernote JobService 最后,我在Evernote JobService的帮助下完成了
Github link - https://github.com/evernote/android-job Github链接 - https://github.com/evernote/android-job
Step 1: Add evernote jobservice dependency 第1步:添加evernote jobservice依赖项
implementation 'com.evernote:android-job:1.3.0-alpha03'
Step 2: Create DemoJobCreator.java class 第2步:创建DemoJobCreator.java类
public class DemoJobCreator implements JobCreator {
@Override
@Nullable
public Job create(@NonNull String tag) {
switch (tag) {
case DemoSyncJob.TAG:
return new DemoSyncJob();
default:
return null;
}
}
}
Step 3: Create DemoSyncJob.java class 第3步:创建DemoSyncJob.java类
public class DemoSyncJob extends Job {
public static final String TAG = ">>>> job_demo_tag";
@Override
@NonNull
protected Result onRunJob(Params params) {
// run your job here
Log.d(TAG, "onRunJob: ");
if(!isMyServiceRunning(this.getContext(), TestService.class)){
Intent intent=new Intent(context,TestService.class);
context.startService(intent);
}
scheduleJob();
return Job.Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(DemoSyncJob.TAG)
.setExecutionWindow(2_000L, 2_000L)
//.setPeriodic(900000) -> recommended. but it will work after 15 min (if you used this no need scheduleJob(); inside onRunJob();)
.build()
.schedule();
}
public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
try {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
}catch (Exception e){
Log.e(TAG, "isMyServiceRunning: ",e );
}
return false;
}
}
Step 4: In your Application file (If not available create it) add following line in onCreate() 第4步:在您的应用程序文件中(如果不可用,创建它)在onCreate()中添加以下行
JobManager.create(this).addJobCreator(new DemoJobCreator());
Step 5: Finally start JobService in your Activity 第5步:最后在您的Activity中启动JobService
DemoSyncJob.scheduleJob();
This JobService will check service running or not (every 2 second) If service not running it will restart the service. 此JobService将检查服务是否运行(每2秒)如果服务未运行,它将重新启动该服务。
Disclaimer : This may be not right solution. 免责声明:这可能不是正确的解决方案。 But it will 100% working.
但它将100%工作。
I hope it helps atleast anyone in future. 我希望将来至少可以帮助任何人。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.