Recyclerview 适配器不刷新

Recyclerview Adapter not refreshing

我有一个 mind-boggling 似乎无法解决的问题。

我的RecyclerView里面的数据没有更新,调试了一整天也没找到有问题的代码。 API returns 正确的数据,我在传递给 AdapterwallItemList 中解析正确的数据。

它应该如何表现

将语言设置更改为两种语言之一(英语或荷兰语)后,我的 Recyclerview 中的项目应随之更新,元素的标题应更改为翻译后的字符串。

我试过的


奇怪的是,当在 populateRecyclerView()adapter.setOnItemClickListener 之前记录 wallItem 的语言时,该语言是正确的。但是当我从 MyRecyclerViewAdapter's onBindViewHolder 中的 object 中获取字符串时,它显示了错误的语言。

这是我的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);
}

}

这是我的 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;
}

}

对于发布所有代码,我深表歉意,但我无法确定关键点,也没有足够的经验来查明哪里出了问题。如果有人可以帮助您,将不胜感激!

我建议您在 onCreate() 方法中使用一个空的 WallItems 数组来初始化和设置适配器。

@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);

}

要更新项目列表,我的适配器中通常有一个 setItems 方法来更新列表并调用 notifyDataSetChanged()

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.CustomViewHolder> {
    ...
    public void setItems(List<WallItem> items) {
        this.wallItemList = wallItemList;
        notifyDataSetChanged();
    }

}

您的 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);
        }
    });
}

我没有测试,买这个是我平时使用RecyclerView的方式。