Android-从UI线程而不是从后台线程修改适配器

问题描述 投票:0回答:1

我有一个从json填充并使用自定义适配器的ListView。

这是我在ZoznamActivity中缩短的代码:

 public class Zoznam extends AppCompatActivity{

    private ArrayList<Actors> actorsList;
    private ActorAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

   setContentView(R.layout.search_filter);
        final ListView lv = findViewById(R.id.listView1);

        actorsList = new ArrayList<>();
        adapter = new ActorAdapter(this, "Zoznam", actorsList);

        lv.setAdapter(adapter);adapter.notifyDataSetChanged();

        new GetContacts(Zoznam.this).execute("all","all");

   private static class GetContacts extends AsyncTask<String, Void, String> {
        ProgressDialog dialog;
        private final WeakReference<Zoznam> activityReference;

        GetContacts(Zoznam context) {
            activityReference = new WeakReference<>(context);
        }

        @Override
        protected void onPreExecute() {
            Zoznam activity = activityReference.get();
            if (activity == null || activity.isFinishing()) return;
            super.onPreExecute();
            dialog = new ProgressDialog(activity);
            dialog.setMessage(activity.getResources().getString(R.string.Loading));
            dialog.setTitle(activity.getResources().getString(R.string.connecting));
            dialog.show();
            dialog.setCancelable(false);
        }

        @Override
        protected String doInBackground(String... sText1) {final Zoznam activity = activityReference.get();


            HttpHandler sh = new HttpHandler();
            String url = "URL";
            String jsonStr = sh.makeServiceCall(url);

            if (jsonStr != null) {
                try {JSONObject jsonObj = new JSONObject(jsonStr);
                    JSONArray actors = jsonObj.getJSONArray("result");

                    for (int i = 0; i < actors.length(); i++) {
                        JSONObject c = actors.getJSONObject(i);

                        Actors actor = new Actors();

                        actor.setLetter(c.getString("letter"));
                        actor.setNazov(c.getString("nazov"));
                        actor.setThumb(c.getString("thumb"));


                        activityReference.get().actorsList.add(actor);

                    }

                }  catch (final JSONException e) {

                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(activity,
                                    R.string.Nodata,
                                    Toast.LENGTH_LONG).show();
                        }
                    }); }

return jsonStr;

            } else {
                activity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(activity,
                                R.string.Network,
                                Toast.LENGTH_LONG).show();
                    }
                });
                return null;
            }
        }

        protected void onPostExecute(String result) {
            Zoznam activity = activityReference.get();
            if (activity == null || activity.isFinishing()) return;
            dialog.dismiss();
            activity.adapter.notifyDataSetChanged();
            super.onPostExecute(result);

        }

    }

    protected void onResume() {
        super.onResume();
        adapter.notifyDataSetChanged();
    }

问题是,在崩溃报告中我发现了此错误:

适配器的内容已更改,但ListView尚未收到通知。确保不从后台线程修改适配器的内容,而仅从UI线程修改。确保您的适配器在其内容更改时调用notifyDataSetChanged()。

但是,仅在一台设备上发生了一次,但是我想解决这个问题。

我已经阅读了更多有关此的主题,但是我仍然没有解决方案。正如您在我的代码中看到的那样,我也在onResume和onPostExecute上调用notifyDataSetChanged(),所以不确定将其放在其他位置。

我认为我需要在从json的for循环之后的某个地方使用activity.runOnUiThread(new Runnable()),在该地方我将项目添加到arraylist,但不确定如何执行此操作以及是否可以解决问题。

我最近的代码更新:

 for (int i = 0; i < actors.length(); i++) {
                    JSONObject c = actors.getJSONObject(i);

                    final Actors actor = new Actors();

                    actor.setLetter(c.getString("letter"));
                    actor.setNazov(c.getString("nazov"));
                    actor.setThumb(c.getString("thumb"));
                    actor.setPerex(c.getString("perex"));
                    actor.setTyp(c.getString("typ"));
                    actor.setPlace(c.getString("place"));
                    actor.setExterier(c.getString("adresar"));

                    activity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            activityReference.get().actorsList.add(actor);
                            activity.adapter.notifyDataSetChanged();
                        }
                    });

                }
android ui-thread
1个回答
0
投票

您可能得到了例外,因为您在后台线程上更新了适配器列表。

activityReference.get().actorsList.add(actor); doInBackground方法中的这一行正在更新您传递给适配器的实际列表。 doInBackground中的所有计算必须非常快地进行,并且notifyDataSetChanged中的onPostExecute被调用。我不确定如何操作,但是这一次没有及时调用您的onPostExecute,因此您的列表已更新,但是您的ListView没有收到通知。

您可以在AsyncTask中创建本地列表,并在onPostExecute中更新活动列表。

© www.soinside.com 2019 - 2024. All rights reserved.