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

Android中AppDatabase初始化后仍为空,调用Dao方法报空指针异常

问题描述

我正在开发一款获取设备位置并存储到数据库的Android应用,已在MainActivity的onCreate()方法中实例化并初始化AppDatabase,但调用LocationDao方法时,始终抛出错误:Attempt to invoke virtual method 'com.example.locator.Interfaces.LocationDao com.example.locator.AppDatabase.locationDao()' on a null object reference。问题发生在onLocationChanged方法中调用appDatabase.locationDao().insert(position)时,相关实现代码如下:

public class MainActivity extends AppCompatActivity implements LocationListener {

    ActivityMainBinding binding;
    AppDatabase appDatabase;
    private Handler handler;
    List<String> newPermissions;

    private LocationManager locationManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding=ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        appDatabase=AppDatabase.getDbIntance(this);
        newPermissions = new ArrayList<>(Arrays.asList(android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.RECEIVE_SMS,
                android.Manifest.permission.READ_SMS, android.Manifest.permission.SEND_SMS,
                android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_COARSE_LOCATION,
                android.Manifest.permission.READ_PHONE_STATE, Manifest.permission.CAMERA));
        if(Build.VERSION.SDK_INT > Build.VERSION_CODES.P) newPermissions.add(Manifest.permission.FOREGROUND_SERVICE);

        if(!checkPermission(this, newPermissions)){
            ActivityCompat.requestPermissions(this, newPermissions.toArray(new String[]{}), 200);
        }

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        // Request location updates
        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) {
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, new MainActivity());

        handler = new Handler();

        // Define the code block to be executed
        Runnable runnable = new Runnable() {
            @SuppressLint("SetTextI18n")
            @Override
            public void run() {
                Log.d("TAG", "run: " + "run every 30s");

                if(appDatabase!=null){
                    if(appDatabase.locationDao().getAll()!=null){
                        MainActivity.this.runOnUiThread(() -> appDatabase.locationDao().getAll().observe(MainActivity.this, locations -> {

                            Collections.reverse(locations);
                            if(locations.size()>0){
                                binding.Longitude.setText("Longitude : "+locations.get(0).getLongitude());
                                binding.Latitude.setText("Latitude : "+locations.get(0).getLatitude());
                                binding.Altitude.setText("Altitude : "+locations.get(0).getAltitude());
                                binding.Accuracy.setText("Accuracy : "+locations.get(0).getAccuracy());
                                binding.send.setVisibility(View.VISIBLE);
                            }


                        }));
                        binding.send.setOnClickListener(v->{});
                    }

                }

                // Repeat every 30 seconds
                handler.postDelayed(this, 30000L);
            }
        };
        handler.post(runnable);

    }

    @Override
    public void onLocationChanged(@NonNull Location location) {
        Log.d("TAG", "onLocationChanged: checking .... ");
        if(location.getAccuracy()<=5f){
            GpsLocation position=new GpsLocation();
            if(position!=null){
                Log.d("TAG", "onLocationChanged: accuracy <=5");
                double latitude = location.getLatitude();
                position.setLatitude(latitude);
                double longitude = location.getLongitude();
                position.setLongitude(longitude);
                double altitude=location.getAltitude();
                position.setAltitude(altitude);
                float accuracy=location.getAccuracy();
                position.setAccuracy(accuracy);
                //TODO: send message with positions
            }else{
                Log.d("TAG", "onLocationChanged: position is null");
            }

        }else{
            GpsLocation position=new GpsLocation();
            if(position!=null){
                Log.d("TAG", "onLocationChanged: accuracy >=5");
                double latitude = location.getLatitude();
                position.setLatitude(latitude);
                double longitude = location.getLongitude();
                position.setLongitude(longitude);
                double altitude=location.getAltitude();
                position.setAltitude(altitude);
                float accuracy=location.getAccuracy();
                position.setAccuracy(accuracy);
                appDatabase.locationDao().insert(position);//错误发生位置
            }else{
                Log.d("TAG", "onLocationChanged: position is null");

            }


        }

    }

    @Override
    public void onProviderEnabled(@NonNull String provider) {
        LocationListener.super.onProviderEnabled(provider);
    }

    @Override
    public void onProviderDisabled(@NonNull String provider) {
        LocationListener.super.onProviderDisabled(provider);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        if(requestCode == 200){
            for(int g : grantResults){
                if(g != PackageManager.PERMISSION_GRANTED){
                    Toast.makeText(this, "Permission non accorde", Toast.LENGTH_SHORT).show();
                    return;
                }
            }
        }
    }


    private boolean checkPermission(Context context, List<String> permissions){
        for(String p : permissions){
            if (ContextCompat.checkSelfPermission(context, p) != PackageManager.PERMISSION_GRANTED) return false;
        }
        return true;
    }
}

// AppDatabase类
@Database(entities = {GpsLocation.class} , version =2)
public abstract  class AppDatabase extends RoomDatabase {

    public abstract LocationDao locationDao();
    public static AppDatabase instance;

    public static AppDatabase  getDbIntance(Context c){
        if (instance ==null){
            instance = Room.databaseBuilder(c.getApplicationContext() , AppDatabase.class , "LocationDb" )
                    .fallbackToDestructiveMigration()
                    .allowMainThreadQueries()
                    .build();
        }
        return instance;
    }
}
问题原因与修复方案

核心原因

你在调用locationManager.requestLocationUpdates时,传入的参数是new MainActivity(),这会创建一个全新的MainActivity实例——这个新实例的appDatabase字段从未被初始化,所以当它的onLocationChanged方法被触发时,就会抛出空指针异常。

修复步骤

  1. 替换位置更新监听器
    将locationManager.requestLocationUpdates的最后一个参数从new MainActivity()改为this,因为当前MainActivity已经实现了LocationListener接口,直接传入自身即可:

    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
    
  2. 补全权限申请后的位置注册逻辑
    当前代码中如果权限未通过,onCreate会直接return,导致位置更新未被注册。需要在onRequestPermissionsResult中,当所有权限通过后补注册位置更新:

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    
        if(requestCode == 200){
            boolean allGranted = true;
            for(int g : grantResults){
                if(g != PackageManager.PERMISSION_GRANTED){
                    Toast.makeText(this, "权限未授予", Toast.LENGTH_SHORT).show();
                    allGranted = false;
                    break;
                }
            }
            // 所有权限通过后注册位置更新
            if(allGranted){
                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) {
                    locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
                }
            }
        }
    }
    

额外优化建议

  • 你启用了allowMainThreadQueries(),这会让数据库操作在主线程执行,容易引发ANR(应用无响应)。建议改用协程或其他异步方式执行数据库操作。
  • onLocationChanged方法的两个分支代码高度重复,可以提取为公共方法减少冗余。

内容的提问来源于stack exchange,提问作者Patrick Renaud

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 13:03:32