76

I am in the process of creating an app that is similar to the built-in SMS app.

What I need:

  • a service that is always running in the background
  • every 5 min. the service checks the current location of the device and calls a web service
  • if certain criteria are met, the service should generate a notification (just like the SMS app)
  • when the notification is clicked, the user is taken to the app (just like the SMS app)
  • when the app is installed the service should be started
  • when the device is rebooted, the service should be started

What I have tried:
- running a regular service which worked just fine until Android kills the service
- using the AlarmManager to make the 5 min. interval call to a service. But I was not able to make this work.

4

5 回答 5

35

始终在后台运行的服务

正如您所发现的,这在任何真正意义上的术语中都是不可能的。这也是糟糕的设计

每 5 分钟 该服务检查设备的当前位置并调用 Web 服务

使用AlarmManager.

使用 AlarmManager 使 5 分钟。对服务的间隔调用。但我无法完成这项工作。

这是一个示例项目,展示了如何使用它,以及如何使用它,WakefulIntentService以便您在尝试完成整个 Web 服务时保持清醒。

如果您仍然遇到问题,请针对您遇到的具体事情提出一个新问题,这些事情AlarmManager让您感到悲伤。

于 2010-04-02T12:15:29.450 回答
26

我的一个应用程序做了非常相似的事情。我建议在给定时间段后唤醒服务postDelayed()

有一个处理程序字段:

private final Handler handler = new Handler();

和复习Runnable

private final Runnable refresher = new Runnable() {
  public void run() {
    // some action
  }
};

您可以在可运行文件中触发通知。

在服务构建时,在每次执行之后启动它,如下所示:

handler.postDelayed(refresher, /* some delay in ms*/);

onDestroy()删除帖子

handler.removeCallbacks(refresher);

要在启动时启动服务,您需要一个自动启动器。这在您的清单中

<receiver android:name="com.example.ServiceAutoStarter">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
  </receiver>

ServiceAutoStarter看起来像这样:

public class ServiceAutoStarter extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
    context.startService(new Intent(context, UpdateService.class));
  }
}

阻止操作系统终止服务是很棘手的。此外,您的应用程序可能会RuntimeException发生崩溃,或者您的逻辑可能会停止。

在我的情况下,它似乎总是有助于刷新屏幕上的服务BroadcastReceiver。因此,如果更新链停滞不前,它将在用户使用手机时复活。

在服务中:

private BroadcastReceiver screenOnReceiver; 

为您服务onCreate()

screenOnReceiver = new BroadcastReceiver() {

  @Override
  public void onReceive(Context context, Intent intent) {
    // Some action
  }
};

registerReceiver(screenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));

然后注销您的onDestroy()服务

unregisterReceiver(screenOnReceiver);
于 2010-04-02T11:44:23.070 回答
4

您可以通过一些简单的实现来做到这一点:

public class LocationTrace extends Service implements LocationListener{

    // The minimum distance to change Updates in meters
    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters
    private static final int TWO_MINUTES = 100 * 10;

    // The minimum time between updates in milliseconds
    private static final long MIN_TIME_BW_UPDATES = 1000 * 10; // 30 seconds

    private Context context;

    double latitude;
    double longitude;

    Location location = null;
    boolean isGPSEnabled = false;
    boolean isNetworkEnabled = false;
    protected LocationManager locationManager;


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

        this.context = this;
        get_current_location();
//      Toast.makeText(context, "Lat"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
        return START_STICKY;
    }


    @Override
    public void onLocationChanged(Location location) {
        if((location != null) && (location.getLatitude() != 0) && (location.getLongitude() != 0)){

            latitude = location.getLatitude();
            longitude = location.getLongitude();

            if (!Utils.getuserid(context).equalsIgnoreCase("")) {
                Double[] arr = { location.getLatitude(), location.getLongitude() };

               // DO ASYNCTASK
            }
        }

    }


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

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }

    /*
    *  Get Current Location
    */
    public Location get_current_location(){

        locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);

        isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);

        isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if(!isGPSEnabled && !isNetworkEnabled){



        }else{
            if (isGPSEnabled) {

                if (location == null) {
                    locationManager.requestLocationUpdates(
                            LocationManager.GPS_PROVIDER,
                            MIN_TIME_BW_UPDATES,
                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                    if (locationManager != null) {
                        location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
                        if (location != null) {
                            latitude = location.getLatitude();
                            longitude = location.getLongitude();
        //                  Toast.makeText(context, "Latgps"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
                        }
                    }
                }
            }
            if (isNetworkEnabled) {

                locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER,
                        MIN_TIME_BW_UPDATES,
                        MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                if (locationManager != null) {

                    if (location != null) {
                        latitude = location.getLatitude();
                        longitude = location.getLongitude();
        //              Toast.makeText(context, "Latgps1"+latitude+"long"+longitude,Toast.LENGTH_SHORT).show();
                    }
                }
            }
        }

        return location;
    }


    public double getLatitude() {
        if(location != null){
            latitude = location.getLatitude();
        }
        return latitude;
    }

    public double getLongitude() {
         if(location != null){
             longitude = location.getLongitude();
         }

        return longitude;
    }


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

    @Override
    public void onDestroy() {
        if(locationManager != null){
            locationManager.removeUpdates(this);
        }
        super.onDestroy();
    }

}

您可以通过以下方式启动服务:

/*--Start Service--*/
startService(new Intent(Splash.this, LocationTrace.class));

在清单中:

 <service android:name=".LocationTrace">
            <intent-filter android:priority="1000">
                <action android:name="android.location.PROVIDERS_CHANGED"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
  </service>
于 2015-12-31T08:55:38.730 回答
1

According to me when you want your service to run always means that it shouldn't get stopped when the app is killed, because if your app is running or is in the background anyways your service will be running. When you kill the app while a service is running the onTaskRemoved function is triggered.

@Override
        public void onTaskRemoved(Intent rootIntent) {
            Log.d(TAG, "onTaskRemoved: removed");
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(System.currentTimeMillis() + 10000);
((AlarmManager) getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), PendingIntent.getService(getApplicationContext(), 0, new Intent(getApplicationContext(), RegisterReceiverService.class), 0));
            super.onTaskRemoved(rootIntent);
        }

So basically once you kill the app the service will be started after 10 seconds. Note: In case you want to use

AlarmManager.ELAPSED_REALTIME_WAKEUP

the minimum time after which you'll be able to restart the service will be 15 minutes.

Remember you also need to start the service on reboot using BroadcastReceiver.

于 2020-02-19T11:36:04.400 回答
1

通过这三个步骤,您可以每 5 分钟唤醒大多数 Android 设备:

1. 为不同的 API 设置您的替代 AlarmManager:

AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent i = new Intent(getApplicationContext(), OwnReceiver.class);
PendingIntent pi = PendingIntent.getBroadcast(getApplicationContext(), 0, i, 0);

if (Build.VERSION.SDK_INT >= 23) {
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}
else if (Build.VERSION.SDK_INT >= 19) {
am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
} else {
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
}

2.构建自己的静态广播接收器:

public static class OwnReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

       //do all of your jobs here

        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        Intent i = new Intent(context, OwnReceiver.class);
        PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);

        if (Build.VERSION.SDK_INT >= 23) {
            am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
        }
        else if (Build.VERSION.SDK_INT >= 19) {
            am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
        } else {
            am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (1000 * 60 * 5), pi);
        }
    }
}

3. 添加<receiver>AndroidManifest.xml

<receiver android:name=".OwnReceiver"  />
于 2018-04-17T12:32:17.910 回答