【问题标题】:Android periodic location updates using workmanagerAndroid 使用 workmanager 定期更新位置
【发布时间】:2020-01-21 19:12:07
【问题描述】:

我正在使用 WorkManager 如下 -

class LocationWorker(
    ctx: Context, params: WorkerParameters
) : CoroutineWorker(ctx, params), KoinComponent {

    private val locationDataRepository: LocationDataRepository by inject()

    override suspend fun doWork(): Result {
        return try {
            locationDataRepository.triggerLocationUpdates()
            Result.success()
        } catch (e: Exception) {
            Result.failure()
        }
    }
}

我触发 Worker 为 -

val myWorker =
            PeriodicWorkRequestBuilder<LocationWorker>(
                15,
                TimeUnit.MINUTES
            ).addTag(
                "location"
            ).build()
        WorkManager.getInstance(context).enqueueUniquePeriodicWork(
            "location",
            ExistingPeriodicWorkPolicy.KEEP,
            myWorker
        )

如您所见,WorkManager 的最短时间为 15 分钟。我想每隔几秒钟就以非常短的时间间隔跟踪位置,而且我希望即使在手机屏幕关闭时也能跟踪位置。 WorkManager 是满足我要求的正确选择,还是您会建议我使用其他 API?

【问题讨论】:

  • 我想是的,请阅读这个中型的博文,你会明白它的面糊。快乐编码:) medium.com/google-developer-experts/…
  • @umerfarooq 谢谢 :) 但是工作经理提供了 15 分钟的最短时间间隔。如果我想每 1 分钟做一次呢?
  • WorkManager 并非设计为每秒运行任务,因为它有两个选项来构建工作请求,即 PeriodicWorkRequest - 每 15 分钟运行一次重复任务,即使我们将时间间隔更改为 anyhwere
  • 您可以实现作业调度程序,但它会耗尽电池。
  • @Coderbox 是的,即使我使用前台服务来获取位置更新。但是缺点是应用被杀死时前台服务无法运行

标签: android kotlin coroutine android-workmanager


【解决方案1】:

我认为这个 codelab 是最好的解决方案。没有 WorkManager,但对我来说,它可以在 AccessibilityService 中工作(我意识到它就像 ForegroundService 的替代品)以逃避永久通知https://codelabs.developers.google.com/codelabs/background-location-updates-android-o/#0

