我试图在服务器上每隔30分钟更新一次位置



我正在尝试发送服务器中的用户位置。我很快就得到了位置并保存在RoomDatabase中,并从RoomDatabase中获取数据发送到服务器。但当应用程序在后台时,我不可能每隔30分钟就得到一次位置。

//调用主活动

PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(MyWorker.class, 30, TimeUnit.MINUTES)
.addTag(TAG)
.build();
WorkManager.getInstance().enqueueUniquePeriodicWork("Location", ExistingPeriodicWorkPolicy.REPLACE, periodicWork);

//工人级

public class MyWorker extends Worker {
private static final String DEFAULT_START_TIME = "00:00";
private static final String DEFAULT_END_TIME = "30:00";
private static final String TAG = "MyWorker";
/**
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
*/
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
/**
* The fastest rate for active location updates. Updates will never be more frequent
* than this value.
*/
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
/**
* The current location.
*/
private Location mLocation;
/**
* Provides access to the Fused Location Provider API.
*/
private FusedLocationProviderClient mFusedLocationClient;
private Context mContext;
/**
* Callback for changes in location.
*/
private LocationCallback mLocationCallback;
public MyWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
mContext = context;
}
@NonNull
@Override
public Result doWork() {
LocationDAO locationDAO = Room.databaseBuilder(mContext, AppDatabase.class, "db-locations")
.allowMainThreadQueries()   //Allows room to do operation on main thread
.build()
.getLocationDAO();
Log.d(TAG, "doWork: Done");
Log.d(TAG, "onStartJob: STARTING JOB..");
DateFormat dateFormat = new SimpleDateFormat("HH:mm", Locale.getDefault());
Calendar c = Calendar.getInstance();
Date date = c.getTime();
String formattedDate = dateFormat.format(date);
try {
Date currentDate = dateFormat.parse(formattedDate);
Date startDate = dateFormat.parse(DEFAULT_START_TIME);
Date endDate = dateFormat.parse(DEFAULT_END_TIME);
if (currentDate.after(startDate) && currentDate.before(endDate)) {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(mContext);
mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
}
};
LocationRequest mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
try {
mFusedLocationClient
.getLastLocation()
.addOnCompleteListener(new OnCompleteListener<Location>() {
@Override
public void onComplete(@NonNull Task<Location> task) {
Log.d(TAG, "Location : " + task.getResult());
if (task.isSuccessful() && task.getResult() != null) {
mLocation = task.getResult();
Log.d(TAG, "Location : " + mLocation);
Date today = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
String dateToStr = format.format(today);
LocationModel locationModel =new LocationModel();
locationModel.setLat(String.valueOf(mLocation.getLatitude()));
locationModel.setLng(String.valueOf(mLocation.getLongitude()));
locationModel.setDateToStr(dateToStr);
//locationDAO.insert(locationModel);
SaveTask st = new SaveTask(locationModel);
st.execute();
//Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = mContext.getString(R.string.app_name);
String description = mContext.getString(R.string.app_name);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(mContext.getString(R.string.app_name), name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = mContext.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, mContext.getString(R.string.app_name))
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
.setContentTitle("New Location Update")
.setContentText("You are at " + getCompleteAddressString(mLocation.getLatitude(), mLocation.getLongitude()))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setStyle(new NotificationCompat.BigTextStyle().bigText("You are at " + getCompleteAddressString(mLocation.getLatitude(), mLocation.getLongitude())));
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mContext);
// notificationId is a unique int for each notification that you must define
notificationManager.notify(1001, builder.build());
mFusedLocationClient.removeLocationUpdates(mLocationCallback);
} else {
Log.w(TAG, "Failed to get location.");
//Toast.makeText(mContext, "Failed to get location.", Toast.LENGTH_LONG ).show();
}
}
});
} catch (SecurityException unlikely) {
Log.e(TAG, "Lost location permission." + unlikely);
}
try {
mFusedLocationClient.requestLocationUpdates(mLocationRequest, null);
} catch (SecurityException unlikely) {
//Utils.setRequestingLocationUpdates(this, false);
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
}
} else {
Log.d(TAG, "Time up to get location. Your time is : " + DEFAULT_START_TIME + " to " + DEFAULT_END_TIME);
}
} catch (ParseException ignored) {
}
return Result.success();
}
private String getCompleteAddressString(double LATITUDE, double LONGITUDE) {
String strAdd = "";
Geocoder geocoder = new Geocoder(mContext, Locale.getDefault());
try {
List<Address> addresses = geocoder.getFromLocation(LATITUDE, LONGITUDE, 1);
if (addresses != null) {
Address returnedAddress = addresses.get(0);
StringBuilder strReturnedAddress = new StringBuilder();
for (int i = 0; i <= returnedAddress.getMaxAddressLineIndex(); i++) {
strReturnedAddress.append(returnedAddress.getAddressLine(i)).append("n");
}
strAdd = strReturnedAddress.toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return strAdd;
}
class SaveTask extends AsyncTask<Void, Void, Void> {
LocationModel locationModel;
public SaveTask(LocationModel locationModel) {
this.locationModel = locationModel;
}
@Override
protected Void doInBackground(Void... voids) {
DatabaseClient.getInstance(getApplicationContext()).getAppDatabase()
.getLocationDAO()
.insert(locationModel);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}

}

//从数据库获取数据

public class GetTasks extends AsyncTask<Void, Void, List<LocationModel>> {
Context mContext;
String requestType;
public GetTasks(Context context, String requestType) {
this.mContext = context;
this.requestType =requestType;
}
@Override
protected List<LocationModel> doInBackground(Void... voids) {
List<LocationModel> taskList = DatabaseClient
.getInstance(mContext)
.getAppDatabase()
.getLocationDAO().getLocation();
return taskList;
}
@Override
protected void onPostExecute(List<LocationModel> tasks) {
super.onPostExecute(tasks);

if (tasks.size()>0) {
LocationPostReg locationPostReg = new LocationPostReg();
updateLocationValue(locationPostReg);
}
}
public static String convertObjToString(Object clsObj) {
//convert object  to string json
String jsonSender = new Gson().toJson(clsObj, new TypeToken<Object>() {
}.getType());
return jsonSender;
}

//将数据发送到服务器

public void updateLocationValue(LocationPostReg locationPostReg){
locationUpdateInterface apiService =
ApiClient.getClient().create(locationUpdateInterface.class);


String locationStr = convertObjToString(locationPostReg);
RequestBody body = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"),locationStr);
Log.d(TAG, locationStr +"   "+ locationPostReg.getUserid()   +"  ");
Call<LocationSuccessfull> call = apiService.doUpdateLocation(body);
call.enqueue(new Callback<LocationSuccessfull>() {
@Override
public void onResponse(Call<LocationSuccessfull> call, Response<LocationSuccessfull> response) {
int statusCode = response.code();
LocationSuccessfull locationInfo = response.body();
// assert locationInfo != null;
if (locationInfo != null && locationInfo.getSuccess())
{
AsyncTask.execute(() ->
DatabaseClient
.getInstance(mContext)
.getAppDatabase()
.getLocationDAO().deleteAll()
);
Print.e(TAG+ " Remove Data");

}
}
@Override
public void onFailure(Call<LocationSuccessfull> call, Throwable t) {
// Log error here since request failed
Log.e(TAG, "error:  "+ t.toString());
}
});
}

频繁从后台请求位置有限制,您可以在此处阅读主题https://developer.android.com/about/versions/oreo/background-location-limitstext

对于经常从后台请求,你必须将你的应用程序带到前台,一种方法是将服务作为前台服务启动,并使用通知,这样用户就会知道你的应用正在前台工作,或者你可以使用可访问性服务,但用户需要自己启用该置换(你不能从你的应用程序中请求该置换(

这是一个持久性通知的例子,它将把你的应用程序带到前台

fun CreateNotification(str:String,id:Int){
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
var serviceChannel = NotificationChannel(CHANNEL_ID,"name",NotificationManager.IMPORTANCE_HIGH)
var notificationManager= getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(serviceChannel)
}
var intent = Intent(this, MainActivity::class.java)
var pendingIntent =PendingIntent.getActivity(this,0, intent,0)
var stopIntent = Intent(this,CloseBackgroundServiceBroadCast::class.java)
stopIntent.action= CloseBackgroundServiceBroadCast.CLOSE_BACKGROUND_LISTENTER_ACTION
var pendingStop = PendingIntent.getBroadcast(this,30,stopIntent,0)
var notification = NotificationCompat.Builder(this,CHANNEL_ID)
.setContentTitle("title")
.setContentText(str)
.setSmallIcon(yourIcon)
//   .addAction(com.example.autogater.R.drawable.dismiss_test,"Stop")
.addAction(R.drawable.ic_menu_search,getString(com.callgate.autogater.R.string.stop),pendingStop)
.setContentIntent(pendingIntent).build()
//   notificationManager.notify(0,notification)
startForeground(1,notification)
}

最新更新