简体   繁体   中英

Cannot observe null data - MVVM with Livedata

I've create simple app using MVVM pattern with LiveData to observe data. The list I display is displayed in a fragment. Everything seems okay to me, as I compared my code to other my samples which work and I found nothing to be wrong.

When activity is started, I swap fragments and in onActivityCreated in line mViewModel.getAllShops().observe(this, new Observer<List<Shop>>() { //<--error I get following error:

 java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' on a null object reference 

my schema is:
- Entity - Shop.class
- Dao - ShopDao.class
- Reposityory - ShopRepository.class
- ViewModel - ShopListViewModel
- Fragment which displays data in RecyclerView - ShopList.java

Shop.class:

@Entity(tableName = "shops")
public class Shop {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    public int id;

    @ColumnInfo(name = "shop_name")
    public String shopName;

    @ColumnInfo(name = "shop_description")
    public String shopDescription;

    @ColumnInfo(name = "radius")
    public int radius;

    @ColumnInfo(name = "latitude")
    public String latitude;

    @ColumnInfo(name = "longitude")
    public String longitude;

    @ColumnInfo(name = "isFavourite")
    public int isFavouriteShop;

    public int getId() {
        return id;
    }

    public String getShopName() {
        return shopName;
    }

    public String getShopDescription() {
        return shopDescription;
    }

    public int getRadius() {
        return radius;
    }

    public String getLatitude() {
        return latitude;
    }

    public String getLongitude() {
        return longitude;
    }

    public int getIsFavouriteShop() {
        return isFavouriteShop;
    }



    @Ignore
    public Shop(String shopName, String shopDescription, int radius, String latitude, String longitude, int isFavouriteShop) {
        this.shopName = shopName;
        this.shopDescription = shopDescription;
        this.radius = radius;
        this.latitude = latitude;
        this.longitude = longitude;
        this.isFavouriteShop = isFavouriteShop;
    }

    public Shop(int id, String shopName, String shopDescription, int radius, String latitude, String longitude, int isFavouriteShop) {
        this.id = id;
        this.shopName = shopName;
        this.shopDescription = shopDescription;
        this.radius = radius;
        this.latitude = latitude;
        this.longitude = longitude;
        this.isFavouriteShop = isFavouriteShop;
    }
}

ShopDao.class:

@Dao
public interface ShopDao {

    @Query("SELECT * FROM shops")
    LiveData<List<Shop>> getAllShops();
}

Repository:

public class ShopRepository {

    private ShopDao dao;
    private LiveData<List<Shop>> mAllShops;

    public ShopRepository(Application application){
        dao = ShopDatabase.getInstance(application).dao();
        mAllShops = dao.getAllShops();
    }

    public LiveData<List<Shop>> getAllShops() {
        return mAllShops;
    }

ViewModel:

public class ShopListViewModel extends ViewModel {


    private LiveData<List<Shop>> mAllShops;
    private ShopRepository mRepository;

    public ShopListViewModel(Application application) {
        mRepository = new ShopRepository(application);
        mAllShops = mRepository.getAllShops();

    }

    public ShopListViewModel() {
    }

    public LiveData<List<Shop>> getAllShops() {
        return mAllShops;
    }
}

called from fragment from onActivityCreated :

@Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mViewModel = ViewModelProviders.of(this).get(ShopListViewModel.class);
        mViewModel.getAllShops().observe(this, new Observer<List<Shop>>() { //<--error
            @Override
            public void onChanged(List<Shop> shops) {
                adapter.setList(shops);
            }
        });
        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerView.setAdapter(adapter);
    }

plus database:

@Database(entities = {Shop.class}, version = 1, exportSchema = false)
public abstract class ShopDatabase extends RoomDatabase {

    public abstract ShopDao dao();

    private static volatile ShopDatabase INSTANCE;

    public static ShopDatabase getInstance(final Context context){
        if (INSTANCE == null){
            synchronized (ShopDatabase.class){
                if (INSTANCE == null){
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
                            ShopDatabase.class,
                            "shop_database.db")
                            .build();
                }
            }
        }
        return INSTANCE;
    }

}

My gradle dependencies:

    implementation 'androidx.room:room-runtime:2.1.0-alpha03'
    annotationProcessor 'androidx.room:room-compiler:2.1.0-alpha03'

    // ViewModel and LiveData
    implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0-alpha01'
    annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.1.0-alpha01'

My project is migrated to Android X so I used those.

I can add items to database with any problem, they are saved and avaible.

Can anyone of you see any mystake I have done?
Thanks in advance!

The mAllShops variable is initialized in the constructor which takes in a parameter of type Application . But that constructor is never called. When you get your ViewModel in your Fragment , it by default calls the parameterless constructor. To get it to call your parameterized constructor, you need to create a ViewModelProvider.Factory .

Try reading the "ViewModel with non-default constructor" section of this

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM