如何在后台访问位置Android 12?
How to access location in background Android 12?
我正在制作一个应用程序,当用户点击电源键两次时获取最后已知的位置。我正在使用前台服务来注册广播接收器,对于位置,我正在使用 fusedlocationproviderclient。用户可以在应用程序处于后台时获取位置。我的问题是我只能获取一次位置。第二次位置为空。我该如何解决?
注意:
它在 android 7 版本中运行良好。
服务:
public class ScreenOnOffBackgroundService extends Service {
private ScreenOnOffReceiver screenOnOffReceiver = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent mainIntent = new Intent(this, DashboardActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,mainIntent, 0);
Notification notification = new NotificationCompat.Builder(this,"safetyId")
.setContentTitle("Safety Service")
.setContentText("Press power key to send alert")
.setSmallIcon(R.drawable.android)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
// Create an IntentFilter instance.
IntentFilter intentFilter = new IntentFilter();
// Add network connectivity change action.
intentFilter.addAction("android.intent.action.SCREEN_ON");
// Set broadcast receiver priority.
intentFilter.setPriority(100);
screenOnOffReceiver = new ScreenOnOffReceiver();
HandlerThread broadcastHandlerThread = new HandlerThread("SafetyThread");
broadcastHandlerThread.start();
Looper looper = broadcastHandlerThread.getLooper();
Handler broadcastHandler = new Handler(looper);
registerReceiver(screenOnOffReceiver,intentFilter,null,broadcastHandler);
}
private void createNotificationChannel() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ){
NotificationChannel channel = new NotificationChannel(
"safetyId",
"Safety Service",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
@Override
public void onDestroy() {
stopForeground(true);
stopSelf();
// Unregister screenOnOffReceiver when destroy.
if(screenOnOffReceiver!=null)
{
unregisterReceiver(screenOnOffReceiver);
}
}
}
广播接收器:
public class ScreenOnOffReceiver extends BroadcastReceiver {
private int count = 0;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action) || Intent.ACTION_SCREEN_OFF.equals(action)) {
count++;
if (count == 2) {
count = 0;
DashboardActivity.getInstance().getLastLocation();
}
}
}
}
仪表板Activity:
public class DashboardActivity extends AppCompatActivity {
public Button btnAlert;
private static DashboardActivity instance;
private final static int REQUEST_CODE = 123;
private FusedLocationProviderClient locationProviderClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
instance = this;
registerService();
btnAlert = findViewById(R.id.btnAlert);
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
btnAlert.setOnClickListener(view -> getLastLocation());
}
public static DashboardActivity getInstance(){
return instance;
}
public void registerService(){
if(!foregroundServiceRunning()){
Intent backgroundService = new Intent(this, ScreenOnOffBackgroundService.class);
ContextCompat.startForegroundService(this,backgroundService);
}
}
public boolean foregroundServiceRunning(){
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
if(ScreenOnOffBackgroundService.class.getName().equals(service.service.getClassName())){
return true;
}
}
return false;
}
@SuppressLint("MissingPermission")
public void getLastLocation() {
// check if permissions are given
if (checkPermissions()) {
// check if location is enabled
if (isLocationEnabled()) {
locationProviderClient.getLastLocation().addOnCompleteListener(task -> {
Location location = task.getResult();
if (location == null) {
requestNewLocationData();
} else {
Toast.makeText(this, "Latitude: "+location.getLatitude(), Toast.LENGTH_LONG).show();
}
});
} else {
Toast.makeText(this, "Please turn on your location", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
} else {
requestPermissions();
}
}
private boolean checkPermissions() {
return ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
String[] permissionArray = new String[]{
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION,};
ActivityCompat.requestPermissions(this, permissionArray, REQUEST_CODE);
}
@SuppressLint("MissingPermission")
private void requestNewLocationData() {
LocationRequest mLocationRequest = LocationRequest.create()
.setInterval(100)
.setFastestInterval(3000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setMaxWaitTime(100).setNumUpdates(1);
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
private final LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
private boolean isLocationEnabled() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
@Override
public void
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLastLocation();
}
}
if (requestCode == 0) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
notifyPolice();
}
}
}
}
首先- DashboardActivity.getInstance()- 永远不要这样做。您假设始终只有 1 个 activity 实例。那是错误的。可以有 0 个。可以有 2 个。你不能让 activity 成为单例。此外,这总是会造成内存泄漏。永远不要将 Activity 存储在静态变量中,这总是内存泄漏。它也是(由于第一个事实)错误的,因为它可以指向 Activity.
的错误实例
其次 - 您正在使用 getLastLocation。不要那样做。该函数用于优化,通常 return null(我知道文档说的是相反的。那里的文档一直是错误的。)如果您需要位置,请改为请求它。 getLastLocation 应该只用于在请求位置更新之前乐观地快速获得结果。
第三,您对 requestNewLocation 的调用传递了一个不执行任何操作的位置处理程序。它甚至没有更新 mLastLocation,因为这是一个方法级变量,而不是 class 变量。
第四-您是否阅读了ANdroid12中关于后台位置处理的新规则? https://proandroiddev.com/android-12-privacy-changes-for-location-55ffd8c016fd
这些只是主要错误,而不是让我“嗯?”的小错误。出于好意,此代码需要进行重大重构。感觉是一个不太懂的人Android 把十几个他不懂的例子拼凑出来的。如果我是你,我会从简化概念开始——做一件事,理解它,然后再做另一件事。你现在一下子做这些事情超出了你的能力,你最好一次只学一件事。
我正在制作一个应用程序,当用户点击电源键两次时获取最后已知的位置。我正在使用前台服务来注册广播接收器,对于位置,我正在使用 fusedlocationproviderclient。用户可以在应用程序处于后台时获取位置。我的问题是我只能获取一次位置。第二次位置为空。我该如何解决?
注意: 它在 android 7 版本中运行良好。
服务:
public class ScreenOnOffBackgroundService extends Service {
private ScreenOnOffReceiver screenOnOffReceiver = null;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent mainIntent = new Intent(this, DashboardActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,0,mainIntent, 0);
Notification notification = new NotificationCompat.Builder(this,"safetyId")
.setContentTitle("Safety Service")
.setContentText("Press power key to send alert")
.setSmallIcon(R.drawable.android)
.setContentIntent(pendingIntent)
.build();
startForeground(1,notification);
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
// Create an IntentFilter instance.
IntentFilter intentFilter = new IntentFilter();
// Add network connectivity change action.
intentFilter.addAction("android.intent.action.SCREEN_ON");
// Set broadcast receiver priority.
intentFilter.setPriority(100);
screenOnOffReceiver = new ScreenOnOffReceiver();
HandlerThread broadcastHandlerThread = new HandlerThread("SafetyThread");
broadcastHandlerThread.start();
Looper looper = broadcastHandlerThread.getLooper();
Handler broadcastHandler = new Handler(looper);
registerReceiver(screenOnOffReceiver,intentFilter,null,broadcastHandler);
}
private void createNotificationChannel() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ){
NotificationChannel channel = new NotificationChannel(
"safetyId",
"Safety Service",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
@Override
public void onDestroy() {
stopForeground(true);
stopSelf();
// Unregister screenOnOffReceiver when destroy.
if(screenOnOffReceiver!=null)
{
unregisterReceiver(screenOnOffReceiver);
}
}
}
广播接收器:
public class ScreenOnOffReceiver extends BroadcastReceiver {
private int count = 0;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SCREEN_ON.equals(action) || Intent.ACTION_SCREEN_OFF.equals(action)) {
count++;
if (count == 2) {
count = 0;
DashboardActivity.getInstance().getLastLocation();
}
}
}
}
仪表板Activity:
public class DashboardActivity extends AppCompatActivity {
public Button btnAlert;
private static DashboardActivity instance;
private final static int REQUEST_CODE = 123;
private FusedLocationProviderClient locationProviderClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
instance = this;
registerService();
btnAlert = findViewById(R.id.btnAlert);
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
btnAlert.setOnClickListener(view -> getLastLocation());
}
public static DashboardActivity getInstance(){
return instance;
}
public void registerService(){
if(!foregroundServiceRunning()){
Intent backgroundService = new Intent(this, ScreenOnOffBackgroundService.class);
ContextCompat.startForegroundService(this,backgroundService);
}
}
public boolean foregroundServiceRunning(){
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for(ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
if(ScreenOnOffBackgroundService.class.getName().equals(service.service.getClassName())){
return true;
}
}
return false;
}
@SuppressLint("MissingPermission")
public void getLastLocation() {
// check if permissions are given
if (checkPermissions()) {
// check if location is enabled
if (isLocationEnabled()) {
locationProviderClient.getLastLocation().addOnCompleteListener(task -> {
Location location = task.getResult();
if (location == null) {
requestNewLocationData();
} else {
Toast.makeText(this, "Latitude: "+location.getLatitude(), Toast.LENGTH_LONG).show();
}
});
} else {
Toast.makeText(this, "Please turn on your location", Toast.LENGTH_LONG).show();
Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivity(intent);
}
} else {
requestPermissions();
}
}
private boolean checkPermissions() {
return ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
private void requestPermissions() {
String[] permissionArray = new String[]{
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.ACCESS_FINE_LOCATION,};
ActivityCompat.requestPermissions(this, permissionArray, REQUEST_CODE);
}
@SuppressLint("MissingPermission")
private void requestNewLocationData() {
LocationRequest mLocationRequest = LocationRequest.create()
.setInterval(100)
.setFastestInterval(3000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setMaxWaitTime(100).setNumUpdates(1);
locationProviderClient = LocationServices.getFusedLocationProviderClient(this);
locationProviderClient.requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.myLooper());
}
private final LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
Location mLastLocation = locationResult.getLastLocation();
}
};
private boolean isLocationEnabled() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
@Override
public void
onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLastLocation();
}
}
if (requestCode == 0) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
notifyPolice();
}
}
}
}
首先- DashboardActivity.getInstance()- 永远不要这样做。您假设始终只有 1 个 activity 实例。那是错误的。可以有 0 个。可以有 2 个。你不能让 activity 成为单例。此外,这总是会造成内存泄漏。永远不要将 Activity 存储在静态变量中,这总是内存泄漏。它也是(由于第一个事实)错误的,因为它可以指向 Activity.
的错误实例其次 - 您正在使用 getLastLocation。不要那样做。该函数用于优化,通常 return null(我知道文档说的是相反的。那里的文档一直是错误的。)如果您需要位置,请改为请求它。 getLastLocation 应该只用于在请求位置更新之前乐观地快速获得结果。
第三,您对 requestNewLocation 的调用传递了一个不执行任何操作的位置处理程序。它甚至没有更新 mLastLocation,因为这是一个方法级变量,而不是 class 变量。
第四-您是否阅读了ANdroid12中关于后台位置处理的新规则? https://proandroiddev.com/android-12-privacy-changes-for-location-55ffd8c016fd
这些只是主要错误,而不是让我“嗯?”的小错误。出于好意,此代码需要进行重大重构。感觉是一个不太懂的人Android 把十几个他不懂的例子拼凑出来的。如果我是你,我会从简化概念开始——做一件事,理解它,然后再做另一件事。你现在一下子做这些事情超出了你的能力,你最好一次只学一件事。