[英]Recyclerview Adapter not refreshing
I have a mind-boggling problem I can't seem to solve. 我有一个难以解决的难题,似乎无法解决。
The data in my RecyclerView
is not updating, and after an entire day of debugging, I can't find the problematic code. RecyclerView
的数据没有更新,经过一整天的调试,我找不到有问题的代码。 The API returns the correct data, and I parse the correct data in a wallItemList
which I pass to the Adapter
. 该API返回正确的数据,然后在wallItemList
解析正确的数据, wallItemList
其传递给Adapter
。
After changing the language setting to either one of the 2 (English or Dutch), the items in my Recyclerview should update with it and the title of the element should change to the translated string. 将语言设置更改为两种语言之一(英语或荷兰语)后,Recyclerview中的项目应随之更新,并且元素的标题应更改为翻译后的字符串。
wallItemList
manually by passing the created wallItemList
from the MainActivity
and calling notifyDataSetChanged()
在适配器内部创建刷新功能,并通过从MainActivity
传递创建的wallItemList
并调用notifyDataSetChanged()
wallItemList
手动更新wallItemList
notifyDataSetChanged()
before, in and after the OnClickListener
in the MyRecyclerViewAdapter
在OnClickListener
中的MyRecyclerViewAdapter
之前,之中和之后调用notifyDataSetChanged()
onBindViewHolder
in the MyRecyclerViewAdapter
设置在项目onBindViewHolder
在MyRecyclerViewAdapter
Strangely enough, when logging the language of the wallItem
just before adapter.setOnItemClickListener
in populateRecyclerView()
, the language is right. 奇怪的是,当在populateRecyclerView()
中的wallItem
之前记录adapter.setOnItemClickListener
的语言时,该语言是正确的。 But when I get the string from the object in MyRecyclerViewAdapter's
onBindViewHolder
, it shows the wrong language. 但是,当我从MyRecyclerViewAdapter's
onBindViewHolder
的对象获取字符串时,它显示了错误的语言。
Here is my MainActivity.java
: 这是我的MainActivity.java
:
public class MainActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
private List<WallItem> WallItemList;
private RecyclerView mRecyclerView;
private MyRecyclerViewAdapter adapter;
private ProgressBar progressBar;
// LifeCycle variables
private String JSONResults = "";
final static private String JSON_KEY_RESULTS = "";
final static private String WALL_ITEM_LIST_KEY = "";
// SharedPrefences variables
private String APIUrlPreferenceString = "";
private String langPreferenceString = "";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Setup shared preferences
setupSharedPreferences();
// Load the recyclerView
loadRecyclerView(savedInstanceState);
}
private void setLanguageSettings(String lang)
{
//create a string for country
String country = "";
if(lang.equals("en"))
{
country = "EN";
}
else if(lang.equals("nl"))
{
country = "NL";
}
//use constructor with country
Locale locale = new Locale(lang, country);
Locale.setDefault(locale);
Configuration config = new Configuration();
config.locale = locale;
getBaseContext().getResources().updateConfiguration(config,
getBaseContext().getResources().getDisplayMetrics());
}
private void setupSharedPreferences()
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
APIUrlPreferenceString = sharedPreferences.getString(getString(R.string.pref_api_url_key), getString(R.string.pref_api_url_def_value));
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
// Language settings
if(sharedPreferences.getBoolean(getString(R.string.pref_lang_check_key), true))
{
// Use device settings
setLanguageSettings(Resources.getSystem().getConfiguration().locale.getLanguage());
langPreferenceString = Resources.getSystem().getConfiguration().locale.getLanguage();
}
else
{
// Use preference settings
setLanguageSettings(sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en)));
langPreferenceString = sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en));
}
}
private void loadRecyclerView(Bundle savedInstanceState)
{
// Lifecycle event to preserve data to prevent repeating API calls
if(savedInstanceState != null && savedInstanceState.containsKey(WALL_ITEM_LIST_KEY) && savedInstanceState.containsKey(JSON_KEY_RESULTS))
{
progressBar.setVisibility(View.GONE);
// Set again in order to preserve state on future rotations
JSONResults = savedInstanceState.getString(JSON_KEY_RESULTS);
// Set wallItemList again in order to preserve state on future rotations
WallItemList = savedInstanceState.getParcelableArrayList(WALL_ITEM_LIST_KEY);
populateRecyclerView();
}
else
{
// First execution
new DownloadTask().execute();
}
}
public class DownloadTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
}
@Override
protected Boolean doInBackground(Void... params) {
boolean result;
String blindWallResults;
try {
// Error fix, because NetworkUtils.buildUrl returns null when failing
if(null == NetworkUtils.buildUrl(APIUrlPreferenceString))
return false;
// Get response from API
blindWallResults = NetworkUtils.getResponseFromHttpUrl(NetworkUtils.buildUrl(APIUrlPreferenceString));
// Send to parser
JSONResults = blindWallResults;
parseResult(blindWallResults);
result = true;
} catch (IOException e) {
e.printStackTrace();
result = false;
}
// When failed
return result;
}
@Override
protected void onPostExecute(Boolean result) {
progressBar.setVisibility(View.GONE);
// If succeeded
if (result) {
populateRecyclerView();
// Show toast when data has been loaded for the first time
Toast.makeText(MainActivity.this, getString(R.string.json_toast_data_loaded), Toast.LENGTH_SHORT).show();
} else {
// If failed make toast
Toast.makeText(MainActivity.this, getString(R.string.json_toast_data_failed), Toast.LENGTH_SHORT).show();
}
}
}
/**
* Populates recyclerView and adds OnItemClickListener
*/
private void populateRecyclerView()
{
WallItem w = WallItemList.get(0);
adapter = new MyRecyclerViewAdapter(MainActivity.this, WallItemList);
mRecyclerView.setAdapter(adapter);
adapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(WallItem item) {
// Function to start new activity
Class detailActivity = DetailActivity.class;
// Create intent
Intent startDetailActivityIntent = new Intent(MainActivity.this, detailActivity);
// Add object to intent
startDetailActivityIntent.putExtra("detailWallItem", (Parcelable)item);
// Start activity
startActivity(startDetailActivityIntent);
}
});
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Save instances of existing objects
outState.putString(JSON_KEY_RESULTS, JSONResults);
outState.putParcelableArrayList(WALL_ITEM_LIST_KEY, (ArrayList<? extends Parcelable>) this.WallItemList);
}
/**
* Parses JSON result
*
* @param result
*/
private void parseResult(String result) {
WallItemList = new ArrayList<>();
try {
JSONArray mJsonArray = new JSONArray(result);
// Loop through JSON array
for (int i = 0; i < mJsonArray.length(); i++) {
// Get picture URI fragment from JSON
String pictureURIFragment = mJsonArray.getJSONObject(i)
.getJSONArray("images").getJSONObject(0)
.getString("url");
// Load images into String
JSONArray JSONImageArray = mJsonArray.getJSONObject(i)
.getJSONArray("images");
// Create array for wallItem
String[] imageArray = new String[JSONImageArray.length()];
// Loop through JSONArray
for(int x = 0; x < JSONImageArray.length(); x++)
{
String pictureURLFragment = JSONImageArray.getJSONObject(x).getString("url");
// Built picture
URL pictureURL = NetworkUtils.builtPictureUrl(pictureURLFragment.toLowerCase());
imageArray[x] = java.net.URLDecoder.decode(pictureURL.toString());
}
// Built picture
URL pictureURL = NetworkUtils.builtPictureUrl(pictureURIFragment.toLowerCase());
String cleanPictureUrl = java.net.URLDecoder.decode(pictureURL.toString());
// add wall item to the list
WallItem item = new WallItem();
// Set fields of wallItem
item.setThumbnail(cleanPictureUrl);
item.setTitle(mJsonArray.getJSONObject(i).getString("author"));
item.setPhotographer(mJsonArray.getJSONObject(i).getString("photographer"));
item.setAddress(mJsonArray.getJSONObject(i).getString("address"));
item.setMaterial(mJsonArray.getJSONObject(i).getJSONObject("material").getString(langPreferenceString));
item.setDescription(mJsonArray.getJSONObject(i).getJSONObject("description").getString(langPreferenceString));
item.setImgURLArray(imageArray);
// Add wallItem to list
WallItemList.add(item);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.api_url_settings_item)
{
Intent startSettingsActivity = new Intent(this, SettingsActivity.class);
startActivity(startSettingsActivity);
return true;
}
return super.onOptionsItemSelected(item);
}
private void getDeviceLanguage()
{
Log.d("HERE", Locale.getDefault().getLanguage());
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if(key.equals(getString(R.string.pref_api_url_key)))
{
// Update String again
APIUrlPreferenceString = sharedPreferences.getString(getString(R.string.pref_api_url_key), getString(R.string.pref_api_url_def_value));
new DownloadTask().execute();
}
if(key.equals(getString(R.string.pref_lang_check_key)))
{
// 1. If true, use system language.
// 2. if System language != en or nl, use default language: en.
// 3. if false, make selectable
}
if(key.equals(getString(R.string.pref_lang_list_key)) || key.equals(getString(R.string.pref_lang_check_key)))
{
// Language settings
if(sharedPreferences.getBoolean(getString(R.string.pref_lang_check_key), true))
{
// Use device settings
setLanguageSettings(Resources.getSystem().getConfiguration().locale.getLanguage());
langPreferenceString = Resources.getSystem().getConfiguration().locale.getLanguage();
}
else
{
// Use preference settings
setLanguageSettings(sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en)));
langPreferenceString = sharedPreferences.getString(getString(R.string.pref_lang_list_key), getString(R.string.pref_lang_label_en));
}
// Reload data after executing new Download task
new DownloadTask().execute();
this.recreate();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
protected void onDestroy() {
super.onDestroy();
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
}
} }
Here is my MyRecyclerViewAdapter.java 这是我的MyRecyclerViewAdapter.java
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
private List<WallItem> wallItemList;
private Context mContext;
private OnItemClickListener onItemClickListener;
public MyRecyclerViewAdapter(Context context, List<WallItem> wallItemList) {
this.wallItemList = wallItemList;
this.mContext = context;
WallItem w = wallItemList.get(0);
}
@Override
public CustomViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.list_row, null);
CustomViewHolder viewHolder = new CustomViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(CustomViewHolder customViewHolder, int i) {
final WallItem wallItem = wallItemList.get(i);
//Download image using picasso library
if (!TextUtils.isEmpty(wallItem.getThumbnail())) {
// Load image into imageView
Picasso.with(mContext).load(wallItem.getThumbnail())
.error(R.drawable.placeholder)
.placeholder(R.drawable.placeholder)
.into(customViewHolder.imageView);
}
//Setting text view title
customViewHolder.textView.setText(Html.fromHtml(wallItem.getMaterial()));
// Set OnClickListener to wallItem
View.OnClickListener listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
onItemClickListener.onItemClick(wallItem);
}
};
customViewHolder.imageView.setOnClickListener(listener);
customViewHolder.textView.setOnClickListener(listener);
}
// Overwrite to return
@Override
public int getItemCount() {
return (null != wallItemList ? wallItemList.size() : 0);
}
class CustomViewHolder extends RecyclerView.ViewHolder {
protected ImageView imageView;
protected TextView textView;
public CustomViewHolder(View view) {
super(view);
this.imageView = (ImageView) view.findViewById(R.id.thumbnail);
this.textView = (TextView) view.findViewById(R.id.title);
}
}
public OnItemClickListener getOnItemClickListener() {
return onItemClickListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
} }
My apologies for posting all the code but I can't identify the crucial points and don't have enough experience to pinpoint where it's going wrong. 我为发布所有代码表示歉意,但我无法确定关键点,也没有足够的经验来查明问题出在哪里。 If anyone could help you would it would be greatly appreciated! 如果有人可以帮助您,将不胜感激!
I suggest you to initialize and set the adapter in onCreate()
method with an empty array of WallItems. 我建议您使用一个空的WallItems数组在onCreate()
方法中初始化和设置适配器。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyRecyclerViewAdapter(MainActivity.this, new ArrayList<WallItem>());
mRecyclerView.setAdapter(adapter);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Setup shared preferences
setupSharedPreferences();
// Load the recyclerView
loadRecyclerView(savedInstanceState);
}
To update the list of items, I normally have a setItems
method inside my adapter that updates the list and calls notifyDataSetChanged()
要更新项目列表,通常我的适配器内部有一个setItems
方法,该方法可以更新列表并调用notifyDataSetChanged()
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
...
public void setItems(List<WallItem> items) {
this.wallItemList = wallItemList;
notifyDataSetChanged();
}
}
Your populateRecyclerView
method then should call the setItems
method to update the new list of items. 然后,您的populateRecyclerView
方法应调用setItems
方法来更新新的项目列表。
private void populateRecyclerView()
{
WallItem w = WallItemList.get(0);
adapter.setItems(WallItemList);
adapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(WallItem item) {
// Function to start new activity
Class detailActivity = DetailActivity.class;
// Create intent
Intent startDetailActivityIntent = new Intent(MainActivity.this, detailActivity);
// Add object to intent
startDetailActivityIntent.putExtra("detailWallItem", (Parcelable)item);
// Start activity
startActivity(startDetailActivityIntent);
}
});
}
I didn't test, buy this is how I normally use RecyclerView. 我没有测试,购买这是我通常使用RecyclerView的方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.