java - 为什么从后台删除应用程序后前台服务不工作?

标签 java android

我一直在尝试实现前台服务,以便在每 3 秒后获取位置,即使应用程序在后台显示通知也是如此。但是,当我从后台删除我的应用程序时,通知也会删除。但是,只有当我在 MI REDMI NOTE 5(API 版本 28)和 MI REDMI NOTE 4(API 版本 24)中执行此操作时才会发生这种情况,但是当我在 Samsung J5(API 版本 23)中运行相同的应用程序时,通知是即使应用程序从后台删除,直到手动从 Activity 中停止时也会显示。不同的结果行为是由于 API 的变化还是由于不同的手机型号?

这是我的服务等级

package com.example.locationrunandall;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;

import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;

public class ForeService extends Service {


    private static final String PACKAGE_NAME =
            "com.example.customizedforeground";

    static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
    static final String EXTRA_LOCATION = PACKAGE_NAME + ".location";
    private static final String EXTRA_STARTED_FROM_NOTIFICATION = PACKAGE_NAME +
            ".started_from_notification";
    private Handler mServiceHandler;
    private NotificationManager mNotificationManager;
   // private Notification notification;
    private LocationRequest mLocationRequest;
    private FusedLocationProviderClient mFusedLocationClient;
    private LocationCallback mLocationCallback;
    private Location mLocation;
    private static final String CHANNEL_ID = "CHANNEL_ONE";
    private static final int NOTIFICATION_ID = 4567123;
    private static final String TAG = "123";
    String loc;

    public ForeService(){}

    @Override
    public void onCreate() {
      mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
      mLocationCallback = new LocationCallback(){
    @Override
    public void onLocationResult(LocationResult locationResult) {
        super.onLocationResult(locationResult);
      //Do Location Work You Want To Do
        onNewLocation(locationResult.getLastLocation());
    }
};
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(3*1000);
        mLocationRequest.setFastestInterval(1000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        getLastLocation();
        HandlerThread handlerThread = new HandlerThread("HANDLER");
        handlerThread.start();
        mServiceHandler = new Handler(handlerThread.getLooper());
        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        CharSequence name = "Name Charseq";
        if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){
            NotificationChannel notificationChannel = new
                    NotificationChannel(CHANNEL_ID,name, NotificationManager.IMPORTANCE_DEFAULT);

            mNotificationManager.createNotificationChannel(notificationChannel);
        }
        startForeground(NOTIFICATION_ID,getNotification());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
       // startForeground(NOTIFICATION_ID,getNotification());
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceHandler.removeCallbacksAndMessages(null);

        //stopForeground(true);
    }

    @androidx.annotation.Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }


    private void getLastLocation() {
        try {
            mFusedLocationClient.getLastLocation()
                    .addOnCompleteListener(new OnCompleteListener<Location>() {
                        @Override
                        public void onComplete(@NonNull Task<Location> task) {
                            if (task.isSuccessful() && task.getResult() != null) {
                                mLocation = task.getResult();
                            } else {
                                Log.d(TAG, "Failed to get location.");
                            }
                        }
                    });
        } catch (SecurityException unlikely) {
            Log.d(TAG, "Lost location permission." + unlikely);
        }
    }

    private void onNewLocation(Location location) {
        mLocation = location;
        if(mLocation==null)
        Log.d("DSK_OPER","Lat: = "+"Not known");
        else
            Log.d("DSK_OPER"," : "+location.getLatitude());
        //send intent to broadcast reciever
        Intent intent = new Intent(ACTION_BROADCAST);
        intent.putExtra(EXTRA_LOCATION, location);
        LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
        // todo - Write More code here
        mNotificationManager.notify(NOTIFICATION_ID,getNotification());
    }



    private Notification getNotification() {

        //Intent intent = new Intent(this,MainActivity.class);

        if(mLocation==null)
            loc = "unknown loc";
        else
            loc = String.valueOf(mLocation.getLatitude());

        NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
                .setContentTitle("Latitude and longitude")
                .setContentText(" = "+loc)
                .setOngoing(true)
                .setPriority(Notification.PRIORITY_HIGH)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setWhen(System.currentTimeMillis());

        // Set the Channel ID for Android O.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder.setChannelId(CHANNEL_ID);
        }
        return builder.build();
    }

}

最佳答案

我正在使用前台服务在一段时间后进行位置更新。如果您的应用程序在后台但未被终止,当您想要更新位置时,前台服务非常有用。但是,当您的应用程序被终止时,您有责任停止前台服务。因此,您只需实现 LifeCycleDelegate,以便您可以在应用程序处于后台时启动服务,并在应用程序处于前台时停止服务。当您的主要 Activity 或 HomeActivity 被终止时,也会终止该服务。 这是 AppLifecycleHandler 的代码。

internal class AppLifecycleHandler(private val lifeCycleDelegate: LifeCycleDelegate) : Application.ActivityLifecycleCallbacks,
    ComponentCallbacks2 {

private var appInForeground = false

override fun onActivityPaused(p0: Activity?) {}

/**
 * app resumed
 */
override fun onActivityResumed(p0: Activity?) {
    if (!appInForeground) {
        appInForeground = true
        lifeCycleDelegate.onAppForegrounded()
    }
}

override fun onActivityStarted(p0: Activity?) {
}

override fun onActivityDestroyed(p0: Activity?) {
}

override fun onActivitySaveInstanceState(p0: Activity?, p1: Bundle?) {
}

override fun onActivityStopped(p0: Activity?) {
}

override fun onActivityCreated(p0: Activity?, p1: Bundle?) {
}

override fun onLowMemory() {}

override fun onConfigurationChanged(p0: Configuration?) {}

/**
 * app sent to background
 */
override fun onTrimMemory(level: Int) {
    if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        appInForeground = false
        lifeCycleDelegate.onAppBackgrounded()
    }
}

将此方法添加到您的应用程序类中 私有(private)乐趣 registerLifecycleHandler(lifeCycleHandler: AppLifecycleHandler) { 注册ActivityLifecycleCallbacks(lifeCycleHandler) 注册组件回调(lifeCycleHandler) }

override fun getLifecycle(): Lifecycle {
    return mLifecycleRegistry
}

在您的应用程序类中实现 LifeCycleDelegate 并重写方法

internal interface LifeCycleDelegate {
fun onAppBackgrounded()
fun onAppForegrounded()

}

在应用程序类中创建应用程序对象

val lifeCycleHandler = AppLifecycleHandler(this)
    registerLifecycleHandler(lifeCycleHandler)

关于java - 为什么从后台删除应用程序后前台服务不工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56359360/

相关文章:

java - 为什么我的 Android 应用程序中的计算(Eclipse)出现错误?

java - Java中从类外部调用私有(private)方法

java - 将列表 <Integer> 处理到线程

android - android中的NoClassFoundError MultipartEntity错误

javascript - 如何将一个值发布到 WebService 中并解析另一个值?超文本标记语言

android - 单击部分文本并移动到其他 Activity

java - 使用@JsonProperty 序列化 map

java - 如果我用更高的 Java 版本编译 Java 代码会怎样?

首次更新后 Android LiveData Observer 未激活

java - 按升序/降序对 Firebase 数据进行排序