You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在AsyncTask中通过Gson字符串构建多ArrayList并修复RecyclerView填充异常

看起来你遇到了几个典型的Android异步操作和数据解析问题,我来帮你一步步解决:

问题1:AsyncTask中SharedPreferences获取错误

你在doInBackground里用getPreferences(getBaseContext().MODE_PRIVATE)是不对的——getPreferences()是Activity的方法,而且MODE_PRIVATE是全局常量,不需要从Context获取。如果你的DoSomeTasks是MoodsActivity的内部类,直接用MoodsActivity.this.getPreferences(MODE_PRIVATE)即可;如果是独立类,要传入Activity的Context对象。

问题2:后台线程不能操作UI

你在doInBackground里调用createRecycler()是错误的,因为这个方法涉及RecyclerView初始化和Adapter设置,属于UI操作,必须在主线程执行。AsyncTask的onPostExecute()方法是在主线程运行的,应该把解析好的数据返回给这个方法,再在这里更新UI。

问题3:Gson反序列化泛型类型错误

直接用gson.fromJson(history, ArrayList.class)会导致Gson无法识别Mood泛型,解析出来的列表元素是LinkedTreeMap而不是Mood对象,调用getName()等方法会抛出类型转换异常。需要用TypeToken来指定具体的泛型类型。

问题4:不必要的列表拆分

拆分出moodNames、moodGenres、moodColors三个独立列表不仅冗余,还容易出现数据不一致的问题。直接传递ArrayList<Mood>给Adapter会更简洁可靠。


修改后的完整代码示例

1. 修复后的AsyncTask(作为MoodsActivity的内部类)

public class DoSomeTasks extends AsyncTask<Void, Void, ArrayList<Mood>> {

    @Override
    protected ArrayList<Mood> doInBackground(Void... voids) {
        // 正确获取SharedPreferences
        SharedPreferences prefs = MoodsActivity.this.getPreferences(MODE_PRIVATE);
        // 用空数组作为默认值,避免解析空字符串抛出异常
        String history = prefs.getString("history", "[]");
        
        try {
            Gson gson = new Gson();
            // 用TypeToken指定泛型类型,让Gson正确解析为Mood列表
            Type moodListType = new TypeToken<ArrayList<Mood>>(){}.getType();
            return gson.fromJson(history, moodListType);
        } catch (Exception e) {
            Log.e("MoodsActivity", "Couldn't load any moods", e);
            return new ArrayList<>(); // 返回空列表,避免后续空指针
        }
    }

    @Override
    protected void onPostExecute(ArrayList<Mood> moodList) {
        super.onPostExecute(moodList);
        // 在主线程更新RecyclerView
        createRecycler(moodList);
    }
}

2. 修改createRecycler方法,直接接收Mood列表

public void createRecycler(ArrayList<Mood> moodList){
    Log.d("MoodsActivity", "Reached createRecycler, mood count: " + moodList.size());
    RecyclerView rView = findViewById(R.id.moodlistView);
    // 直接把Mood列表传给Adapter
    RecycleViewAdapter rAdapt = new RecycleViewAdapter(moodList, this);
    rView.setAdapter(rAdapt);
    rView.setLayoutManager(new LinearLayoutManager(this));
}

3. 调整RecyclerViewAdapter,直接使用Mood对象

// 示例Adapter结构,根据你的布局需求调整控件ID
public class RecycleViewAdapter extends RecyclerView.Adapter<RecycleViewAdapter.ViewHolder> {

    private ArrayList<Mood> mMoodList;
    private Context mContext;

    public RecycleViewAdapter(ArrayList<Mood> moodList, Context context) {
        mMoodList = moodList;
        mContext = context;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.your_item_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Mood currentMood = mMoodList.get(position);
        holder.nameTv.setText(currentMood.getName());
        holder.genreTv.setText(currentMood.getGenre());
        // 假设Color是android.graphics.Color,转换为ARGB值设置背景
        holder.colorView.setBackgroundColor(currentMood.getColor().toArgb());
    }

    @Override
    public int getItemCount() {
        return mMoodList.size();
    }

    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView nameTv;
        TextView genreTv;
        View colorView;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            nameTv = itemView.findViewById(R.id.tv_mood_name);
            genreTv = itemView.findViewById(R.id.tv_mood_genre);
            colorView = itemView.findViewById(R.id.view_mood_color);
        }
    }
}

4. 启动AsyncTask的方式

在MoodsActivity的onCreate或者onResume里启动异步任务:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_moods);
    
    // 启动异步任务加载数据,避免主线程负载过高
    new DoSomeTasks().execute();
    
    // 按钮点击事件简化写法
    Button preferenceButton = findViewById(buttonId);
    preferenceButton.setOnClickListener(v -> {
        Intent preferencesPage = new Intent(MoodsActivity.this, PreferencesActivity.class);
        startActivity(preferencesPage);
    });
}

额外建议

  • 用Log代替System.out.print,Android Studio的Logcat能更清晰地查看调试信息和异常堆栈。
  • 如果你的minSdkVersion >= 26,建议用Coroutines替代AsyncTask(AsyncTask已被官方废弃),但上述代码在旧版本依然有效。

内容的提问来源于stack exchange,提问作者AshleeCW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:50:05