Подписка на LiveData приводит к нулю после попытки извлечь объект из базы данных Room - PullRequest
0 голосов
/ 26 мая 2018

Я пишу приложение Medicine Reminder, в котором сущность лекарства хранится в базе данных с использованием Room API.Поток приложения выглядит так:

1) Активность с DrawerLayout, поэтому она состоит из NavigationView для Drawer и LinearView для панели инструментов и фрагмента.

2) Фрагмент # 1 (TopFragment - это ListFragment) - есть два варианта.Нажмите на первый элемент, чтобы перейти ко второму фрагменту - MedicineListFragment.

3) MedicineListFragment извлекает все лекарства из БД и отображает их с помощью RecyclerView - все работает.

4) Нажатие на элемент - вэлемент представления переработчика - следует создать намерение, которое создает новое действие MedicineDetailsActivity.Идентификатор медицины выбранного элемента передается намерению в реализации RecylcerViewAdapter.

@Override
public void onBindViewHolder(@NonNull MedicineRecyclerViewAdapter.ViewHolder holder, final int position) {
    final Medicine item = medicines.get(position);

    holder.itemNameView.setText(item.getName());
    holder.itemDescriptionView.setText(item.getDescription());
    holder.itemContainer.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(context, MedicineDetailsActivity.class);
            intent.putExtra(MedicineDetailsActivity.EXTRA_MEDICINE, item.getId());
            context.startActivity(intent);
        }
    });
}

5) Следующим шагом должно быть отображение сведений о лекарстве, но подписка на Observer из ViewModel возвращает ноль вместо одного лекарства.Что странно, если я отлаживаю и устанавливаю точку останова перед вызовом метода .observer, лекарство возвращается!

public class MedicineViewModel extends AndroidViewModel {

private AppDatabase db;

public MedicineViewModel(Application application) {
    super(application);
    createDb();
}

public LiveData<List<Medicine>> findAllBooks() {
    return db.medicineModel().findAllMedicine();
}

public LiveData<Medicine> findMedicineById(int id) {
    return db.medicineModel().findMedicineById(id);
}

private void createDb() {
    db = AppDatabase.getInMemoryDatabase(this.getApplication());
    DatabaseInitializer.populateAsync(db);
}

}

И это MedicineDetailsActivity

public class MedicineDetailsActivity extends AppCompatActivity {

public static final String EXTRA_MEDICINE = "EXTRA_MEDICINE";
private MedicineViewModel medicineViewModel;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_medicine_details);

    medicineViewModel = ViewModelProviders.of(this).get(MedicineViewModel.class);
    subscribeMedicine();
}

private void subscribeMedicine() {
    Intent intent = getIntent();
    int medicineId = intent.getExtras().getInt(EXTRA_MEDICINE);

    medicineViewModel.findMedicineById(medicineId).observe(this, new Observer<Medicine>() {
        @Override
        public void onChanged(@NonNull Medicine medicine) {
            showUI(medicine);
        }
    });
}

private void showUI(Medicine medicine) {
    TextView medicineName = findViewById(R.id.medicine_details_name);
    medicineName.setText(medicine.getName());
    TextView medicineDescription = findViewById(R.id.medicine_details_description);
    medicineDescription.setText(medicine.getDescription());
}

}

