当应用程序从最近的应用程序中删除时,IntentService 停止工作

IntentService stops working when app is removed from recent apps

我在我的应用程序中使用地理围栏,并且我想根据地理围栏事件(进入或退出)执行一些操作。 Geofence documentation 说一旦你设置了 geofence 它将自动触发事件,你可以用 IntentService 捕获这个事件。为此,我做了如下 intentservice:

GeofenceTransitionsIntentService.java

public class GeofenceTransitionsIntentService extends IntentService {

    Handler mHandler;
    public GeofenceTransitionsIntentService() {
        super("GeofenceTransitionsIntentService");
        mHandler = new Handler();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("JK-->>","service started!");
    }

    @Override
    protected void onHandleIntent(Intent intent) {

        Log.e("JK-->>","onHandel--->>");

        GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
        if (geofencingEvent.hasError()) {
            Log.e("JK-->>","geofenceEvent has error!");
            return;
        }

        int geofenceTransitionType = geofencingEvent.getGeofenceTransition();
        if (geofenceTransitionType == Geofence.GEOFENCE_TRANSITION_ENTER) {
            Log.e("JK-->>","enter!");
            mHandler.post(new DisplayToast(this,"Enter"));
        } else if (geofenceTransitionType == Geofence.GEOFENCE_TRANSITION_EXIT) {
            mHandler.post(new DisplayToast(this,"Exit"));
            Log.e("JK-->>","exit");
        }
    }

    public class DisplayToast implements Runnable {
        private final Context mContext;
        String mText;

        public DisplayToast(Context mContext, String text){
            this.mContext = mContext;
            mText = text;
        }

        public void run(){
            Toast.makeText(mContext, mText, Toast.LENGTH_SHORT).show();
        }
    }

}

现在,问题是当应用程序打开时(无论是前景还是背景)并且我在地理围栏中进入或退出它工作正常并向我显示吐司消息并且 logcat 显示日志但是当我删除应用程序时最近的应用程序没有向我显示 toast 消息或 logcat.

中没有显示日志

我试图在 google 上找到解决方案,但大多数答案都建议使用该服务,但如果我没记错,IntentService 会在工作完成后自动停止,并在收到任何意图时自行启动。所以,我认为使用 IntentService 来完成这个任务效率更高。

更新 我正在使用以下代码行注册地理围栏。

geofencingClient.addGeofences(getGeofencingRequest(),getGeofencePendingIntent());

在 getGeofencePendingIntent() 中,我使用以下代码行开始意图服务。

private PendingIntent getGeofencePendingIntent() {
        if(geofencePendingIntent != null)
            return geofencePendingIntent;
        Intent in = new Intent(SetProfileOnlineActivity.this,GeofenceTransitionsIntentService.class);
        geofencePendingIntent = PendingIntent.getService(SetProfileOnlineActivity.this,111451,in,PendingIntent.FLAG_UPDATE_CURRENT);
        return geofencePendingIntent;
    }

此服务将 运行 始终 :


转到项目java -> 右键->新建->服务->服务 将其命名为守望者


watchman.java

public class watchman extends Service
{
NotificationManager mNotifyManager;
NotificationCompat.Builder mBuilder;
NotificationChannel notificationChannel;
String NOTIFICATION_CHANNEL_ID = "1";


public watchman() { }

@Override
public void onCreate()
{

    try
    {
        mNotifyManager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);

        mBuilder = new NotificationCompat.Builder(this, null);
        mBuilder.setContentTitle("Insta Promo")
                .setContentText("We are ready to help you.")
                .setSmallIcon(R.drawable.ic_launcher_background);



        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {
            notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "My Notifications", NotificationManager.IMPORTANCE_HIGH);

            // Configure the notification channel.
            notificationChannel.setDescription("Channel description");
            notificationChannel.enableLights(true);
            notificationChannel.setLightColor(Color.RED);
            notificationChannel.setVibrationPattern(new long[]{0, 1000, 500, 1000});
            notificationChannel.enableVibration(true);
            notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
            mNotifyManager.createNotificationChannel(notificationChannel);
        }
        else
        {
            mBuilder.setContentTitle("Insta Promo")
                    .setPriority(NotificationCompat.PRIORITY_HIGH)
                    .setColor(ContextCompat.getColor(this, R.color.colorAccent))
                    .setVibrate(new long[]{100, 250})
                    .setLights(Color.YELLOW, 500, 5000)
                    .setAutoCancel(true);
        }

        mBuilder.setChannelId(NOTIFICATION_CHANNEL_ID);

        mNotifyManager.notify(1, mBuilder.build());

        startForeground(1, mBuilder.build());

    }
    catch(Exception e)
    {
        Log.d(TAG, "EXCEPTION IN SHOWING NOTIFICATION xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx...\n");
        Log.e("MY_APP", "exception", e);

    }

}

@Override
public int onStartCommand(Intent intent, int flags, int startId)
{

    new Thread(new Runnable()
    {

        public void run()
        {

            while (true)
            {
                try
                {
                    Log.d(TAG, "Thread : Running again...\n");

                    Thread.sleep(10000);
                }
                catch (InterruptedException e)
                {
                    Log.d(TAG, "Thread : InterruptedException Error in service...\n");
                }

            }


        }

    }).start();
    return START_STICKY;

}

@Override
public void onDestroy()
{
    super.onDestroy();
}

@Override
public IBinder onBind(Intent intent)
{
    // TODO: Return the communication channel to the service.
    throw new UnsupportedOperationException("Not yet implemented");
}

}

它会在您将其创建为服务时自动注册到清单文件中,无需更新清单文件。


从主要 activity 或从任何您想开始的地方调用它

    Log.d(TAG, " Good to Go \n");
    Log.d(TAG, "Starting Service from main...\n");
    Intent intent = new Intent(MainActivity.this, watchman.class);
    startService(intent);
    Log.d(TAG, "Main has started the service...\n");

现在,即使您将它从最近的应用中删除...,它也会一直存在于您的记忆中 运行,要查看它,请关注 logcat。希望能帮助到你。它在从 4.1 到最新的 8.0 oreo

的项目中工作

为了显示通知,我正在使用振动权限,因此也为您提供清单文件。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rushi.oreo">


<uses-permission android:name="android.permission.VIBRATE"/>

<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=".watchman"
        android:enabled="true"
        android:exported="true" />


</application>

</manifest>

希望它真的对您或其他人有所帮助。

  1. IntentService 将在分配给它的工作完成后自动停止。
  2. 如果您希望 运行 的服务在后台停止的可能性很小,则它必须是前台服务。请确保在后台工作线程中启动您的服务,因为默认情况下服务 运行s 在主线程上。

这里有更多详细信息 - https://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)

但是请注意将服务设置为前台会严重影响您的phone电池寿命。并且将服务作为前台也让用户感到厌烦,因为它始终显示通知并且无法关闭。

您最好使用 JobScheduler 或 Firebase JobDispatcher 来安排后台工作。

我找到了答案...我的代码没有问题,IntentService 也工作得很好,但错误出现在测试中。我在 android Oreo 运行 设备上测试我的应用程序。

在 android oreo google 中更新了他们的政策,在前台他们将发送位置更新任意次数,但在 后台 他们将发送位置每小时仅更新 几次。 其背后的主要原因是为了延长设备的使用寿命。

有关 android oreo 位置更新的更多信息,您可以查看 this 文档。