使用处理程序发布到 UI 线程

Posted

技术标签:

【中文标题】使用处理程序发布到 UI 线程【英文标题】:Use Handler To Post In To UI Thread 【发布时间】:2015-10-27 18:15:30 【问题描述】:

我正在开发一个 android 应用程序,该应用程序从 Internet 获取图像并显示在用户界面中。我正在使用 RecyclerView 来显示图像。我打算使用单独的线程下载图像。并通过处理程序更新 RecyclerView。我不知道这个概念是否正确,(我知道 AsyncTask,但出于学习目的,我正在尝试实现 Handler。) 所以我的编码与下面相同

private void loadNewsThumbnailImage(ArrayList<DataItem> dataList) 
    for (DataItem item : DataList)  //DataItem is the model class
        loadThumbnailFromInternet(item);
        




private void loadThumbnailFromInternet(final DataItem dataItem) 

        Thread imageDowloaderThread = new Thread(new Runnable() 
            @Override
            public void run() 
                Bitmap bitmap = null;
                try 
                    bitmap = getDataItemBitmap(dataItem.getmImageUrl());
                    dataItem.setmThumbnail(bitmap);
                    new Handler().post(new Runnable()  // Tried new Handler(Looper.myLopper()) also
                        @Override
                        public void run() 
                            mAdapter.notifyDataSetChanged();
                        
                    );
                 catch (IOException e) 
                    e.printStackTrace();
                
            
        );
        imageDowloaderThread.start();

    

我已执行此代码,但出现错误,应用程序已终止,我不知道为什么会这样。请任何人帮我解决。并解释当前代码的问题所在。

(请不要建议使用 AsyncTask(我试过了,效果很好))

更新

获取错误:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

【问题讨论】:

请重新加载qn 【参考方案1】:

您的应用程序正在终止,因为您正在从非 UI 线程调用 notifyDataSetChanged()。

替换:

 new Handler().post(new Runnable()  // Tried new Handler(Looper.myLopper()) also
                        @Override
                        public void run() 
                            mAdapter.notifyDataSetChanged();
                        
                    ); 

有了这个:

new Handler(Looper.getMainLooper()).post(new Runnable()  // Tried new Handler(Looper.myLopper()) also
                    @Override
                    public void run() 
                        mAdapter.notifyDataSetChanged();
                    
                );

【讨论】:

听起来不错,但是 Looper.getMainLooper() 和 Looper.myLooper() 有什么区别呢? Looper.getMainLooper() 获取应用程序的主循环器,而 Looper.myLooper() 返回与当前线程关联的循环器。推荐人:developer.android.com/reference/android/os/Looper.html【参考方案2】:

你定义的线程没有Looper,也没有消息队列,所以你不能在这个线程中发送消息。 AsyncTask 有自己的 Looper,你可以在它的源代码中找到它。这是在 AsyncTask 中定义的处理程序:

private static class InternalHandler extends Handler 
    public InternalHandler() 
        super(Looper.getMainLooper());
    

    @SuppressWarnings("unchecked", "RawUseOfParameterizedType")
    @Override
    public void handleMessage(Message msg) 
        AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
        switch (msg.what) 
            case MESSAGE_POST_RESULT:
                // There is only one result
                result.mTask.finish(result.mData[0]);
                break;
            case MESSAGE_POST_PROGRESS:
                result.mTask.onProgressUpdate(result.mData);
                break;
        
    

【讨论】:

以上是关于使用处理程序发布到 UI 线程的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Android 处理程序更新 UI 线程中的 TextView?

QtConcurrent--在数以千计的结果发布到UI线程中保持GUI的响应。

使用 WPF ui 进行多线程处理

在 ui 线程中执行委托(使用消息泵)

WPF_UI线程

WPF 线程 Dispatcher