Android地图Fragment无法聚焦当前位置,本地AVD异常求助
Android地图功能异常排查与修复
问题概述
我开发的Android应用包含Map Fragment,原本启动后会自动缩放聚焦到用户当前位置,运行正常。拉取同事开发的导航栏功能分支后,地图能正常显示,但无法设置想要的地标类型。删除原AVD并创建新AVD后,地图不再自动缩放聚焦当前位置,点击SET按钮设置地标类型时出现错误:
E/libprocessgroup: set_timerslack_ns write failed: Operation not permitted
该应用在同事的模拟器上运行正常,但我的环境中出现上述问题。
布局文件(activity_landin_page.xml)
<?xml version="1.0" encoding="utf-8"?> <androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/drawer_layout" tools:context=".LandinPage"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include layout="@layout/main_toolbar"/> <fragment android:id="@+id/mapfragment" class="com.google.android.gms.maps.SupportMapFragment" android:layout_width="match_parent" android:layout_height="500dp" tools:layout_editor_absoluteX="-16dp" /> </LinearLayout> <RelativeLayout android:layout_width="300dp" android:layout_height="match_parent" android:layout_gravity="start" android:background="@color/white"> <include layout="@layout/main_nav_drawer"/> </RelativeLayout> <Spinner android:id="@+id/spType" android:layout_width="409dp" android:layout_height="wrap_content" android:layout_marginTop="550dp" android:layout_marginBottom="130dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/btnSet" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="600dp" android:layout_marginBottom="80dp" android:text="SET" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/mapfragment" /> </androidx.drawerlayout.widget.DrawerLayout>
主页面代码(LandinPage.java)
package com.example.final_opsc_task2; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.FragmentActivity; import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.location.Location; import android.os.AsyncTask; import android.os.Bundle; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; import com.google.android.gms.maps.CameraUpdateFactory; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.OnMapReadyCallback; import com.google.android.gms.maps.SupportMapFragment; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.MarkerOptions; import com.google.android.gms.tasks.OnSuccessListener; import com.google.android.gms.tasks.Task; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.List; public class LandinPage extends FragmentActivity implements OnMapReadyCallback { Spinner spType; Button btnSet; GoogleMap map; FusedLocationProviderClient fusedLocationProviderClient; double currentLat = 0, currentLong = 0; SupportMapFragment supportMapFragment; DrawerLayout drawerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_landin_page); spType = findViewById(R.id.spType); btnSet = findViewById(R.id.btnSet); supportMapFragment = (SupportMapFragment) getSupportFragmentManager() .findFragmentById(R.id.mapfragment); String[] PlaceName = {"bank", "diner", "hotel", "beach"}; String[] TypeOfPlace = {"Bank", "Diner", "Hotel", "Beach"}; spType.setAdapter(new ArrayAdapter<>(LandinPage.this, android.R.layout.simple_spinner_dropdown_item, TypeOfPlace)); fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); if (ActivityCompat.checkSelfPermission(LandinPage.this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { getCurrentLocation(); } else { ActivityCompat.requestPermissions(LandinPage.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 44); } btnSet.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int i = spType.getSelectedItemPosition(); String url = "https://maps.googleapis.com/maps/api/place/nearbysearch/json" + "?location=" + currentLat + "," + currentLong + "&radius=5000" + "&types=" + TypeOfPlace[i] + "&sensor=true" + "&key=" + getResources().getString(R.string.google_map_key); new PlaceTask().execute(url); } }); drawerLayout = findViewById(R.id.drawer_layout); } public void ClickMenu(View view) { openDrawer(drawerLayout); } public static void openDrawer(DrawerLayout drawerLayout) { drawerLayout.openDrawer(GravityCompat.START); } public void ClickLogo(View view) { closeDrawer(drawerLayout); } public static void closeDrawer(DrawerLayout drawerLayout) { if(drawerLayout.isDrawerOpen(GravityCompat.START)) { drawerLayout.closeDrawer(GravityCompat.START); } } public void ClickHome(View view) { recreate(); } public void ClickGoals(View view) { redirectActivity(this,Goals.class); } public void ClickFavourites(View view) { redirectActivity(this,FavouritePage.class); } public void ClickSettings(View view) { redirectActivity(this,AccountSettings.class); } public void ClickLogout(View view) { logout(this); } public static void logout(Activity activity) { AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle("Log out"); builder.setMessage("Are you sure you want to log out?"); builder.setPositiveButton("YES", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { activity.finishAffinity(); System.exit(0); } }); builder.setNegativeButton("NO", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.show(); } public static void redirectActivity(Activity activity, Class aClass) { Intent intent = new Intent(activity,aClass); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(intent); } @Override protected void onPause() { super.onPause(); closeDrawer(drawerLayout); } private void getCurrentLocation() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } Task<Location> task = fusedLocationProviderClient.getLastLocation(); task.addOnSuccessListener(new OnSuccessListener<Location>() { @Override public void onSuccess(Location location) { if(location != null) { currentLat = location.getLatitude(); currentLong = location.getLongitude(); supportMapFragment.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(@NonNull GoogleMap googleMap) { map = googleMap; map.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(currentLat,currentLong), 10 )); } }); } } }); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 44) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { getCurrentLocation(); } } } @Override public void onMapReady(@NonNull GoogleMap googleMap) { map = googleMap; map.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(currentLat,currentLong), 15 )); } private class PlaceTask extends AsyncTask<String,Integer,String>{ @Override protected String doInBackground(String... strings) { String data = null; try { data = downloadUrl(strings[0]); } catch (IOException e) { e.printStackTrace(); } return data; } @Override protected void onPostExecute(String s) { new ParserTask().execute(s); } } private String downloadUrl(String string) throws IOException { URL url = new URL(string); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.connect(); InputStream stream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuilder builder = new StringBuilder(); String line = ""; while ((line = reader.readLine()) != null){ builder.append(line); } String data = builder.toString(); reader.close(); return data; } private class ParserTask extends AsyncTask<String,Integer,List<HashMap<String,String>>> { @Override protected List<HashMap<String,String>> doInBackground(String... strings) { JsonParser jsonParser = new JsonParser(); List<HashMap<String,String>> mapList = null; JSONObject object = null ; try { object = new JSONObject(strings[0]); mapList = jsonParser.parseResult(object); } catch (JSONException e) { e.printStackTrace(); } return mapList; } @Override protected void onPostExecute(List<HashMap<String, String>> hashMaps) { for (int i=0; i<hashMaps.size();i++) { HashMap<String,String> hashMapList = hashMaps.get(i); double lat = Double.parseDouble(hashMapList.get("lat")); double lng = Double.parseDouble((hashMapList.get("lng"))); String name = hashMapList.get("name"); LatLng latLng = new LatLng(lat,lng); MarkerOptions options = new MarkerOptions(); options.position(latLng); options.title(name); map.addMarker(options); } } } }
问题修复方案
1. 地标类型设置失效问题
Google Places API的types参数要求使用小写的类型标识符(如"bank"),但当前代码使用了显示名称(如"Bank")。修改按钮点击事件中的URL拼接逻辑:
// 原代码 "&types=" + TypeOfPlace[i] + // 修改为 "&types=" + PlaceName[i] +
PlaceName数组存储的是符合API要求的小写类型值,替换后即可正确请求对应类型的地标。
2. 地图不自动聚焦当前位置问题
- 模拟器位置设置:新AVD默认无模拟位置,打开模拟器的"Extended controls"(三点图标)→ "Location",输入经纬度或选择预设位置,点击"Set location"。
- 调整地图与位置初始化顺序:先初始化地图,再获取位置更新相机,避免因地图未初始化导致缩放失效:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_landin_page); // ... 其他初始化代码 ... // 先初始化地图 supportMapFragment.getMapAsync(this); // 再获取位置 fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { getCurrentLocation(); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 44); } } // 修改getCurrentLocation中的地图更新逻辑 private void getCurrentLocation() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } Task<Location> task = fusedLocationProviderClient.getLastLocation(); task.addOnSuccessListener(new OnSuccessListener<Location>() { @Override public void onSuccess(Location location) { if(location != null && map != null) { currentLat = location.getLatitude(); currentLong = location.getLongitude(); // 使用已初始化的map对象直接更新相机 map.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(currentLat,currentLong), 15 )); } } }); } - 处理LastLocation为空的情况:新模拟器可能无位置历史,
getLastLocation会返回null,需添加实时位置请求逻辑:// 添加依赖(build.gradle) implementation 'com.google.android.gms:play-services-location:21.0.1' // 在LandinPage中添加LocationCallback private LocationCallback locationCallback = new LocationCallback() { @Override public void onLocationResult(@NonNull LocationResult locationResult) { super.onLocationResult(locationResult); if (locationResult.getLastLocation() != null && map != null) { Location location = locationResult.getLastLocation(); currentLat = location.getLatitude(); currentLong = location.getLongitude(); map.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(currentLat, currentLong), 15 )); // 获取到位置后停止请求 fusedLocationProviderClient.removeLocationUpdates(this); } } }; // 修改getCurrentLocation方法 private void getCurrentLocation() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { return; } Task<Location> task = fusedLocationProviderClient.getLastLocation(); task.addOnSuccessListener(new OnSuccessListener<Location>() { @Override public void onSuccess(Location location) { if(location != null && map != null) { currentLat = location.getLatitude(); currentLong = location.getLongitude(); map.animateCamera(CameraUpdateFactory.newLatLngZoom( new LatLng(currentLat,currentLong), 15 )); } else { // LastLocation为空,请求实时位置 LocationRequest locationRequest = LocationRequest.create(); locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(1000); fusedLocationProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper()); } } }); }
3. "set_timerslack_ns write failed"错误
该错误是Android 11+模拟器的系统级警告,通常不影响应用功能,可通过以下方式缓解:
- 将模拟器系统版本降级到Android
相关产品推荐
相关产品推荐

