Android: 是否有任何 Android 服务可以在应用程序关闭时执行并且也像绑定服务一样(持续交互)

Android: Is there any Android service that can execute when the app is closed and also acts like a bound service(constant interaction)

我想要一个位置更新服务,我需要从 MainActivity 查询它。我需要一项服务,因为当应用程序关闭时,我需要它在后台 运行,以便将位置发送到服务器并基于该位置发送通知。我还读到绑定服务像服务器一样工作,activity 像客户端一样,不需要启动服务,这对于该服务必须完成的任务来说是理想的。哪种类型的服务可以满足我的需求?非常感谢

START_STICKY 告诉 OS 在它有足够的内存后重新创建服务,并以空意图再次调用 onStartCommand()。 START_NOT_STICKY 告诉 OS 不要再费心重新创建服务。

您可以使用服务在应用程序关闭时触发或从任务中终止:

public class App_killed extends Service {

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("ClearFromRecentService", "Service Started");
    return START_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("ClearFromRecentService", "Service Destroyed");
}

public void onTaskRemoved(Intent rootIntent) {
    Log.e("ClearFromRecentService", "END");
    //here you can call a background network request to post you location to server when app is killed
    Toast.makeText(getApplicationContext(), "Warning: App killed", Toast.LENGTH_LONG).show();
    stopSelf(); //call this method to stop the service
}
}

在清单上删除您的服务

 <service
        android:name="com.empiregroup.amarridebiker.App_killed"
        android:stopWithTask="false" />

即使应用程序关闭,此服务也会继续执行...您也可以使用 Binder class 在任何 activity 中获取服务 class 的实例。

完整源代码:适用于我的情况

public class GPSTracker extends Service {

private static Context mContext;
// flag for GPS status
boolean isGPSEnabled = false;
// flag for network status
boolean isNetworkEnabled = false;
// flag for GPS status
boolean canGetLocation = false;
protected LocationManager locationManager;
static String latitude_s, longitude_s;
Thread triggerService;
private final IBinder mBinder = new MyBinder();

public GPSTracker() {
    super();
}


public GPSTracker(Context context) {
    mContext = context;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    //Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
    Log.i(LOG, "Service started");
    if (intent != null) {
        addLocationListener();
     }
    return START_STICKY;
}

private void addLocationListener() {
    triggerService = new Thread(new Runnable() {
        public void run() {
            try {
                Looper.prepare();//Initialise the current thread as a looper.
                locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);

                //Criteria c = new Criteria();
                //c.setAccuracy(Criteria.ACCURACY_COARSE);

                //final String PROVIDER = locationManager.getBestProvider(c, true);

                MyLocationListener myLocationListener = new MyLocationListener();
                if (checkLocationPermission()) {
                    locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 0, myLocationListener);
                }
                Log.d("LOC_SERVICE", "Service RUNNING!");
                Looper.loop();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }, "LocationThread");
    triggerService.start();
}

public static void updateLocation(Location location) {
    Context appCtx = Global_variable.getAppContext();

    double latitude, longitude;

    latitude = location.getLatitude();
    longitude = location.getLongitude();
    try {
        latitude_s = Double.toString(latitude);
        longitude_s = Double.toString(longitude);
    } catch (Exception e) {

    }
    Intent filterRes = new Intent();
    filterRes.setAction("mypackage.action.LOCATION");
    filterRes.putExtra("latitude", latitude);
    filterRes.putExtra("longitude", longitude);
    filterRes.putExtra("id", id);
    appCtx.sendBroadcast(filterRes);
}


class MyLocationListener implements LocationListener {

    @Override
    public void onLocationChanged(Location location) {
        updateLocation(location);
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
}


public boolean checkLocationPermission() {
    String permission = "android.permission.ACCESS_FINE_LOCATION";
    int res = mContext.checkCallingOrSelfPermission(permission);
    return (res == PackageManager.PERMISSION_GRANTED);
}


@Override
public void onCreate() {
    super.onCreate();
    Log.d(LOG, "Service created");
}


@Override
public void onDestroy() {
    super.onDestroy();
    Log.d(LOG, "Service destroyed");
}


/**
 * Function to check GPS/wifi enabled
 *
 * @return boolean
 */
public boolean canGetLocation() {
    locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
    // getting GPS status
    isGPSEnabled = locationManager
            .isProviderEnabled(LocationManager.GPS_PROVIDER);

    // getting network status
    isNetworkEnabled = locationManager
            .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

    if (!isGPSEnabled && !isNetworkEnabled) {
        // location service disabled
        canGetLocation = false;
    } else {
        canGetLocation = true;
    }
    return canGetLocation;
}

/**
 * Function to show settings alert dialog
 * On pressing Settings button will lauch Settings Options
 */
public void showSettingsAlert() {
    AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);
    // Setting Dialog Title
    alertDialog.setTitle("GPS is settings");
    // Setting Dialog Message
    alertDialog.setMessage("GPS is not enabled. Do you want to go to settings menu?");
    // On pressing Settings button
    alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
            mContext.startActivity(intent);
        }
    });

    // on pressing cancel button
    alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int which) {
            dialog.cancel();
        }
    });

    // Showing Alert Message
    alertDialog.show();
}

@Override
public IBinder onBind(Intent arg0) {
    return mBinder;
}

public class MyBinder extends Binder {
    GPSTracker getService() {
        return GPSTracker.this;
    }
}

public String getLatitude_s() {
    return latitude_s;
}

public String getLongitude_s() {
    return longitude_s;
}

}

广播接收器 class 用于从服务获取位置并将其发送到服务器。

public class LocationReceiver extends BroadcastReceiver {

double latitude, longitude;

@Override
public void onReceive(final Context context, final Intent calledIntent)
{
    Log.d("LOC_RECEIVER", "Location RECEIVED!");

    latitude = calledIntent.getDoubleExtra("latitude", -1);
    longitude = calledIntent.getDoubleExtra("longitude", -1);

    updateRemote(latitude, longitude,biker_id);

}

private void updateRemote(final double latitude, final double longitude ,final String id)
{
    //HERE YOU CAN PUT YOUR ASYNCTASK TO UPDATE THE LOCATION ON YOUR SERVER
    String latitude_s=Double.toString(latitude);
    String longitude_s=Double.toString(longitude);
    new SendToServer().execute(longitude_s, latitude_s,id);
}

在清单文件中添加服务和接收器

    <service
        android:name="com.yourpackage.GPSTracker"
        android:enabled="true"
        android:label="GPS Data"></service>

    <service
        android:name="com.yourpackage.App_killed"
        android:stopWithTask="false" />

    <receiver
        android:name="com.yourpackage.LocationReceiver"
        android:enabled="true">
        <intent-filter>
            <action android:name="mypackage.action.LOCATION" />
        </intent-filter>
    </receiver>

在 activity:

中启动服务
  GPSTracker gps;
  gps = new GPSTracker(this);
        // check if GPS enabled
        if (gps.canGetLocation()) {
            startService(new Intent(getApplicationContext(), GPSTracker.class));
            } else {
            gps.showSettingsAlert();
        }