【发布时间】:2019-03-27 00:15:25
【问题描述】:
在前言中,我正在使用 react-native,我们的应用程序使用了很多后台进程。我们尝试了许多基于 React Native 的解决方案,例如 background-fetch、background-geolocation 等。我们在测试中发现,在后台线程中收集数据的最佳方法是 Android 的本机 Work Manager。我已经设法在工作管理器中实现了一些基本的东西,比如时间戳和应用程序的使用。但现在我正在努力让新的 Android Places SDK(Google Places 现已弃用)在 Work Manager 中工作。下面是我遇到的错误的图片。
Can't create handler inside thread that has not called Looper.prepare()
在遇到任何错误后,我很自然地来到这里,你们中的许多人建议异步任务,并创建一个处理程序。由于对 Android 线程处理不熟悉,我不确定如何或在哪里实现这些东西。到目前为止,我已经尝试在 onCreate() 以及我的 Worker 中调用 Looper.prepare()。
这是我的地方代码
package com.bettertime.betterLocation;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.RequiresPermission;
import android.util.Log;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.tasks.Task;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.model.Place;
import com.google.android.libraries.places.api.model.PlaceLikelihood;
import com.google.android.libraries.places.api.net.FindCurrentPlaceRequest;
import com.google.android.libraries.places.api.net.FindCurrentPlaceResponse;
import com.google.android.libraries.places.api.net.PlacesClient;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.support.v7.app.AppCompatActivity;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.ACCESS_WIFI_STATE;
import static com.bettertime.MainActivity.placesClient;
public class BetterLocation extends AppCompatActivity {
private List<Place.Field> placeList = new ArrayList<>();
private static String TAG = "Location: ";
public static Map<String, Object> places = new HashMap<>();
int PERMISSION_ALL = 1;
String[] PERMISSIONS = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_WIFI_STATE
};
public void findCurrentPlace() {
places.clear();
if(ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, ACCESS_WIFI_STATE) == PackageManager.PERMISSION_GRANTED) {
findCurrentPlaceWithPermissions();
}
}
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
private void findCurrentPlaceWithPermissions() {
placeList.add(Place.Field.NAME);
placeList.add(Place.Field.ADDRESS);
placeList.add(Place.Field.LAT_LNG);
placeList.add(Place.Field.TYPES);
FindCurrentPlaceRequest currentPlaceRequest =
FindCurrentPlaceRequest.builder(placeList).build();
if(ContextCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, ACCESS_WIFI_STATE) == PackageManager.PERMISSION_GRANTED) {
Task<FindCurrentPlaceResponse> currentPlaceTask = placesClient.findCurrentPlace(currentPlaceRequest);
currentPlaceTask.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
FindCurrentPlaceResponse response = task.getResult();
assert response != null;
for (PlaceLikelihood placeLikelihood : response.getPlaceLikelihoods()) {
Log.d(TAG, "findCurrentPlace: "
+ placeLikelihood.getPlace().getName() + "\n"
+ placeLikelihood.getPlace().getAddress() + "\n"
+ placeLikelihood.getPlace().getLatLng() + "\n"
+ placeLikelihood.getPlace().getTypes() + "\n"
+ placeLikelihood.getLikelihood());
PlaceObj placeObj = new PlaceObj(
placeLikelihood.getPlace().getName(),
placeLikelihood.getPlace().getAddress(),
placeLikelihood.getPlace().getLatLng(),
placeLikelihood.getPlace().getTypes(),
placeLikelihood.getLikelihood());
places.put("place", placeObj);
}
} else {
Exception exception = task.getException();
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
Log.e(TAG, "findCurrentPlaceWithPermissions: " + apiException.getStatusCode());
}
}
});
}
}
//////////////////////////
// Helper methods below //
//////////////////////////
private boolean checkPermission(String permission) {
boolean hasPermission =
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
if (!hasPermission) {
ActivityCompat.requestPermissions(this, new String[]{permission}, 0);
}
return hasPermission;
}
public static boolean hasPermissions(Context context, String... permissions) {
if (context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
}
这是我的工作经理
package com.bettertime.betterWorkManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.NonNull;
import android.util.Log;
import com.bettertime.betterLocation.BetterLocation;
import com.bettertime.packages.NativeUsageEvents;
import com.bettertime.timePackage.NativeTime;
import com.google.firebase.firestore.FirebaseFirestore;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import static com.bettertime.betterLocation.BetterLocation.places;
public class BetterWorkManager extends Worker {
private static final String TAG = "Work Manager Firing";
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private NativeTime nativeTime = new NativeTime();
public static Handler mHandler;
private BetterLocation betterLocation = new BetterLocation();
public BetterWorkManager(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Worker.Result doWork() {
Log.d(TAG, "doWork: fired");
userStamp();
return Result.success();
}
private void userStamp(){
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
betterLocation.findCurrentPlace();
}
};
Looper.loop();
Log.d(TAG, "places test: " + places.toString());
}
我去掉了一些不必要的部分,但这就是它的要点。而且这里是我的主要活动。
package com.bettertime;
import android.os.Bundle;
import com.bettertime.betterWorkManager.BetterWorkManager;
import com.facebook.react.ReactActivity;
import com.google.android.libraries.places.api.Places;
import com.google.android.libraries.places.api.net.PlacesClient;
import java.util.concurrent.TimeUnit;
import androidx.work.ExistingPeriodicWorkPolicy;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
public class MainActivity extends ReactActivity {
private static final String W_TAG = "Periodic Worker";
public static PlacesClient placesClient;
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "BetterYou";
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Places.initialize(getApplicationContext(), "THIS_IS_MY_API_KEY");
placesClient = Places.createClient(this);
PeriodicWorkRequest fireUploadBuilder =
new PeriodicWorkRequest.Builder(BetterWorkManager.class, 15, TimeUnit.MINUTES).build();
WorkManager.getInstance().enqueueUniquePeriodicWork(W_TAG, ExistingPeriodicWorkPolicy.KEEP, fireUploadBuilder);
}
}
有没有人成功尝试在工作管理器中实施 Places SDK?如果权限已被接受,为什么 Places SDK 必须与主 UI 线程通信?任何意见是极大的赞赏。我已经查看了 Looper 和 AsyncTask 的文档,但是两者都没有多大意义,因为我几乎没有将它们放入的上下文。如果您提出任何建议,请提供有关在何处使用它的上下文。
【问题讨论】:
标签: android google-places-api google-places android-workmanager