为什么 LiveData setValue 或 PostValue 在视图中只触发一次 onChange?
Why LiveData setValue or PostValue triggers onChange just once in the view?
LiveData setValue 应该触发了 Activity 中的 onChanged 方法,但是它只在第一次调用,当我尝试进行分页时,它中断并且不再调用 onChanged,虽然我的响应确实成功,我在日志中看到了它。 setValue/postValue 怎么了?这是一个错误吗?我应该自己实现观察者模式吗?那么使用 LiveData 有什么意义呢?我的寻呼仅仅为了这已经2-3天了.....
主要Activity class
public class MainActivity extends AppCompatActivity
private MutableLiveData<List<Photo>> mLivePhotos;
// some code...
@Override
protected void onCreate(Bundle savedInstanceState) {
mLivePhotos = loadData();
mLivePhotos.observe(this, photos -> {
Log.d(TAG, "onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
mProgressBar.setVisibility(View.GONE);
mPhotos = photos;
if (mIsInitialCall) {
initiateAdapter();
mIsInitialCall = false;
} else {
mAdapter.updateList(mPhotos.subList(mPageNumber, mPageNumber + 10));
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int lastPosition =
mLayoutManager.findLastCompletelyVisibleItemPosition();
Log.d(TAG, "onScrolled - lastPosition: " + lastPosition);
if (lastPosition == mLayoutManager.getItemCount() - 1) {
Log.d(TAG, "onScrolled - End of list?");
loadData();
}
}
});
}
private MutableLiveData<List<Photo>> loadData() {
Log.d(TAG, "loadData");
if (mArticleViewModel == null) return null;
mPageNumber += 10;
mProgressBar.setVisibility(View.VISIBLE);
return mArticleViewModel.loadPhotos();
}
ViewModel
public class ArticleViewModel extends ViewModel {
private MutableLiveData<List<Photo>> photos;
private ArticleRepository articleRepository;
public MutableLiveData<List<Photo>> loadPhotos() {
Log.d(TAG, "getArticleList");
//TODO; add Dagger 2
articleRepository = new ArticleRepository();
photos = articleRepository.getPhotos();
return photos;
}
存储库
public class ArticleRepository {
public MutableLiveData<List<Photo>> getPhotos() {
final MutableLiveData<List<Photo>> result = new MutableLiveData<>();
Log.d(TAG, "getResults");
ApiService.getService().getPhotos().enqueue(new Callback<List<Photo>>() {
@Override
public void onResponse(Call<List<Photo>> call, Response<List<Photo>> response) {
Log.d(TAG, "onResponse");
if (response.isSuccessful()) {
Log.d(TAG, "isSuccessful");
result.postValue(response.body());
}
}
@Override
public void onFailure(Call<List<Photo>> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage() + "\n" + t.getStackTrace());
}
});
return result;
}
Activity 不应该有任何 MutablieLiveData 成员变量,它应该在 ViewModel 中。
之所以它只在第一次有效,是因为当您第一次观察到某些内容时,它会通知已更改,但是由于您的安排不正确,它再也不会更新。也就是说,因为 ArticleRepository 是在您的 ViewModel 中使用一组新的 MutableLiveData 重新创建的,所以您之前订阅的不再相关 - 而且您只订阅一次 onCreate()
.
您应该将绑定与异步任务分开,例如 loadData()
它们不是一回事。绑定是您在开始收集 MutableLiveData 时所做的(您在 loadData 中所做的),但是在您完成之后,您不应该再做一次。
我还注意到您实际上在模型中使用了 LiveData,不建议这样做,因为它会破坏模式并可能带来其他问题。应该准备演示文稿的是 ViewModel,而不是存储库。由于您当前已经配置了一些东西,您的存储库也可以称为 ViewModel。相反,您应该做的是使用可观察对象将新批次通知给 ViewModel post 或处理可能发生的错误。
研究这个例子:https://developer.android.com/topic/libraries/architecture/viewmodel
注意 loadUsers()
在调用 getUsers()
时完成一次。这就是将 Activity 绑定到 ViewModel 的原因。但是 loadUsers()
可以稍后再做,并且应该 post 对 ViewModel 中的 LiveData 进行更改。
您不应在每次加载更多照片时 new MutableLiveData()
,而应在单个 MutableLiveData
对象上调用 postValue
。示例代码如下:
视图模型:
public class ArticleViewModel extends ViewModel {
private MutableLiveData<List<Photo>> photos;
public MutableLiveData<List<Photo>> getPhotoList() {
Log.d(TAG, "loadData");
if (photos == null) {
photos = new MutableLiveData<>();
loadPhotos();
}
return photos;
}
public void loadPhotos() {
Log.d(TAG, "getArticleList");
ApiService.getService().getPhotos().enqueue(new Callback<List<Photo>>() {
@Override
public void onResponse(Call<List<Photo>> call, Response<List<Photo>> response) {
Log.d(TAG, "onResponse");
if (response.isSuccessful()) {
Log.d(TAG, "isSuccessful");
List<Photo> morePhotos = response.body();
List<Photo> allPhotos = new ArrayList<>();
allPhotos.addAll(photos.getValue());
allPhotos.addAll(morePhotos);
photos.postValue(allPhotos); // <--- post change here
}
}
@Override
public void onFailure(Call<List<Photo>> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage() + "\n" + t.getStackTrace());
}
});
}
}
主要活动:
public class MainActivity extends AppCompatActivity
private ArticleViewModel mArticalViewModel;
// some code...
@Override
protected void onCreate(Bundle savedInstanceState) {
mArticalViewModel = ViewModelProviders.of(this).get(ArticleViewModel.class);
mArticleViewModel.getPhotoList().observe(this, photos -> {
Log.d(TAG, "onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
mProgressBar.setVisibility(View.GONE);
mPhotos = photos;
if (mIsInitialCall) {
initiateAdapter();
mIsInitialCall = false;
} else {
mAdapter.updateList(mPhotos.subList(mPageNumber, mPageNumber + 10));
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int lastPosition =
mLayoutManager.findLastCompletelyVisibleItemPosition();
Log.d(TAG, "onScrolled - lastPosition: " + lastPosition);
if (lastPosition == mLayoutManager.getItemCount() - 1) {
Log.d(TAG, "onScrolled - End of list?");
mArticleViewModel.loadPhotos(); // <--- changed here
}
}
});
}
是回收适配器“arraylist.addAll 或 list.addAll”中的“mAdapter.updateList”函数,viewModel 中的“loadPhotos”函数是否调用了 onCreate?如果是这样,请尝试将“arraylist.addAll 或 list.addAll”更改为“arraylist = data 或 list = data”。并将 loadmore 函数与 firstCallApi(您在 onCreate 中放置的视图模型函数)分开。
所以loadmore函数是用来更新数据的,而firstCall是用来初始化数据的。观察 loadmore 插入代码“arraylist.addAll 或 list.addAll”和 firstCall 插入“list = data”。
示例:
https://gist.github.com/kazuiains/c52f9fc597b66c05b7ec0439a0bb4ccb
LiveData setValue 应该触发了 Activity 中的 onChanged 方法,但是它只在第一次调用,当我尝试进行分页时,它中断并且不再调用 onChanged,虽然我的响应确实成功,我在日志中看到了它。 setValue/postValue 怎么了?这是一个错误吗?我应该自己实现观察者模式吗?那么使用 LiveData 有什么意义呢?我的寻呼仅仅为了这已经2-3天了.....
主要Activity class
public class MainActivity extends AppCompatActivity private MutableLiveData<List<Photo>> mLivePhotos; // some code... @Override protected void onCreate(Bundle savedInstanceState) { mLivePhotos = loadData(); mLivePhotos.observe(this, photos -> { Log.d(TAG, "onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); mProgressBar.setVisibility(View.GONE); mPhotos = photos; if (mIsInitialCall) { initiateAdapter(); mIsInitialCall = false; } else { mAdapter.updateList(mPhotos.subList(mPageNumber, mPageNumber + 10)); } }); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { int lastPosition = mLayoutManager.findLastCompletelyVisibleItemPosition(); Log.d(TAG, "onScrolled - lastPosition: " + lastPosition); if (lastPosition == mLayoutManager.getItemCount() - 1) { Log.d(TAG, "onScrolled - End of list?"); loadData(); } } }); } private MutableLiveData<List<Photo>> loadData() { Log.d(TAG, "loadData"); if (mArticleViewModel == null) return null; mPageNumber += 10; mProgressBar.setVisibility(View.VISIBLE); return mArticleViewModel.loadPhotos(); }
ViewModel
public class ArticleViewModel extends ViewModel { private MutableLiveData<List<Photo>> photos; private ArticleRepository articleRepository; public MutableLiveData<List<Photo>> loadPhotos() { Log.d(TAG, "getArticleList"); //TODO; add Dagger 2 articleRepository = new ArticleRepository(); photos = articleRepository.getPhotos(); return photos; }
存储库
public class ArticleRepository { public MutableLiveData<List<Photo>> getPhotos() { final MutableLiveData<List<Photo>> result = new MutableLiveData<>(); Log.d(TAG, "getResults"); ApiService.getService().getPhotos().enqueue(new Callback<List<Photo>>() { @Override public void onResponse(Call<List<Photo>> call, Response<List<Photo>> response) { Log.d(TAG, "onResponse"); if (response.isSuccessful()) { Log.d(TAG, "isSuccessful"); result.postValue(response.body()); } } @Override public void onFailure(Call<List<Photo>> call, Throwable t) { Log.d(TAG, "onFailure: " + t.getMessage() + "\n" + t.getStackTrace()); } }); return result; }
Activity 不应该有任何 MutablieLiveData 成员变量,它应该在 ViewModel 中。
之所以它只在第一次有效,是因为当您第一次观察到某些内容时,它会通知已更改,但是由于您的安排不正确,它再也不会更新。也就是说,因为 ArticleRepository 是在您的 ViewModel 中使用一组新的 MutableLiveData 重新创建的,所以您之前订阅的不再相关 - 而且您只订阅一次 onCreate()
.
您应该将绑定与异步任务分开,例如 loadData()
它们不是一回事。绑定是您在开始收集 MutableLiveData 时所做的(您在 loadData 中所做的),但是在您完成之后,您不应该再做一次。
我还注意到您实际上在模型中使用了 LiveData,不建议这样做,因为它会破坏模式并可能带来其他问题。应该准备演示文稿的是 ViewModel,而不是存储库。由于您当前已经配置了一些东西,您的存储库也可以称为 ViewModel。相反,您应该做的是使用可观察对象将新批次通知给 ViewModel post 或处理可能发生的错误。
研究这个例子:https://developer.android.com/topic/libraries/architecture/viewmodel
注意 loadUsers()
在调用 getUsers()
时完成一次。这就是将 Activity 绑定到 ViewModel 的原因。但是 loadUsers()
可以稍后再做,并且应该 post 对 ViewModel 中的 LiveData 进行更改。
您不应在每次加载更多照片时 new MutableLiveData()
,而应在单个 MutableLiveData
对象上调用 postValue
。示例代码如下:
视图模型:
public class ArticleViewModel extends ViewModel {
private MutableLiveData<List<Photo>> photos;
public MutableLiveData<List<Photo>> getPhotoList() {
Log.d(TAG, "loadData");
if (photos == null) {
photos = new MutableLiveData<>();
loadPhotos();
}
return photos;
}
public void loadPhotos() {
Log.d(TAG, "getArticleList");
ApiService.getService().getPhotos().enqueue(new Callback<List<Photo>>() {
@Override
public void onResponse(Call<List<Photo>> call, Response<List<Photo>> response) {
Log.d(TAG, "onResponse");
if (response.isSuccessful()) {
Log.d(TAG, "isSuccessful");
List<Photo> morePhotos = response.body();
List<Photo> allPhotos = new ArrayList<>();
allPhotos.addAll(photos.getValue());
allPhotos.addAll(morePhotos);
photos.postValue(allPhotos); // <--- post change here
}
}
@Override
public void onFailure(Call<List<Photo>> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.getMessage() + "\n" + t.getStackTrace());
}
});
}
}
主要活动:
public class MainActivity extends AppCompatActivity
private ArticleViewModel mArticalViewModel;
// some code...
@Override
protected void onCreate(Bundle savedInstanceState) {
mArticalViewModel = ViewModelProviders.of(this).get(ArticleViewModel.class);
mArticleViewModel.getPhotoList().observe(this, photos -> {
Log.d(TAG, "onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
mProgressBar.setVisibility(View.GONE);
mPhotos = photos;
if (mIsInitialCall) {
initiateAdapter();
mIsInitialCall = false;
} else {
mAdapter.updateList(mPhotos.subList(mPageNumber, mPageNumber + 10));
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int lastPosition =
mLayoutManager.findLastCompletelyVisibleItemPosition();
Log.d(TAG, "onScrolled - lastPosition: " + lastPosition);
if (lastPosition == mLayoutManager.getItemCount() - 1) {
Log.d(TAG, "onScrolled - End of list?");
mArticleViewModel.loadPhotos(); // <--- changed here
}
}
});
}
是回收适配器“arraylist.addAll 或 list.addAll”中的“mAdapter.updateList”函数,viewModel 中的“loadPhotos”函数是否调用了 onCreate?如果是这样,请尝试将“arraylist.addAll 或 list.addAll”更改为“arraylist = data 或 list = data”。并将 loadmore 函数与 firstCallApi(您在 onCreate 中放置的视图模型函数)分开。
所以loadmore函数是用来更新数据的,而firstCall是用来初始化数据的。观察 loadmore 插入代码“arraylist.addAll 或 list.addAll”和 firstCall 插入“list = data”。
示例: https://gist.github.com/kazuiains/c52f9fc597b66c05b7ec0439a0bb4ccb