【问题标题】:Android LiveData Observer not being triggered second timeAndroid LiveData Observer 没有被第二次触发
【发布时间】:2018-09-01 23:12:35
【问题描述】:

我正在开展一项允许用户过滤其搜索结果的活动。 最初,我获取所有数据,但是当用户想要过滤它时,我需要调用另一个查询并更新视图。我为此使用 Android ROOM 和 ViewModel。

问题在于,每次获取新数据时,我都需要创建一个新的观察者,因为旧的观察者“停止”启动。通常,这应该与一个观察者一起工作,每次更新数据时都会调用它。你能帮我理解为什么会这样吗?

活动:

package com.jds.fitnessjunkiess.getfitapp.Activities.ExercisesView;

import android.arch.lifecycle.ViewModelProviders;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;

import com.jds.fitnessjunkiess.getfitapp.Activities.ExercisesView.Adapters.ExercisesAdapter;
import com.jds.fitnessjunkiess.getfitapp.Data.ViewModels.ExerciseViewModel;
import com.jds.fitnessjunkiess.getfitapp.R;

public class ExercisesViewActivity extends AppCompatActivity implements View.OnClickListener {

  private ExerciseViewModel exerciseViewModel;
  private ExercisesAdapter recyclerViewerAdapter;

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

    Toolbar toolbar = findViewById(R.id.toolbar_exercise_view_activity);
    toolbar.setTitle("Exercises");
    setSupportActionBar(toolbar);

    ActionBar actionBar = getSupportActionBar();
    if (actionBar != null) {
      actionBar.setDisplayHomeAsUpEnabled(true);
      actionBar.setDisplayShowHomeEnabled(true);
    }

    RecyclerView recyclerView = findViewById(R.id.exercise_view_recycle_viewer);
    RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
    recyclerView.setLayoutManager(layoutManager);
    this.recyclerViewerAdapter = new ExercisesAdapter();
    recyclerView.setAdapter(recyclerViewerAdapter);

    this.exerciseViewModel = ViewModelProviders.of(this).get(ExerciseViewModel.class);
    this.exerciseViewModel.setFilters("", "");
//    this.exerciseViewModel.selectAll();
    this.exerciseViewModel.select().observe(this, exercises -> {
      if (exercises != null) {
        this.recyclerViewerAdapter.updateDataset(exercises);
      }
    });

    Button button = findViewById(R.id.test_button);
    button.setOnClickListener(this);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
      case android.R.id.home:
        onBackPressed();
        break;
    }

    return true;
  }

  @Override
  public void onClick(View v) {
    this.exerciseViewModel.setFilters("", "");
//    this.exerciseViewModel.select().observe(this, exercises -> {
//      if (exercises != null) {
//        this.recyclerViewerAdapter.updateDataset(exercises);
//      }
//    });
  }
}

查看模型:

public class ExerciseViewModel extends AndroidViewModel {
  ExercisesRepository repository;
  LiveData<List<Exercise>> data;

  public ExerciseViewModel(Application application) {
    super(application);
    this.repository = new ExercisesRepository(application);
  }

  public void setFilters(String muscleGroups, String type) {
    this.data = this.repository.filterSelect(muscleGroups, type);
  }

  public LiveData<List<Exercise>> select() {
    return data;
  }

  public void insert(Exercise exercise) {
    this.repository.insert(exercise);
  }
}

存储库

public class ExercisesRepository {
  private ExerciseDao dao;

  public ExercisesRepository(Application context) {
    WorkoutRoomDatabase database = WorkoutRoomDatabase.getDb(context);
    this.dao = database.exerciseDao();
  }

  public LiveData<List<Exercise>> filterSelect(String muscleGroups, String type) {
    return this.dao.filterSelect("%" + muscleGroups + "%", "%" + type + "%");
  }

  public void insert(Exercise exercise) {
    new insertAsyncTask(this.dao).execute(exercise);
  }

  private static class insertAsyncTask extends AsyncTask<Exercise, Void, Void> {

