Android服务没有在棒棒糖中重新启动

时间:2016-03-02 12:45:25

标签: android android-service

在我的应用程序中,我在后台使用基于位置的服务。所以当它被破坏时我需要重启我的服务。

但是我在logcat中收到了这条消息

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

我的服务onDestroy

@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&堆栈溢出。 所有这些都指的是 Service.START_STICKY 。但我已经用过了。

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

感谢任何帮助。

7 个答案:

答案 0 :(得分:7)

您可以使用BroadcasteReceiver重新启动它,该onDestroy()处理从您服务的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")); } } 发送的广播。

如何做到这一点:

<强> StickyService.java

public class RestartServiceReceiver extends BroadcastReceiver
{

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

    }

}

<强> RestartServiceReceiver.java

    <service android:name=".StickyService" >
    </service>

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

声明清单文件中的组件:

class A:
   id = ....
   type = 'dynamic' or None 

class B:
   id =...
   rels = relationship(A)

希望这会对你有所帮助。

答案 1 :(得分:4)

onTaskRemoved中的代码阻止系统运行killProcess命令。 Kitkat的延迟是由使用来自API 19 inexactalarmService.set引起的。请改用setExact

如果您希望保留service,建议您将notification附加到foreground并使其{{1}}。这样,被杀的可能性就会降低。

答案 2 :(得分:3)

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


}

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

答案 3 :(得分:2)

如何检查套接字是否连接的issocketalive? 如果生成了sockettimeoutexception,则尝试设置getinputstream和getoutputstream。 其他问题可能是套接字未正确关闭。 所以,如果可能,那么将套接字代码放在这里

答案 4 :(得分:2)

这对我有用

在android中添加此属性:allowBackup =&#34; false&#34;在应用程序标记的清单文件中。

public void methodName(Object value){
        if(value instanceof Integer){

        }else if(value instanceof String){

        }

}

答案 5 :(得分:2)

在Android中让服务一直在后台运行的想法在99%的时候都是错误的。

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

您说您有基于位置的服务。我假设您使用的是Google Play服务FusedLocationProvider,如果不是您应该

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

请参阅FusedLocationProviderApi official documentation

开始侦听位置更新

  1. 使用GoogleClient API
  2. 连接到LocationServices.API
  3. 根据您的需求构建LocationRequest(请参阅the doc
  4. 使用requestLocationUpdates()版本
  5. 致电PendingIntent

    停止聆听

    1. 使用GoogleClient API
    2. 连接到LocationServices.API
    3. 使用相同的removeLocationUpdates()
    4. 致电PendingIntent

      您的PendingIntent可以启动另一项服务来处理新位置。

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

      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()为您提供PendingIntent,您需要在Activity上使用startIntentSenderForResult()Activity方法来解决此问题。因此,您需要创建一个Notification来启动Activity来解决此问题,最后再次致电Service

      我通常只是开始Activity致力于完成所有工作。它更容易,但您不想在其中调用connectBlocking()。查看this了解如何操作。

      您可能会问为什么不直接在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");
              }
      
          }
      }
      

      但也可以是广播或任何适合你的东西。

答案 6 :(得分:0)

最后,我在 Evernote JobService

的帮助下实现了目标

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

步骤1:添加Evernote Jobservice依赖项

>>> d2 = dict((k, int(v)) for k,v in list2)
>>> d2
{'a': 1, 'c': 3, 'd': 4, 'b': 2}

第2步:创建DemoJobCreator.java类

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

第3步:创建DemoSyncJob.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;
    }
}
}

步骤4:在您的应用程序文件中(如果无法创建,请在onCreate()中添加以下行)

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

第5步:最后在“活动”中启动JobService

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

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

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

我希望它将来能帮助任何人。