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