Android从另一个线程加载ListView

时间:2014-03-24 14:38:25

标签: android android-listview

请解释一下为什么这段代码不起作用?(我需要在 onClick()中调用 lv.setAdapter(adapterA)。有必要更改适配器)。它可以在主线程上运行代码,但我需要在另一个线程中加载数据。我会很感激任何想法。谢谢。

package com.example.examplelist;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;

public class ActivityElemsExample extends Activity implements OnClickListener {
    ArrayList<Elem> myList;
    Button btn;
    ListView lv;
    AdapterA adapterA;
    AdapterB adapterB;
    boolean running = false;
    Thread thread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button)findViewById(R.id.button_loading);
        btn.setOnClickListener(this);
        lv = (ListView)findViewById(R.id.lv);

        myList = new ArrayList<Elem>();
        adapterA = new AdapterA(this, myList);
        adapterB = new AdapterB(this, myList);
    }

    public void onClick(View button){
        if(!running){
            running = true;
            Log.d("MyLogs", "LOADING");

            /*
            if(...){
                lv.setAdapter(adapterA);
            }
            else{
                lv.setAdapter(adapterB);
            }
            */

            lv.setAdapter(adapterA);

            thread = new Thread(new Runnable(){
            public void run(){
                myList.clear();

                for(int i=0; i < 3000; i++){
                    myList.add(new Elem(i, System.currentTimeMillis(), "Elem "+i));
                }
                handler.sendEmptyMessage(1);
            }
            });
            thread.start();
        }
    }

    public void onDestroy(){
        super.onDestroy();
        if(thread != null){
            while(true){
                try{
                    thread.join();
                    break;
                }
                catch (InterruptedException e){}
            }
        }
    }

    public Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            /*
             if(...){

             }
             else{

             }
             */

            adapterA.notifyDataSetInvalidated();
            adapterA.notifyDataSetChanged();

            running = false;
        }
    };
}

日志:

FATAL EXCEPTION: main
Process: com.example.examplelist, PID:553
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its contentges ...

3 个答案:

答案 0 :(得分:0)

问题是,您在显示适配器的数据时正在修改它。您应该在添加更多项目之前复制数据,然后替换适配器中的数据并通知。

答案 1 :(得分:0)

您可以从后台线程在UI线程上运行该段代码。任何修改UI的工作(例如列表)都需要在UI线程上。您可以使用活动的runOnUiThread方法。

 MyActivity.runOnUiThread(new Runnable() {

    @Override
    public void run() {
        // UI work here
       }
    });

您还可以将所有项目放在后台线程的列表中,然后在列表中包含所有项目后更新适配器。

http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)

答案 2 :(得分:-1)

解决方案:

package com.example.examplelist;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;

public class ActivityElemsExample extends Activity implements OnClickListener {
    ArrayList<Elem> myList;
    Button btn;
    ListView lv;
    AdapterA adapterA;
    AdapterB adapterB;
    boolean running = false;
    Thread thread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (Button)findViewById(R.id.button_loading);
        btn.setOnClickListener(this);
        lv = (ListView)findViewById(R.id.lv);

        myList = new ArrayList<Elem>();

        adapterA = new AdapterA(this, myList);
        adapterB = new AdapterB(this, myList);

    }

    public void onClick(View button){
        if(!running){
            running = true;
            Log.d("MyLogs", "LOADING");

            thread = new Thread(new Runnable(){
            public void run(){
                myList.clear();

                for(int i=0; i < 3000; i++){
                    myList.add(new Elem(i, System.currentTimeMillis(), "Elem "+i));
                }
                handler.sendEmptyMessage(1);
            }
            });
            thread.start();
        }
    }

    public void onDestroy(){
        super.onDestroy();
        if(thread != null){
            while(true){
                try{
                    thread.join();
                    break;
                }
                catch (InterruptedException e){}
            }
        }
    }

    public Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {

            lv.setAdapter(adapterA);

            running = false;
        }
    };
}