当用户从最近的任务屏幕中滑动我的应用时,我的应用关闭,预定的工作根本无法运行。我在"显示缓存的流程"中找不到它。屏幕。但有些应用程序可以幸存下来。我关闭它们并将它们擦掉但是它们仍然有一个缓存进程并且它们的预定作业正常运行。如果我停止它们,它们会重新启动。这些应用程序在执行缓存过程时有何不同之处?
我尝试使用START_STICKY创建服务,但它没有用。
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("My Service", "started");
return Service.START_STICKY;
}
我甚至尝试检测服务已关闭并使用AlarmManager重新启动服务。但似乎闹钟管理器在许多设备上都没有工作。
@Override
public void onTaskRemoved(Intent rootIntent) {
Log.e("My Service", "taskremoved");
PendingIntent service = PendingIntent.getService(
getApplicationContext(),
1001,
new Intent(getApplicationContext(), Test.class),
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1000, service);
}
如果我关闭电池优化,它可以工作,但其他其他应用程序会在启用优化时执行此操作。
答案 0 :(得分:0)
这完全取决于您如何生成通知。如果您的通知是针对某些操作,请使用广播接收器监听这些操作并在发生该操作时发布通知,另一方面,如果需要某些代码持续运行,则必须使服务像聊天应用程序一样运行不断收听新消息
答案 1 :(得分:0)
据我所知,您可以控制您的应用程序直到onStop()活动回调,以及旧版Android(on api 11)中的onPause()。之后,Android可能会随时终止您的应用。
因此,要回到应用程序关闭时的状态,您必须将状态保存在onPause()或onStop()-Api 11或更新 - 并在onResume()或onStart()中恢复它取决于你支持的api。
如果该过程已被擦除内存或放入缓存一段时间,我不认为它是您作为开发人员控制的。 另见其他问题:On Android, what's the difference between running processes and cached background processes?
编辑我
再次阅读你的问题之后,我认为如果你的服务被杀死,那么它更多地是关于你的服务被杀死而不是缓存的进程。
如果是这种情况,我将Service
放在一起Activity
,它由AlarmManager
启动并停止,并由<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.here">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".ServiceExample">
</service>
</application>
</manifest>
提供支持。
活动可以开始停止服务。启动服务后,您可以退出活动并查看服务是否正在运行。 (仅供参考,至少在我的Oreo模拟器中,我可以在缓存的进程中看到该服务。)
当活动开始时,它会检查服务是否正在运行&#34;从某种意义上说,你还没有阻止它。并使用该信息设置按钮的状态。
服务告诉活动(如果有)关于其运行状态的变化。 关于调度,服务重新安排每次执行。
在代码中,Android(Oreo和Marshmellow)版本之间存在区别,因为它们处理后台进程的方式。由于Oreo能够在没有时间限制的情况下运行,服务必须在前台运行,向用户显示消息并让他知道发生了什么。
清单(更改包名称)
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
//Some intent actions to receive from the service.
public static final String STOPPED = "stopped";
public static final String STARTING = "starting";
public static final String RUNNING = "running";
public static final String WAITING = "waiting";
public static final String STOPPING = "stopping";
TextView tvDisplay;
Button btnStart, btnStop;
String serviceStatus = STOPPED;
BroadcastReceiver receiver;
IntentFilter intentFilter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter = new IntentFilter();
intentFilter.addAction(STOPPED);
intentFilter.addAction(STARTING);
intentFilter.addAction(RUNNING);
intentFilter.addAction(WAITING);
intentFilter.addAction(STOPPING);
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
action = action == null ? "" : action;
if(!action.equals("")) {
serviceStatus = action;
updateUi();
}
}
};
tvDisplay = findViewById(R.id.tvDisplay);
btnStart = findViewById(R.id.btnStart);
btnStop = findViewById(R.id.btnStop);
btnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this.getApplicationContext(), ServiceExample.class);
intent.putExtra("stop",false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
btnStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this.getApplicationContext(), ServiceExample.class);
intent.putExtra("stop",true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
} else {
startService(intent);
}
}
});
}
@Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getApplicationContext())
.unregisterReceiver(receiver);
}
@Override
protected void onResume() {
super.onResume();
LocalBroadcastManager.getInstance(getApplicationContext())
.registerReceiver(receiver,intentFilter);
if(isMyServiceRunning(ServiceExample.class)){
serviceStatus = WAITING;
}else{
serviceStatus = STOPPED;
}
updateUi();
}
private void updateUi(){
if(serviceStatus.equals(STOPPED)){
btnStart.setEnabled(true);
btnStop.setEnabled(false);
}else if(serviceStatus.equals(STOPPING)){
btnStart.setEnabled(false);
btnStop.setEnabled(false);
}else if(serviceStatus.equals(STARTING)){
btnStart.setEnabled(false);
btnStop.setEnabled(false);
}else if(serviceStatus.equals(RUNNING)){
btnStart.setEnabled(false);
btnStop.setEnabled(true);
}else if(serviceStatus.equals(WAITING)){
btnStart.setEnabled(false);
btnStop.setEnabled(true);
}
tvDisplay.setText(serviceStatus);
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
//This part checks for a running service
//https://stackoverflow.com/questions/600207/how-to-check-if-a-service-is-running-on-android
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
//This part checks if there is a pending intent (scheduled in the alarm manager)
Intent intent = new Intent(getApplicationContext(), ServiceExample.class);
PendingIntent testIntent;
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
testIntent = PendingIntent.getForegroundService(getApplicationContext(),12345,intent,PendingIntent.FLAG_NO_CREATE);
}else{
testIntent = PendingIntent.getService(getApplicationContext(),12345,intent,PendingIntent.FLAG_NO_CREATE);
}
return (testIntent != null);
}
}
活动。
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
public class ServiceExample extends Service {
private boolean stop = false;
private String CHANNEL_ID = "ServiceExample";
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
@Override
public void onCreate() {
Toast.makeText(this, "creating service", Toast.LENGTH_SHORT).show();
stop = false;
alarmMgr = (AlarmManager)this.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getApplicationContext(), ServiceExample.class);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
alarmIntent = PendingIntent.getForegroundService(getApplicationContext(),12345,intent,0);
}else{
alarmIntent = PendingIntent.getService(getApplicationContext(),12345,intent,0);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(getString(R.string.app_name))
.setContentText("ServiceExample is running")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(1, notification);
boolean stopExtra = intent.getBooleanExtra("stop", false);
if(stopExtra) {
if (!stop) {
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(new Intent(MainActivity.STOPPING));
stop = true;
alarmMgr.cancel(alarmIntent);
alarmIntent.cancel();
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(new Intent(MainActivity.STOPPED));
}
}else{
if(stop){
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(new Intent(MainActivity.STARTING));
stop = false;
}
}
if(!stop){
Thread thread = new Thread(new SomeJobClass());
thread.start();
long now = System.currentTimeMillis();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (alarmMgr != null) {
alarmMgr.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, now + 30000, alarmIntent);
}
}else{
if (alarmMgr != null) {
alarmMgr.setExact(AlarmManager.RTC_WAKEUP, now + 30000, alarmIntent);
}
}
}else{
stopSelf();
}
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
private final class SomeJobClass implements Runnable{
@Override
public void run() {
broadcastToActivity(MainActivity.RUNNING);
try {
//Simulate the time it takes to run the job
Thread.sleep(10000);
} catch (InterruptedException e) {
// Restore interrupt status.
Thread.currentThread().interrupt();
}
broadcastToActivity(MainActivity.WAITING);
stopSelf();
}
}
private void broadcastToActivity(String intentAction){
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(new Intent(intentAction));
}
}
服务
Explode