05-26 09:10:20.258 9482-9482/com.project.medicinereminder I/System.out: Sending WAIT chunk
05-26 09:10:21.282 9482-9489/com.project.medicinereminder I/art: Debugger is active
05-26 09:10:21.460 9482-9482/com.project.medicinereminder I/System.out: Debugger has connected waiting for debugger to settle...
05-26 09:10:21.661 9482-9482/com.project.medicinereminder I/System.out: waiting for debugger to settle...
05-26 09:10:21.863 9482-9482/com.project.medicinereminder I/System.out: waiting for debugger to settle...
05-26 09:10:22.064 9482-9482/com.project.medicinereminder I/System.out: waiting for debugger to settle...
05-26 09:10:22.265 9482-9482/com.project.medicinereminder I/System.out:  waiting for debugger to settle...
05-26 09:10:22.465 9482-9482/com.project.medicinereminder I/System.out: waiting for debugger to settle...
05-26 09:10:22.666 9482-9482/com.project.medicinereminder I/System.out:waiting for debugger to settle...
05-26 09:10:22.866 9482-9482/com.project.medicinereminder I/System.out: debugger has settled (1492)
05-26 09:10:23.395 9482-9482/com.project.medicinereminder W/System: ClassLoader referenced unknown path: /data/app/com.project.medicinereminder-1/lib/arm64
05-26 09:10:23.416 9482-9482/com.project.medicinereminder I/InstantRun: starting instant run server: is main process
05-26 09:10:23.463 9482-9482/com.project.medicinereminder I/HwCust: Constructor found for class android.app.HwCustActivityImpl
05-26 09:10:23.524 9482-9482/com.project.medicinereminder W/art: Before Android 4.1, method android.graphics.PorterDuffColorFilter android.support.graphics.drawable.VectorDrawableCompat.updateTintFilter(android.graphics.PorterDuffColorFilter, android.content.res.ColorStateList, android.graphics.PorterDuff$Mode) would have incorrectly overridden the package-private method in android.graphics.drawable.Drawable
05-26 09:10:23.826 9482-9482/com.project.medicinereminder I/HwSecImmHelper: mSecurityInputMethodService is null
05-26 09:10:23.832 9482-9482/com.project.medicinereminder I/HwPointEventFilter: do not support AFT because of no config
05-26 09:10:23.892 9482-9511/com.project.medicinereminder I/OpenGLRenderer: Initialized EGL, version 1.4
05-26 09:10:23.902 9482-9511/com.project.medicinereminder W/linker: /vendor/lib64/libhwuibp.so: unused DT entry: type 0xf arg 0xe3a
05-26 09:10:24.002 9482-9482/com.project.medicinereminder W/art: Before Android 4.1, method int android.support.v7.widget.DropDownListView.lookForSelectablePosition(int, boolean) would have incorrectly overridden the package-private method in android.widget.ListView
05-26 09:10:24.253 9482-9487/com.project.medicinereminder I/art: Do partial code cache collection, code=29KB, data=29KB
05-26 09:10:24.254 9482-9487/com.project.medicinereminder I/art: After code cache collection, code=29KB, data=29KB Increasing code cache capacity to 128KB
05-26 09:10:33.236 9482-9482/com.project.medicinereminder I/hwaps: JNI_OnLoad
05-26 09:10:33.559 9482-9487/com.project.medicinereminder I/art: Do partial code cache collection, code=51KB, data=56KB
05-26 09:10:33.560 9482-9487/com.project.medicinereminder I/art: After code cache collection, code=50KB, data=55KB Increasing code cache capacity to 256KB
05-26 09:10:33.750 9482-9487/com.project.medicinereminder I/art: Compiler allocated 7MB to compile void android.widget.TextView.<init> (android.content.Context, android.util.AttributeSet, int, int)
05-26 09:10:47.687 9482-9489/com.project.medicinereminder I/art: Starting a blocking GC Instrumentation
05-26 09:10:47.728 9482-9487/com.project.medicinereminder I/art: Do full code cache collection, code=123KB, data=118KB
05-26 09:10:47.729 9482-9487/com.project.medicinereminder I/art: After code cache collection, code=120KB, data=92KB
05-26 09:10:47.783 9482-9482/com.project.medicinereminder I/HwPointEventFilter: do not support AFT because of no config
05-26 09:10:49.733 9482-9482/com.project.medicinereminder E/AndroidRuntime: 
FATAL EXCEPTION: main
Process: com.project.medicinereminder, PID: 9482
java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.project.medicinereminder.database.Medicine.name' on a null object reference
    at com.project.medicinereminder.MedicineDetailsActivity.showUI(MedicineDetailsActivity.java:44)
    at com.project.medicinereminder.MedicineDetailsActivity.access$000(MedicineDetailsActivity.java:16)
    at com.project.medicinereminder.MedicineDetailsActivity$1.onChanged(MedicineDetailsActivity.java:37)
    at com.project.medicinereminder.MedicineDetailsActivity$1.onChanged(MedicineDetailsActivity.java:34)
    at android.arch.lifecycle.LiveData.considerNotify(LiveData.java:109)
    at android.arch.lifecycle.LiveData.dispatchingValue(LiveData.java:126)
    at android.arch.lifecycle.LiveData.setValue(LiveData.java:282)
    at android.arch.lifecycle.LiveData$1.run(LiveData.java:87)
    at android.os.Handler.handleCallback(Handler.java:761)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:156)
    at android.app.ActivityThread.main(ActivityThread.java:6623)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
05-26 09:10:49.749 9482-9482/com.project.medicinereminder I/Process: Sending signal. PID: 9482 SIG: 9

Я могу, конечно, поставить Parcerable или Serializable на намерение (я пробовал со вторым - он работает), но я хочу сделать это, используя вышеупомянутый способ.Пожалуйста, помогите!

1 Ответ

0 голосов
/ 26 мая 2018

Проблема решена.Спасибо @ pskink

После учебника о Room API (https://codelabs.developers.google.com/codelabs/android-persistence/#0) перед добавлением данных в in memory database, каждый раз, когда я инициализировал MedicineViewModel, я заполнял базу данных тестовыми данными. Но простодо этого был выполнен метод delete в базе данных.

Из-за асинхронной операции база данных еще не была заполнена при создании MedicineDetailsActivity.

После удаления метода delete из populateметод, где были добавлены записи медицины, все работает правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...