You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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上下文环境不存在,必然触发空指针异常。

另外代码还有两个隐藏问题:

  1. mFusedLocationClient未初始化,调用getLastLocation()会触发二次空指针
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:10:15