如何在不冻结程序的情况下更新ListView

时间:2017-12-04 04:30:29

标签: java android multithreading

所以我有一个strings(ISBN)列表,我需要用listview填充与这些strings相关联的对象(书籍对象)。问题是我必须使用字符串获取Book对象的函数需要时间,因此要获得30本书,等待接近4或5秒。

我想到的一种方法是一次获取一个Book对象,并在我得到它们时将它们添加到列表中。但是这个过程会冻结UI,直到完成所有这些操作。如果我尝试将此进程放在一个新线程中,它将不允许我添加到任何UI对象(因为它来自另一个线程)。如果我尝试将其放入AsyncTask,我无法访问ListView,因为它位于MainActivity类中。

必须有一种动态更新UI元素的方法,我相信我已经看过它了。有什么建议吗?

编辑

这是我用来实际向列表中添加项目的代码:

//List view and adapter setup
listView = (ListView) findViewById(R.id.listViewCheckout);
bookAdapter = new SearchBookAdapter(getApplicationContext(), R.layout.search_row_layout);
listView.setAdapter(bookAdapter);

for(int i = 0; i < searches.size(); i++) {

    //Get the book
    Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));

    //Assign data to the adapter variables
    Bitmap cover = book.getCover();
    String title = book.getTitle();
    String author = book.getAuthor();

    //Add data to the adapter and set the list
    SearchBookDataProvider dataProvider = new SearchBookDataProvider(cover, title, author);
    bookAdapter.add(dataProvider);
    bookAdapter.notifyDataSetChanged();
}

5 个答案:

答案 0 :(得分:1)

您是否可以对代码进行一些更改,它认为它可以正常工作

//List view and adapter setup
listView = (ListView) findViewById(R.id.listViewCheckout);
bookAdapter = new SearchBookAdapter(getApplicationContext(), R.layout.search_row_layout);
SearchBookDataProvider dataProvider;
listView.setAdapter(bookAdapter);

 new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] objects) {
                for(int i = 0; i < searches.size(); i++) {

                //Get the book
                Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));

                //Assign data to the adapter variables
                Bitmap cover = book.getCover();
                String title = book.getTitle();
                String author = book.getAuthor();

                //Add data to the adapter and set the list
                dataProvider = new SearchBookDataProvider(cover, title, author);
                bookAdapter.add(dataProvider);
                }
            }
            @Override
            protected void onPostExecute(Object o) {
                if (bookAdapter!= null) {
                    bookAdapter.notifyDataSetChanged();
                }
                super.onPostExecute(o);
            }
 }.execute();

答案 1 :(得分:0)

您可以使用 TimerTask 来更新listview或runUiThread()或doInBackground()。但是,请记住在更新列表时应使用 notifysetChanges()

答案 2 :(得分:0)

第1步:声明Executer服务

 private ExecutorService mExecuterService = null;

第2步:为列表迭代声明一个类并查看更新

  class ListViewUpdater implements Runnable{

            public ListViewUpdater(/* if you need you can pass list params here */){

            }

            @Override
            public void run() {
                for(int i = 0; i < searches.size(); i++) {

                    //Get the book
                    Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));

                    //Assign data to the adapter variables
                    Bitmap cover = book.getCover();
                    String title = book.getTitle();
                    String author = book.getAuthor();



                }
//below code is important for Updating UI ,you should run UI Updates in UI thread
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        bookAdapter.notifyDataSetChanged();
                    }
                });
            }
        }

第3步:启动并调用以下方法

//Add data to the adapter and set the list
    SearchBookDataProvider dataProvider = new SearchBookDataProvider(cover, title, author);
   bookAdapter.add(dataProvider);
    mExecuterService = Executors.newSingleThreadExecutor()
    mExecuterService.execute(new ListViewUpdater());

它可以解决你的问题。

答案 3 :(得分:0)

我认为如果您愿意使用开源项目,那么我的建议将是使用RX-JAVA。它基于被动和推送模型。

link for rx-java

rx-java example

答案 4 :(得分:-1)

您可以获取线程中的书籍列表,并使用收到的数据发送广播。 在MainActivity类中注册广播接收器并更新接收器中的适配器。这不应该冻结用户界面。

编辑 -

  BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Book book = (Book)intent.getSerializableExtra("Book");
        SearchBookDataProvider dataProvider = new SearchBookDataProvider(cover, title, author);
        bookAdapter.add(dataProvider);
        bookAdapter.notifyDataSetChanged();
    }
};

Thread thread = new Thread(){
    @Override
    public void run()
    {
        for(int i = 0; i < searches.size(); i++) {

            //Get the book
            Book book = BackendFunctions.getBookFromISBN(fbSnapshot, searches.get(i));

            Intent intent = new Intent();
            intent.setAction("Book Received");
            intent.putExtra("Book",book);
            sendBroadcast(intent);
        }
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    listView = (ListView) findViewById(R.id.listView);
    listView.setAdapter(bookAdapter);
    registerReceiver(broadcastReceiver,new IntentFilter("Book Received"));
    thread.start();

}