我想每15分钟向服务器发布位置更新,即使应用程序没有在前台运行

时间:2013-11-26 07:44:44

标签: android service alarmmanager

我希望从Android手机到服务器每15分钟到服务器发送一次位置更新。这是服务或报警管理器是最好的选择。

如果我启动服务,我是否可以启动asynctask将位置发布到服务器。?

这是我使用的代码:

    @Override
    public void onStart(Intent intent, int startId) {
        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        listener = new MyLocationListener();
        locationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER, 4000, 0, listener);
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
                4000, 0, listener);
    }




    public class MyLocationListener implements LocationListener {

        public void onLocationChanged(final Location loc) {
            Log.i("**************************************", "Location changed");
            if (isBetterLocation(loc, previousBestLocation)) {
                loc.getLatitude();
                loc.getLongitude();

//              
//              intent.putExtra("Latitude", loc.getLatitude());
//              intent.putExtra("Longitude", loc.getLongitude());
//              intent.putExtra("Provider", loc.getProvider());
//              
//              sendBroadcast(intent);

            }
        }

        public void onProviderDisabled(String provider) {
            Toast.makeText(getApplicationContext(), "Gps Disabled",
                    Toast.LENGTH_SHORT).show();
        }

        public void onProviderEnabled(String provider) {
            Toast.makeText(getApplicationContext(), "Gps Enabled",
                    Toast.LENGTH_SHORT).show();
        }
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }

    }
}

我不知道如何每15分钟间隔运行服务后台.. 当我获得新的位置更新时,我想启动一个aysnctask.Is服务或警报管理器是最好的选择。     如果我启动服务,我可以启动asynctask将位置发布到服务器。?

2 个答案:

答案 0 :(得分:10)

更新回答

旧答案不适用于针对M或更高级别的应用,因为静态连接接收器will no longer receive broadcasts

现在,最佳选择是FusedLocationApi,它是Google Play服务的一部分。

compile 'com.google.android.gms:play-services-location:[version_here]'

创建处理位置更新的IntentService

/**
 * Handles location updates from FusedLocationProvider
 */
public final class LocationUpdateService extends IntentService {

    private static final String TAG = "LocationUpdateService";

    public static final String ACTION_HANDLE_LOCATION = "ACTION_HANDLE_LOCATION";

    public LocationUpdateService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(final Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (action != null) {
                switch (action) {
                    case ACTION_HANDLE_LOCATION:
                        onActionHandleLocation(intent);
                        break;

                    default:
                        Log.w(TAG, "onHandleIntent(), unhandled action: " + action);
                        break;
                }
            }
        }
    }

    private void onActionHandleLocation(@NonNull final Intent intent) {
        if (!LocationResult.hasResult(intent)) {
            Log.w(TAG, "No location result in supplied intent");
            return;
        }

        final LocationResult locationResult = LocationResult.extractResult(intent);
        if (locationResult == null) {
            Log.w(TAG, "LocationResult is null in supplied intent");
            return;
        }

        // TODO send to server using a blocking request.
        // Remember that this is the background thread already
    }
}

不要忘记将其添加到Manifest应用程序标记

<service android:name=".LocationUpdateService"/>

请求位置权限,连接GoogleApiClient,您现在可以执行以下操作

@NonNull
private static PendingIntent createLocationServiceIntent(@NonNull final Context context) {
    final Intent intent = new Intent(context, LocationUpdateService.class);
    intent.setAction(LocationUpdateService.ACTION_HANDLE_LOCATION);

    return PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

public static void scheduleLocationUpdates(@NonNull final Context context,
        @NonNull final GoogleApiClient googleApiClient) {
    // Make sure you have permission, request if necessary
    if (googleApiClient.isConnected() &&
            ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
            // ACCESS_COARSE_LOCATION, depending on what you want
            == PackageManager.PERMISSION_GRANTED) {

        LocationServices.FusedLocationApi.requestLocationUpdates(googleApiClient,
                LocationRequest.create().setInterval(AlarmManager.INTERVAL_FIFTEEN_MINUTES),
                createLocationServiceIntent(context));
    }
}

public static void unscheduleLocationUpdates(@NonNull final Context context,
        @NonNull final GoogleApiClient googleApiClient) {
    if (googleApiClient.isConnected()) {
        LocationServices.FusedLocationApi
                .removeLocationUpdates(googleApiClient, createLocationServiceIntent(context));
    }
}

旧答案

AsyncTask适用于短时间操作,主要是在UI中等待时。在这种情况下,您最好使用Service开始WakeLock。但请注意,每隔15 minutes,您可能会耗尽电池电量。当设备未连接到网络时,请考虑不安排警报。

1)注册静态BroadcastReceiver in Manifest以监控设备是否已连接。 Intent action for network events in android sdk

2)当设备连接到互联网并且允许位置时,启动将保存WakeLock的服务,侦听一个位置更新,取消注册位置更新,将位置发送到服务器,安排AlarmManager,释放WakeLock和cals stopSelf();如果没有进行位置更新,请考虑超时。如果达到超时,取消注册位置更新,注册下一个警报,释放WakeLock并调用stopSelf。

3)如果您在Receiver中接收网络已断开连接,请取消所有警报并在运行时停止服务。

按要求执行第2步的代码示例

public final class ConnectivityReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        final AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        final PendingIntent wakeupIntent = PendingIntent.getService(context, 0,
                new Intent(context, LocationUpdaterService.class), PendingIntent.FLAG_UPDATE_CURRENT);

        final boolean hasNetwork = !intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
        if (hasNetwork) {
            // start service now for doing once
            context.startService(new Intent(context, LocationUpdaterService.class));

            // schedule service for every 15 minutes
            alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                    SystemClock.elapsedRealtime() + AlarmManager.INTERVAL_FIFTEEN_MINUTES,
                    AlarmManager.INTERVAL_FIFTEEN_MINUTES, wakeupIntent);
        } else {
            alarmManager.cancel(wakeupIntent);
        }
    }

}

public  final class LocationUpdaterService extends Service implements LocationListener {

    private enum State {
        IDLE, WORKING;
    }



    private static State state;

    private LocationManager locationManager;
    private WakeLock wakeLock;

    static {
        state = State.IDLE;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        this.wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "LocationUpdaterService");
    }


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

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (state == State.IDLE) {
            state = State.WORKING;
            this.wakeLock.acquire();
            // register location updates, not gonna code it you know

        }
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        state = State.IDLE;
        if (this.wakeLock.isHeld()) {
            this.wakeLock.release();
        }
    }

    private void sendToServer(Location location) {
        // send to server in background thread. you might want to start AsyncTask here
    }

    private void onSendingFinished() {
        // call this after sending finished to stop the service
        this.stopSelf(); //stopSelf will call onDestroy and the WakeLock releases.
        //Be sure to call this after everything is done (handle exceptions and other stuff) so you release a wakeLock
        //or you will end up draining battery like hell
    }

    @Override
    public void onLocationChanged(Location location) {
        locationManager.removeUpdates(this); // you will want to listen for updates only once
        sendToServer(location);
    }

    @Override
    public void onProviderDisabled(String provider) {
    }

    @Override
    public void onProviderEnabled(String provider) {
    }

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

}

答案 1 :(得分:0)

是的,您可以每隔15分钟为接收器安排警报,并触发可启动AsyncTask并发布位置更新的服务