调用FusedLocationProviderClient.getLastLocation()时空指针崩溃求助
崩溃原因
报错java.lang.NullPointerException: 尝试对空对象引用调用虚拟方法 'com.google.android.gms.tasks.Task com.google.android.gms.location.FusedLocationProviderClient.getLastLocation()',核心原因是fusedLocationClient对象未完成初始化,处于null状态时调用了它的方法。
导致初始化失败的直接原因:MyFirebaseMessagingService中的onCreate方法使用了protected修饰符,而Service类的onCreate方法是public的,系统无法正确触发这个方法,导致fusedLocationClient = LocationServices.getFusedLocationProviderClient(...)这行代码从未执行。
另外,代码中sharedPref也未初始化,后续调用sharedPref.getString()也会触发空指针异常,需要一并修复。
修复步骤
1. 修正Service生命周期方法的修饰符并完成初始化
将onCreate方法的修饰符改为public,同时在该方法中完成fusedLocationClient和sharedPref的初始化:
@Override public void onCreate() { super.onCreate(); fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); sharedPref = getSharedPreferences("sendnow_prefs", Context.MODE_PRIVATE); }
注意:必须添加
@Override注解确保重写父类方法,同时调用super.onCreate()保证Service的正常初始化流程。
2. 将网络请求移至后台线程
handleNow方法中的HttpURLConnection网络请求不能在主线程执行(Android 3.0+禁止),需要将这部分逻辑放到子线程中:
if (location != null) { // 其他获取数据的逻辑不变 new Thread(new Runnable() { @Override public void run() { try { URL url = new URL(urlString); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setDoOutput(true); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8")); writer.write(params); writer.flush(); writer.close(); // 获取响应码,判断请求是否成功 int responseCode = urlConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { Log.d(TAG, "位置数据发送成功"); } else { Log.e(TAG, "位置数据发送失败,响应码:" + responseCode); } urlConnection.disconnect(); } catch (Exception e) { Log.e(TAG, "网络请求异常:", e); } } }).start(); }
3. 权限处理优化
当前代码中仅判断权限是否存在,若无权限直接返回。可以考虑在权限缺失时,记录日志提示用户开启权限,或者通过广播通知前端页面发起权限请求。
完整修改后的核心代码片段
public class MyFirebaseMessagingService extends FirebaseMessagingService { private SharedPreferences sharedPref; private static final String TAG = "MyFirebaseMsgService"; private FusedLocationProviderClient fusedLocationClient; @Override public void onCreate() { super.onCreate(); fusedLocationClient = LocationServices.getFusedLocationProviderClient(this); sharedPref = getSharedPreferences("sendnow_prefs", Context.MODE_PRIVATE); } private void handleNow() { Log.d(TAG, "Short lived task is done."); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { Log.w(TAG, "位置权限未授予,无法获取位置"); return; } fusedLocationClient.getLastLocation() .addOnSuccessListener(new OnSuccessListener<Location>() { @Override public void onSuccess(Location location) { if (location != null) { boolean isCharging = MyFirebaseMessagingService.getCharging(getApplicationContext()); float batteryLevel = MyFirebaseMessagingService.getBatteryLevel(getApplicationContext()); String username = sharedPref.getString("sendnow_username", "nativestorage_null"); String userId = sharedPref.getString("sendnow_user_id", "nativestorage_null"); String licenseholderId = sharedPref.getString("sendnow_licenseholder_id", "nativestorage_null"); String urlString = "URL"; // 替换为实际服务器地址 String params = "username=" + username + "&user_id=" + userId + "&licenseholder_id=" + licenseholderId + "&altitude=" + location.getAltitude() + "&speed=" + location.getSpeed() + "&location=" + location.getLatitude() + "," + location.getLongitude() + "&lastGpsUpdate=" + location.getTime() + "&charging=" + isCharging + "&batteryLevel=" + batteryLevel; new Thread(new Runnable() { @Override public void run() { try { URL url = new URL(urlString); HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setDoOutput(true); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8")); writer.write(params); writer.flush(); writer.close(); int responseCode = urlConnection.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK) { Log.d(TAG, "位置数据发送成功"); } else { Log.e(TAG, "发送失败,响应码:" + responseCode); } urlConnection.disconnect(); } catch (Exception e) { Log.e(TAG, "网络请求出错:", e); } } }).start(); } else { Log.w(TAG, "获取到的位置为null"); } } }); } }
内容的提问来源于stack exchange,提问作者Calvin