    private ExerciseDao exerciseDao;

    insertAsyncTask(ExerciseDao  dao) {
      exerciseDao = dao;
    }

    @Override
    protected Void doInBackground(final Exercise... params) {
      exerciseDao.insert(params[0]);
      return null;
    }
  }
}

道:

@Dao
public interface ExerciseDao {
  @Query("SELECT * FROM exercises WHERE muscleGroups LIKE :muscleGroup AND type LIKE :type")
  LiveData<List<Exercise>> filterSelect(String muscleGroup, String type);
  @Query("SELECT * FROM exercises")
  LiveData<List<Exercise>> selectAll();
  @Insert
  void insert(Exercise exercise);
  @Update
  void update(Exercise exercise);
  @Delete
  void delete(Exercise exercise);
  @Query("DELETE FROM exercises")
  void deleteAll();
}

【问题讨论】:

    标签: android observable


    【解决方案1】:

    您需要进行一些更改,因为您正在重新分配 LiveData 对象,而不是添加过滤的项目。

    您需要将您的 LiveData> 数据 称为 MutableLiveData> 并在 setFilters 方法中,您需要从存储库中获取数组列表并添加它在 MutableLiveData 中使用 setValue 方法。

    ExerciseViewModel

     MutableLiveData<List<Exercise>> data = new MutableLiveData<>();
    
    
        public void setFilters(String muscleGroups, String type) {
            List<Exercise> ex = this.repository.filterSelect(muscleGroups, type).getValue();
            this.data.setValue(ex);
        }
    

    希望对你有帮助。

    【讨论】:

    • 感谢代码示例。我已经实现了这个更改,但现在来自 DB 的结果始终为 NULL,但我知道 DB 中有与该查询匹配的数据。
    • 我忘了创建 MutableLiveData 的实例:MutableLiveData> data = new MutableLiveData();
    • 我在 ViewModel 中创建了一个 MutableLiveData 实例。然而,DAO 的结果是返回 LiveData,我在其上调用 getValue() 并获得 NULL。
    • 那么,你需要检查和调试你的代码。也许你还有别的东西。我无法测试整个代码。对不起
    • 无论如何我正在查看您的代码,但您缺少一些东西,您的 recyclerView 声明在哪里?你在哪里将适配器设置为 recyclerview.setAdapter()
    【解决方案2】:

    在您的 setFilters 方法中,您将一个全新的实时数据重新分配给您拥有的实时数据实例。实时数据仅在其值发生更改时触发事件。因此,您可以使用可变的实时数据,并通过此类的 setValue() 设置它的值。您的观察者将被调用。

    【讨论】:

    • 谢谢!我现在就试试,让你知道它是否有效。 :)
    • @Jeremi 你有没有让你的代码工作?如果是这样,您还需要添加什么才能使其正常工作?
    【解决方案3】:

    我面临同样的问题,当我通过按钮单击时没有调用第二个观察者,而当我调用 BottomSheetDialogFragament 的 onCreateView 函数时,两个观察者都被调用。

    private fun getKey() {
            if (ApiConstants.publicKey == null) {
                sendOTPViewModel.key.observe(viewLifecycleOwner, Observer { t ->
                    if (t == ApiConstants.KEY_SUCCESS) {
                        getKey()
                    }
                })
    
            } else {
                validateUser(number, from, BaseActivity.getDeviceId(mContext))
            }
        }
    
     private fun validateUser(loginId: String?, loginType: String?, deviceId: String?) {
    
            sendOTPViewModel.getValidateUser(loginId, loginType, deviceId).observe(viewLifecycleOwner, Observer { t ->
                LoggerUtils.E(TAG, t)
            })
    
        }
    
    

    【讨论】:

      【解决方案4】:

      Kotlin 答案

      如果您正在使用,请删除函数中的这两点:

      1. = viewModelScope.launch { }
      2. 暂停

      【讨论】:

        猜你喜欢
        • 2022-06-12
        • 2019-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多