Android定位应用测试崩溃:空指针异常问题求助
定位功能开发中的空指针异常解决方案
问题现象
执行mainTest(ru.myitschool.lab23.InstrumentedTestGeo)时进程崩溃,抛出空指针异常:
java.lang.NullPointerException: 尝试在空对象引用上调用虚拟方法'android.content.pm.ApplicationInfo android.content.Context.getApplicationInfo()'
完整错误调用栈:
at android.content.ContextWrapper.getApplicationInfo(ContextWrapper.java:190) at android.view.ContextThemeWrapper.getTheme(ContextThemeWrapper.java:174) at android.content.Context.obtainStyledAttributes(Context.java:809) at androidx.appcompat.app.AppCompatDelegateImpl.createSubDecor(AppCompatDelegateImpl.java:852) at androidx.appcompat.app.AppCompatDelegateImpl.ensureSubDecor(AppCompatDelegateImpl.java:819) at androidx.appcompat.app.AppCompatDelegateImpl.findViewById(AppCompatDelegateImpl.java:640) at androidx.appcompat.app.AppCompatActivity.findViewById(AppCompatActivity.java:261) at ru.myitschool.lab23.MainActivity.<init>(MainActivity.java:26) at java.lang.Class.newInstance(Native Method) at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95) at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45) at android.app.Instrumentation.newActivity(Instrumentation.java:1273) at androidx.test.runner.MonitoringInstrumentation.newActivity(MonitoringInstrumentation.java:866) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3901) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4201) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2438) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:226) at android.os.Looper.loop(Looper.java:313) at android.app.ActivityThread.main(ActivityThread.java:8669) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
原MainActivity代码
import android.annotation.SuppressLint; import android.content.pm.PackageManager; import android.location.Address; import android.os.Bundle; import android.view.View; import android.widget.TextView; import android.location.Geocoder; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; import java.io.IOException; import java.util.List; import java.util.Locale; public class MainActivity extends AppCompatActivity { private FusedLocationProviderClient mFusedLocationClient; TextView text_longitude = findViewById(R.id.text_longitude), text_accuracy = findViewById(R.id.text_accuracy), text_address = findViewById(R.id.text_address); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @SuppressLint("Range") public void getLoc(View v) { if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // TODO: Consider calling // ActivityCompat#requestPermissions // here to request the missing permissions, and then overriding // public void onRequestPermissionsResult(int requestCode, String[] permissions, // int[] grantResults) // to handle the case where the user grants the permission. See the documentation // for ActivityCompat#requestPermissions for more details. return; } mFusedLocationClient.getLastLocation().addOnSuccessListener(this, location -> { if (location != null) { text_longitude.setText(String.valueOf(location.getLatitude())); text_accuracy.setText(String.valueOf(location.getAccuracy())); Geocoder geocoder = new Geocoder(this, Locale.getDefault()); try { text_address.setText((CharSequence) geocoder.getFromLocation(location.getLatitude(), location.getAccuracy(), 1)); } catch (IOException e) { e.printStackTrace(); } } }); } }
问题根源
在成员变量初始化阶段直接调用findViewById()是错误的:此时Activity的Context还未完成初始化,findViewById()依赖的Activity上下文环境不存在,必然触发空指针异常。
另外代码还有两个隐藏问题:
mFusedLocationClient未初始化,调用getLastLocation()会触发二次空指针- Geocoder调用错误:
getFromLocation()第二个参数应该是经度,而非精度,且返回的是List<Address>,不能直接强转为CharSequence
修正后的代码
import android.annotation.SuppressLint; import android.content.pm.PackageManager; import android.location.Address; import android.location.Geocoder; import android.os.Bundle; import android.view.View; import android.widget.TextView; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.LocationServices; import java.io.IOException; import java.util.List; import java.util.Locale; public class MainActivity extends AppCompatActivity { private FusedLocationProviderClient mFusedLocationClient; // 先声明成员变量,不初始化 private TextView text_longitude; private TextView text_accuracy; private TextView text_address; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 在setContentView之后初始化View,此时Context已就绪 text_longitude = findViewById(R.id.text_longitude); text_accuracy = findViewById(R.id.text_accuracy); text_address = findViewById(R.id.text_address); // 初始化FusedLocationProviderClient mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); } @SuppressLint("MissingPermission") public void getLoc(View v) { // 检查权限 if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // 触发权限申请 ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, 1001); return; } mFusedLocationClient.getLastLocation().addOnSuccessListener(this, location -> { if (location != null) { // 显示纬度(可根据需求调整变量命名) text_longitude.setText(String.format(Locale.getDefault(), "纬度: %.6f", location.getLatitude())); text_accuracy.setText(String.format(Locale.getDefault(), "精度: %.2f米", location.getAccuracy())); Geocoder geocoder = new Geocoder(this, Locale.getDefault()); try { // 正确传递经纬度参数 List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1); if (!addresses.isEmpty()) { Address address = addresses.get(0); // 拼接详细地址 StringBuilder addressStr = new StringBuilder(); for (int i = 0; i <= address.getMaxAddressLineIndex(); i++) { addressStr.append(address.getAddressLine(i)).append("\n"); } text_address.setText(addressStr.toString()); } else { text_address.setText("未获取到地址信息"); } } catch (IOException e) { e.printStackTrace(); text_address.setText("地址解析失败"); } } else { text_longitude.setText("未获取到位置信息"); } }); } // 处理权限申请结果 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == 1001) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限获取成功,重新调用定位方法 getLoc(findViewById(R.id.your_button_id)); // 替换成你的按钮实际ID } else { text_longitude.setText("定位权限被拒绝"); } } } }
关键修正点
- 将TextView的初始化移至
onCreate()方法中setContentView()之后,确保Context已初始化 - 初始化
mFusedLocationClient,避免空指针 - 修正Geocoder的调用参数,正确处理地址结果
- 添加权限申请逻辑,完善权限处理流程
内容的提问来源于stack exchange,提问作者Foogles super
相关产品推荐
相关产品推荐

