旋转设备时 Recyclerview 数据消失
Posted
技术标签:
【中文标题】旋转设备时 Recyclerview 数据消失【英文标题】:Recyclerview data disappears when device is rotated 【发布时间】:2020-08-02 08:14:32 【问题描述】:即使我使用的是 ViewModel,只要设备旋转,Recyclerview 中的数据就会消失。我不得不将 makeSearch() 方法放在 onClick() 方法中,因为我需要获取按钮抓取的文本并将其用作搜索参数。有没有更好的方法可以解决这个问题来避免这个问题?我的代码就在这里:
搜索活动:
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
// What happens when the search button is clicked
materialButton.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
if (Objects.requireNonNull(textInputEditText.getText()).toString().isEmpty())
textInputEditText.setError("Type a search query");
else
mSearchInput = Objects.requireNonNull(textInputEditText.getText()).toString();
textInputEditText.setText("");
makeSearch();
);
// Gets the ViewModel, Observes the Question LiveData and delivers it to the Recyclerview
private void makeSearch()
final SearchAdapter searchAdapter = new SearchAdapter();
SearchViewModel mSearchViewModel = new ViewModelProvider(this,
new CustomSearchViewModelFactory(new SearchRepository())).get(SearchViewModel.class);
mSearchViewModel.setQuery(mSearchInput);
mSearchViewModel.getQuestionLiveData().observe(this, new Observer<List<Question>>()
@Override
public void onChanged(List<Question> questions)
mQuestions = questions;
searchAdapter.setQuestions(questions);
);
mRecyclerView.setAdapter(searchAdapter);
searchAdapter.setOnClickListener(mOnClickListener);
搜索视图模型:
public class SearchViewModel extends ViewModel
private SearchRepository mSearchRepository;
private MutableLiveData<String> mSearchLiveData = new MutableLiveData<>();
private LiveData<List<Question>> mQuestionLiveData = Transformations.switchMap(mSearchLiveData, (query) ->
return mSearchRepository.getQuestions(query);
);
SearchViewModel(SearchRepository searchRepository)
this.mSearchRepository = searchRepository;
public LiveData<List<Question>> getQuestionLiveData()
return mQuestionLiveData;
public void setQuery(String query)
mSearchLiveData.setValue(query);
搜索存储库:
public class SearchRepository
//private String inTitle;
private MutableLiveData<List<Question>> mQuestions = new MutableLiveData<>();
public SearchRepository()
//getQuestionsWithTextInTitle();
private void getQuestionsWithTextInTitle(String inTitle)
ApiService apiService = RestApiClient.getApiService(ApiService.class);
Call<QuestionsResponse> call = apiService.getQuestionsWithTextInTitle(inTitle);
call.enqueue(new Callback<QuestionsResponse>()
@Override
public void onResponse(Call<QuestionsResponse> call, Response<QuestionsResponse> response)
QuestionsResponse questionsResponse = response.body();
if (questionsResponse != null)
mQuestions.postValue(questionsResponse.getItems());
//shouldShowData = true;
else
Log.d("SearchRepository", "No matching question");
//shouldShowData = false;
@Override
public void onFailure(Call<QuestionsResponse> call, Throwable t)
//shouldShowData = false;
t.printStackTrace();
);
public LiveData<List<Question>> getQuestions(String inTitle)
getQuestionsWithTextInTitle(inTitle);
return mQuestions;
【问题讨论】:
据我所知,您没有在onCreate()
中执行任何操作来重新填充您的 RecyclerView
。您说inTitle
需要成为您的视图模型的构造函数参数,这极大地限制了自己,因为该值会随着用户在搜索中键入而改变。您可能希望让您的视图模型公开一个稳定的LiveData
(例如,MediatorLiveData
),该活动始终可以观察到,并让搜索更新该稳定的输出。有关示例,请参见 gitlab.com/commonsguy/cw-jetpack-java/-/tree/v0.8/Weather。
【参考方案1】:
您通过CustomSearchViewModelFactory
将搜索输入传递到ViewModel 的构造函数和SearchRepository
的构造函数的方法在任何情况下都行不通。当您第一次搜索 CustomSearchViewModelFactory
创建 ViewModel 时,第二次点击搜索时,您的 SearchViewModel
已经创建,并且您的工厂没有第二次调用,这意味着您永远不会收到第二个查询。
相反,您应该归档ViewModel Overview documentation,并使用Transformations.switchMap()
将您的输入(搜索字符串)转换为给定查询的新LiveData<List<Question>>
。
这意味着您的 ViewModel 看起来像
public class SearchViewModel extends ViewModel
private SearchRepository mSearchRepository;
private MutableLiveData<String> mSearchLiveData = new MutableLiveData<String>();
private LiveData<List<Question>> mQuestionLiveData =
Transformations.switchMap(mSearchLiveData, (query) ->
return mSearchRepository.getQuestions(query);
);
public SearchViewModel()
mSearchRepository = new SearchRepository();
public void setQuery(String query)
mSearchLiveData.setValue(query);
public LiveData<List<Question>> getQuestionLiveData()
return mQuestionLiveData;
然后您将 Activity 更新为:
-
始终观察
getQuestionLiveData()
(请注意,在您实际设置第一个查询之前,您不会收到对观察者的回调)
在您的SearchViewModel
上致电setQuery()
makeSearch()
完全删除您的CustomSearchViewModelFactory
(不再需要)。
【讨论】:
嗨@ianhanniballake,感谢您的回复。我对您编写的部分代码遇到了挑战。首先,mQuestionLiveData
是 LiveData<List<Question>>
而不是 LiveData<String>
。其次,mSearchRepository.getQuestions()
返回一个LiveData<List<Question>>
,正如我在上面添加的SearchRepository
类中所见。这使得实现您编写的代码有点困难,请帮助
@MayorJay - 是的,你是对的。我已经更正了我的代码
更正仍然没有帮助解决我的问题。请查看我上面的SearchRepository
课程。谢谢。当我尝试你的代码时,我收到了这个错误java.lang.RuntimeException: Cannot create an instance of class com.example.josycom.flowoverstack.viewmodel.SearchViewModel
您还需要更改您的 SearchRepository,使其不接受构造函数参数,而是将输入输入到 getQuestions(),为每个查询构建一个新的 LiveData 实例
我使用您在ViewModel documentation 中看到的答案和示例修改了我的代码,我将SearchRespository
作为参数传递给SearchViewModel
构造函数。它的工作原理是每次我输入新的搜索查询时,都会返回并显示一个新的相应结果,但是在设备旋转时,显示的数据仍然消失以上是关于旋转设备时 Recyclerview 数据消失的主要内容,如果未能解决你的问题,请参考以下文章
使用 Glide 和 RecyclerView 上下滚动时图像消失,图像之间的空间增加