【讨论】:

    【解决方案2】:

    即使应用程序被杀死,它也可能对您有所帮助..我只是一点点 当设备进入打盹模式时担心,因为当 GPS 无法访问时 设备静止

    前台服务主要目的是在应用被终止时以持久通知运行

    LocationService.class

    public class LocationService extends Service implements
            GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
        public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000 * 30; //30 secs
        public static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
                UPDATE_INTERVAL_IN_MILLISECONDS / 2;
        protected static final String TAG = "LocationUpdateService";
        public static final int HORIZONTAL_ACCURACY_IN_METERS = 100;
    
        /**
         * The identifier for the notification displayed for the foreground service.
         */
        private static final int NOTIFICATION_ID = 12345678;
    
        public static boolean mRequestingLocationUpdates = false;
        public boolean isEnded = false;
        protected GoogleApiClient mGoogleApiClient;
        protected LocationRequest mLocationRequest;
    
    
    
        private SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        private double latitude = 0;
        private double longitude = 0;
        private float[] results1 = new float[1];
        private float distanceInMeters = 0;
        private Handler mHandler;
    
    
        @Override
        public void onCreate() {
            super.onCreate();
    
    
            String CHANNEL_ID = "FOREGROUND_CHANNEL";
            if (Build.VERSION.SDK_INT >= 26) {
    
                NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                        "location_notification",
                        NotificationManager.IMPORTANCE_DEFAULT);
    
                ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
            }
    
            Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setOngoing(true)
                    .setContentTitle("G Star")
    
                    .setSmallIcon(R.drawable.gm_noti_logo)
                    .setContentText("Running").build();
    
            startForeground(NOTIFICATION_ID, notification);
            Utility.getInstance().makeDescriptiveLogs("ON CREATE WAS HIT");
    
            sendLocationDataToServerPeriodically();
    
    
        }
    
        private void sendLocationDataToServerPeriodically() {
    
    
    //getting the alarm manager
            AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    
            //creating a new intent specifying the broadcast receiver
            Intent intentLR = new Intent(this, PostLocationReceiver.class);
    
            PendingIntent pi = PendingIntent.getBroadcast(this, 0, intentLR,
                    PendingIntent.FLAG_UPDATE_CURRENT);
    
    
            if (android.os.Build.VERSION.SDK_INT >= 23) {
                assert am != null;
                am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                        AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
            } else if (Build.VERSION.SDK_INT >= 19) {
                if (am != null) {
                    am.setInexactRepeating(AlarmManager.RTC_WAKEUP,
                            System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
                }
            } else {
                if (am != null) {
                    am.setRepeating(AlarmManager.RTC_WAKEUP,
                            System.currentTimeMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, pi);
                }
            }
    
    
        }
    
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
    
            isEnded = false;
    
            Utility.getInstance().makeDescriptiveLogs("ONSTART COMMAND WAS HIT");
            buildGoogleApiClient();
            if (mGoogleApiClient.isConnected() && mRequestingLocationUpdates) {
                startLocationUpdates();
            }
            mHandler = new Handler();
            return START_STICKY;
        }
    
        @Override
        public void onConnected(Bundle bundle) {
            startLocationUpdates();
        }
    
        @Override
        public void onConnectionSuspended(int i) {
            // The connection to Google Play services was lost for some reason. We call connect() to
            // attempt to re-establish the connection.
    
            mGoogleApiClient.connect();
        }
    
        @Override
        public void onLocationChanged(Location location) {
    
            if (location.getAccuracy() < HORIZONTAL_ACCURACY_IN_METERS)
                updateUI(location);
        }
    
        @Override
        public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
            // Refer to the javadoc for ConnectionResult to see what error codes might be returned in
            // onConnectionFailed.
    
        }
    
        protected synchronized void buildGoogleApiClient() {
    
            mGoogleApiClient = new GoogleApiClient.Builder(this)
                    .addConnectionCallbacks(this)
                    .addOnConnectionFailedListener(this)
                    .addApi(LocationServices.API)
                    .build();
    
            createLocationRequest();
        }
    
        /**
         * Updates the latitude, the longitude, and the last location time in the UI.
         */
        private void updateUI(Location mCurrentLocation) {
    
    
    
            mHandler.post(() -> {
                /*GET DEVICE CURRENT BATTERY LEVEL*/
                int batteryPercent = Utility.getInstance().getBatteryPercentage(LocationService.this);
    
    
                /*  CALCULATE DISTANCE BETWEEN LAT LONG INTERVALS*/
                if (latitude != 0 && longitude != 0) {
                    Location.distanceBetween(latitude, longitude, mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), results1);
                    distanceInMeters = results1[0];
                }
    
    
                latitude = mCurrentLocation.getLatitude();
                longitude = mCurrentLocation.getLongitude();
    
                /*CHECK IF DEVICE HAS ACTIVE INTERNET CONNECTION*/
                String networkStatus = Utility.getInstance().checkConnection(LocationService.this) ? "1" : "0";
    
    
                /*CHECK NETWORK SIGNAL STRENGTH*/
                String signalStrength = Utility.getInstance().getSignalStrength(LocationService.this);
    
                SQLiteDBHandler db = SQLiteDBHandler.getInstance(LocationService.this);
                db.insertDeviceLocation(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude(), Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? mCurrentLocation.getSpeedAccuracyMetersPerSecond() : mCurrentLocation.getSpeed(), sdf.format(Calendar.getInstance().getTime()), distanceInMeters, batteryPercent, networkStatus, signalStrength);
    
    
            });
    
        }
    
        protected void createLocationRequest() {
            mGoogleApiClient.connect();
            mLocationRequest = new LocationRequest();
            mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
            mLocationRequest.setSmallestDisplacement(5);
            mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
            mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
        }
    
        /**
         * Requests location updates from the FusedLocationApi.
         */
        public void startLocationUpdates() {
            if (!mRequestingLocationUpdates) {
                mRequestingLocationUpdates = true;
    
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                    return;
                }
    
    
                LocationServices.FusedLocationApi.requestLocationUpdates(
                        mGoogleApiClient, mLocationRequest, this);
    
                isEnded = true;
            }
        }
    
        /**
         * Removes location updates from the FusedLocationApi.
         */
        public void stopLocationUpdates() {
            if (mRequestingLocationUpdates) {
                mRequestingLocationUpdates = false;
    
    
    
                LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient, this);
    
            }
        }
    
        @Override
        public void onDestroy() {
    
            mHandler.removeCallbacksAndMessages(null);
    
            stopLocationUpdates();
    
            super.onDestroy();
        }
    
    
    }
    

    【讨论】:

    • 所以你是说我们不需要WorkManager
    • @IgorGanapolsky 不,我分享了对我有用的东西,因此它可能对某人有所帮助。使用 WorkManager 而不是 AlarmManager 将是一个更好的实现......设备的更多汁液
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-06
    • 1970-01-01
    • 2017-05-02
    • 2013-10-03
    • 1970-01-01
    相关资源
    最近更新 更多