繁体   English   中英

为什么前台服务从后台删除应用程序后无法正常工作?

[英]Why foreground Service not working after removing app from the background?

即使应用程序在后台显示通知,我也一直在尝试实施前台服务,以便每隔3秒获取一次位置。 但是当我从后台删除我的应用时,通知也会删除。 但是,这只发生在MI REDMI NOTE 5(API版本28)和MI REDMI NOTE 4(API版本24)中,但是当我在Samsung J5(API版本23)中运行相同的应用程序时,通知是甚至在应用程序从后台删除,直到从活动中手动停止为止。 变化的结果行为是由于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,以便在应用程序处于后台时启动服务,并在应用程序处于前台时停止服务。 并在主要活动或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 fun registerLifecycleHandler(lifeCycleHandler:AppLifecycleHandler){registerActivityLifecycleCallbacks(lifeCycleHandler)registerComponentCallbacks(lifeCycleHandler)}

override fun getLifecycle(): Lifecycle {
    return mLifecycleRegistry
}

在您的应用程序类中实现LifeCycleDelegate并覆盖这些方法

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

}

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

val lifeCycleHandler = AppLifecycleHandler(this)
    registerLifecycleHandler(lifeCycleHandler)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM