Android 服务无法在棒棒糖中重新启动



在我的应用程序中,我在后台使用基于位置的服务。因此,当服务被销毁时,我需要重新启动服务。

但是我在日志猫中收到了这条消息

ProcessRecord{320afaf6 20614:com.odoo.crm:my_odoo_gps_service/u0a391}的虚假死亡,curProc for 20614:null

我的服务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);
 }

我的服务销毁

@Override
public void onDestroy() {
    System.out.println("destroy service");
    super.onDestroy();
    wakeLock.release();
}

我的服务 onStartCommand

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
        return Service.START_STICKY;
}

我不知道错误是什么。我在google和stackoverflow中搜索了两者。所有这些都是指Service.START_STICKY。但我已经用过了。

相同的服务重启在 KitKat 中有效,但有一些延迟(~5 分钟)。

任何帮助,不胜感激。

可以使用处理

从服务onDestroy()发送的广播的BroadcasteReceiver重新启动它。

如何执行此操作:

粘性服务.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"));
    }
}

重新启动服务接收器.java

public class RestartServiceReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent) {
    context.startService(new Intent(context.getApplicationContext(), StickyService.class));
    }
}

在清单文件中声明组件:

    <service android:name=".StickyService" >
    </service>
    <receiver android:name=".RestartServiceReceiver" >
        <intent-filter>
            <action android:name="IWillStartAuto" >
            </action>
        </intent-filter>
    </receiver>

希望这对您有所帮助。

onTaskRemoved中的代码阻止系统运行killProcess命令。Kitkat延迟是由使用 alarmService.set 引起的,这与 API 19 不精确。请改用 setExact 。

如果您有想要保持活动状态的service,建议您在其上附加一个notification并使其foreground。这样它被杀死的可能性就会降低。

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;
    }

}

您可以修改此代码以满足您的需求,但这是启动前台服务的基本结构。如果被杀,它会重新启动。

你如何检查插座是否连接?如果生成了套接字超时异常,则尝试设置 getinputstream 和 getoutputstream。可能是套接字未正确关闭的其他问题。所以如果可能的话,把你的套接字代码放在这里

这对

我有用

在应用程序标记的清单文件中的 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>

在Android中始终在后台运行服务的想法在99%的情况下都是错误的。

系统需要"关闭"CPU,并切换到低电池使用率配置文件。

说您有基于位置的服务。我假设你正在使用谷歌播放服务FusedLocationProvider,如果不是你应该

FusedLocationProvider允许您使用 PendingIntent 注册位置更改。这意味着您的服务不需要一直运行,它只需要注册位置更改,然后在新位置到来时做出反应并完成其工作。

请参阅FusedLocationProviderApi官方文档。

开始侦听位置更新

  1. 使用LocationServices.API API 连接到GoogleClient
  2. 根据您的需求构建LocationRequest(请参阅文档)
  3. 使用 PendingIntent 版本呼叫requestLocationUpdates()

停止收听

  1. 使用LocationServices.API API 连接到GoogleClient
  2. 使用相同的PendingIntent呼叫removeLocationUpdates()

您的待定意图可以启动另一个服务来处理新位置。

例如,从服务执行此操作:

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);
    }
}

然后,服务可以立即停止。

第一次运行此代码时,它将失败。与谷歌客户端的连接通常需要用户执行一些操作。如果是这种情况,ConnectionResult.hasResolution()方法将返回 true。否则,原因是其他原因,您无法从中恢复。这意味着您唯一能做的就是通知用户该功能将不起作用或有一个很好的回退。

ConnectionResult.getResolution()为您提供了在Activity上使用ActivitystartIntentSenderForResult()方法来解决此意图所需的PendingIntent。因此,您将创建一个Notification开始Activity来解决此问题,最后再次致电您的Service

我通常只是创办一个专门从事所有工作的Activity。这要容易得多,但您不想在其中调用connectBlocking()。看看这个如何做到这一点。

您可能会问为什么不直接在Activity中请求位置更新。这实际上完全没问题,除非您需要位置监视器自动启动设备,即使用户没有明确打开应用程序。

<receiver android:name=".BootCompletedBroadcastReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

这样,您只需运行服务即可在设备重新启动时进行连接并请求位置更新。

有关如何构建位置请求的示例:

    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;
    }

以及您的待定意图:

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);
}

如果您需要在后台工作,您的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");
        }
    }
}

但也可以是广播或任何适合您的内容。

最后,我在Evernote JobService的帮助下实现了

Github链接 - https://github.com/evernote/android-job

步骤 1:添加印象笔记作业服务依赖项

implementation 'com.evernote:android-job:1.3.0-alpha03'

第 2 步:创建演示作业创建者.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;
    }
}
}

第 3 步:创建演示同步作业.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;
  }
  }

第 4 步:在您的应用程序文件中(如果不可用,请创建它)在 onCreate() 中添加以下行

 JobManager.create(this).addJobCreator(new DemoJobCreator());

第 5 步:终于在您的活动中启动工作服务

DemoSyncJob.scheduleJob();

此作业服务将检查服务是否正在运行(每 2 秒)如果服务未运行,它将重新启动服务。

免责声明:这可能不是正确的解决方案。但它将 100% 工作。

我希望它至少在未来对任何人有所帮助。

最新更新