簡體   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