我有点困惑处理器,AsyncTask和线程之间的区别在Android。我在StackOverflow上读过不少博客和问题。

Handler是后台线程,为您提供与UI通信。例如,更新进度条应该通过Handler来完成。使用Handlers可以获得MessagingQueues的优势,因此如果您想调度消息或更新多个UI元素或有重复任务。

AsyncTask是类似的,事实上,他们利用Handler,但不运行在UI线程,所以它很适合抓取数据,例如抓取web服务。稍后您可以与UI交互。

然而,线程不能与UI交互,提供更多的“基本”线程,你错过了AsyncTask的所有抽象。

但是,我希望在服务中运行套接字连接。这应该运行在一个处理程序或线程,甚至一个AsyncTask?UI交互根本不需要。它对我使用的性能有影响吗?

同时,文档也得到了很大的改进。


在我看来,线程并不是进行套接字连接的最有效的方式,但它们确实在运行线程方面提供了最多的功能。我这么说是因为根据经验,长时间运行线程会导致设备非常热且资源密集。即使是一个简单的while(正确)也会在几分钟内使手机发热。如果你说UI交互不重要,也许AsyncTask是好的,因为它们是为长期流程设计的。这只是我的看法。

更新

请忽略我以上的回答!早在2011年,我就回答了这个问题,当时我对Android的经验远不如现在。我上面的回答是误导性的,被认为是错误的。我把它留在那里,因为很多人在下面评论纠正我,我已经吸取了教训。

There are far better other answers on this thread, but I will at least give me more proper answer. There is nothing wrong with using a regular Java Thread; however, you should really be careful about how you implement it because doing it wrong can be very processor intensive (most notable symptom can be your device heating up). AsyncTasks are pretty ideal for most tasks that you want to run in the background (common examples are disk I/O, network calls, and database calls). However, AsyncTasks shouldn't be used for particularly long processes that may need to continue after the user has closed your app or put their device to standby. I would say for most cases, anything that doesn't belong in the UI thread, can be taken care of in an AsyncTask.


AsyncTask用于执行一些后台计算并将结果发布到UI线程(带有可选的进度更新)。既然你不关心UI,那么处理器或线程似乎更合适。

您可以生成一个后台线程,并通过使用处理程序的post方法将消息传递回主线程。


如果我们看一下源代码,就会发现AsyncTask和Handler完全是用Java编写的。(不过也有一些例外。但这不是重点)

所以在AsyncTask或Handler中没有什么魔力。这些类使开发人员的工作更加轻松。

例如:如果程序A调用方法A(),方法A()可以在程序A的不同线程中运行。我们可以通过以下代码轻松验证:

Thread t = Thread.currentThread();    
int id = t.getId();

为什么我们应该使用一个新线程的一些任务?你可以为它谷歌。很多很多原因,e。G:起重、长时间工作。

那么,线程,AsyncTask和处理程序之间的区别是什么?

AsyncTask和Handler是用Java写的(在内部它们使用线程),所以我们可以用Handler或AsyncTask做的所有事情,我们也可以使用线程来实现。

Handler和AsyncTask能真正帮助什么?

最明显的原因是调用线程和工作线程之间的通信。 调用线程:调用工作线程执行某些任务的线程。调用线程不一定是UI线程)。当然,我们可以用其他方式在两个线程之间进行通信,但是由于线程安全,存在许多缺点(和危险)。

这就是为什么我们应该使用Handler和AsyncTask。这些类为我们做了大部分工作,我们只需要知道要重写哪些方法。

Handler和AsyncTask之间的区别是:当Caller线程是一个UI线程时使用AsyncTask。 这是android文档说的:

AsyncTask允许正确和简单地使用UI线程。这个类 允许执行后台操作,并在UI上发布结果 线程,而不必操作线程和/或处理程序

我想强调两点:

1)易于使用UI线程(所以,当调用线程是UI线程时使用)。

2)不需要操纵处理程序。(意思是:你可以使用Handler而不是AsyncTask,但AsyncTask是一个更简单的选择)。

在这篇文章中有很多东西我还没有说,例如:什么是UI线程,或者为什么它更容易。你必须知道每个类背后的一些方法并使用它,你才会完全理解其中的原因。

@:当你阅读Android文档时,你会看到:

Handler允许您发送和处理Message和Runnable对象 与线程的messagqueuue相关联

这种描述乍一看可能很奇怪。我们只需要了解每个线程都有每个消息队列(就像一个待办事项列表),并且线程将接收每条消息,直到消息队列为空(就像我们完成工作并上床睡觉一样)。因此,当Handler通信时,它只是给调用线程一个消息,它将等待处理。

复杂?只要记住Handler可以安全地与调用线程通信。


AsyncTask被设计为在后台执行不超过几秒的操作(不建议从服务器下载兆字节的文件或计算cpu密集型任务,如文件IO操作)。如果您需要执行一个长时间运行的操作,强烈建议您使用java本机线程。Java为您提供了各种与线程相关的类来完成您所需要的工作。使用Handler更新UI线程。


线程

Android支持标准的Java线程。您可以使用标准线程和包“java.util”中的工具。并发”将操作放到后台。唯一的限制是您不能直接从后台进程更新UI。

如果你需要从后台任务更新UI,你需要使用一些Android特定的类。你可以使用类“android.os”。或者AsyncTask类

类“Handler”可以更新UI。句柄为接收消息和可运行对象提供方法。要使用处理程序,必须继承它的子类并重写handleMessage()来处理消息。要处理Runable,可以使用post()方法;您的活动中只需要一个处理程序实例。

线程可以通过sendMessage(Message msg)或sendEmptyMessage方法发布消息。

AsyncTask

如果你有一个Activity需要下载内容或执行可以在后台完成的操作,AsyncTask允许你维护一个响应式用户界面,并将这些操作的进度发布给用户。

要了解更多信息,你可以看看这些链接。

http://mobisys.in/blog/2012/01/android-threads-handlers-and-asynctask-tutorial/

http://www.slideshare.net/HoangNgoBuu/android-thread-handler-and-asynctask


深入观察之后,事情就一目了然了。

AsyncTask:

这是一种使用线程的简单方法,无需了解任何java线程模型。 AsyncTask给出了各个工作线程和主线程的回调。

用于小的等待操作,如下所示:

从web服务中获取一些数据并在布局中显示。 数据库查询。 当你意识到运行的操作永远不会被嵌套。

处理程序:

当我们在android中安装一个应用程序时,它会为该应用程序创建一个名为MAIN UI thread的线程。所有活动都在该线程中运行。根据android单线程模型规则,我们不能访问UI元素(位图,textview等)直接为另一个线程内定义的活动。

Handler允许你从其他后台线程与UI线程通信。这在android中很有用,因为android不允许其他线程直接与UI线程通信。处理程序可以发送和处理与线程的MessageQueue关联的Message和Runnable对象。每个Handler实例都与单个线程和该线程的消息队列相关联。创建新的Handler时,它将绑定到创建它的线程的线程/消息队列。

它最适合:

它允许您进行消息排队。 消息调度。

线程:

现在是讨论线程的时候了。

线程是AsyncTask和Handler的父线程。它们都在内部使用线程,这意味着您也可以创建自己的线程模型,如AsyncTask和Handler,但这需要对Java的多线程实现有很好的了解。


让我试着用一个例子来回答这个问题:)- MyImageSearch[请参考这里的主活动屏幕的图像-包含编辑文本/搜索按钮/网格视图]

MyImageSearch -一旦用户在编辑文本字段输入详细信息并单击搜索按钮,我们将通过flickr提供的web服务在互联网上搜索图像(您只需要在那里注册以获得密钥/秘密令牌)-对于搜索,我们发送一个HTTP请求和get JSON数据返回响应,其中包含个人图像的url,然后我们将使用它来加载网格视图。

My Implementation - In the main activity I will define a inner class which extends the AsyncTask to send the HTTP Request in doInBackGround Method and fetch the JSON Response and update my local ArrayList of FlickrItems which I am going to use to update my GridView via the FlickrAdapter (extends the BaseAdapter) and call the adapter.notifyDataSetChanged() in the onPostExecute() of AsyncTask to reload the grid view. Note that here the HTTP Request is a blocking call because of which I have done it via the AsyncTask. And, I can cache the items in adapter to increase the performance or store them on SDCard. The grid that I will be inflating in the FlickrAdapter contains in my implementation a progressbar and image view. Below you can find the code for mainActivity which I used.

现在回答问题- 因此,一旦我们获得了用于获取单个图像的JSON数据,我们就可以实现通过Handlers或线程或AsyncTask在后台获取图像的逻辑。我们应该注意到,由于我的图像一旦下载就必须显示在UI/主线程上,我们不能简单地使用线程,因为它们不能访问上下文。 在FlickrAdapter中,我能想到的选择:

Choice 1: Create a LooperThread [extends thread] - and keep on downloading images sequentially in one thread by keeping this thread open [looper.loop()] Choice 2: Make use of a Thread Pool and post the runnable via myHandler which contains reference to my ImageView, but since the views in Grid View are recycled, again the problem might arise where image at index 4 is displayed at index 9 [download may take more time] Choice 3 [I used this]: Make use of a Thread Pool and send a message to myHandler, which contains data related to ImageView's index and ImageView itself, so while doing handleMessage() we will update the ImageView only if currentIndex matches the index of the Image we tried to download. Choice 4: Make use of AsyncTask to download the images in background, but here I will not have access to the number of threads I want in the thread pool and it varies with different android version, but in Choice 3 I can make of conscious decision of the size of thread pool depending on device configuration being used.

以下是源代码:

public class MainActivity extends ActionBarActivity {

    GridView imageGridView;
    ArrayList<FlickrItem> items = new ArrayList<FlickrItem>();
    FlickrAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageGridView = (GridView) findViewById(R.id.gridView1);
        adapter = new FlickrAdapter(this, items);
        imageGridView.setAdapter(adapter);
    }

    // To avoid a memory leak on configuration change making it a inner class
    class FlickrDownloader extends AsyncTask<Void, Void, Void> {



        @Override
        protected Void doInBackground(Void... params) {
            FlickrGetter getter = new FlickrGetter();

            ArrayList<FlickrItem> newItems = getter.fetchItems();

            // clear the existing array
            items.clear();

            // add the new items to the array
            items.addAll(newItems);

            // is this correct ? - Wrong rebuilding the list view and should not be done in background
            //adapter.notifyDataSetChanged();

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            adapter.notifyDataSetChanged();
        }

    }

    public void search(View view) {
        // get the flickr data
        FlickrDownloader downloader = new FlickrDownloader();
        downloader.execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

我希望我的回答虽然很长,但将有助于理解一些更精细的细节。


就像Vogella网站上关于Android后台处理的教程,AsyncTask和Loaders一样:

Handler类可用于注册到线程,并提供一个简单的通道将数据发送到该线程。

AsyncTask类封装了后台进程的创建和与主线程的同步。它还支持报告正在运行的任务的进度。

线程基本上是多线程的核心元素,开发人员使用它有以下缺点:

如果您使用Java线程,则必须处理以下需求 在你自己的代码中: 如果将结果返回到用户界面,则与主线程同步 没有取消线程的默认值 没有默认线程池 Android中没有处理配置更改的默认值

关于AsyncTask,正如Android开发者参考所说:

AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers. AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.

2015年5月更新:我找到了一个涵盖这个主题的优秀系列讲座。

这是谷歌搜索:道格拉斯施密特讲座android并发和同步 这是YouTube上第一节课的视频 所有这些都是来自范德堡大学的CS 282 (2013): Android系统编程的一部分。这是YouTube播放列表 道格拉斯·施密特似乎是个出色的讲师

重要提示:如果你正在考虑使用AsyncTask来解决线程问题,你应该首先检查ReactiveX/RxAndroid,以获得更合适的编程模式。有一个很好的资源可以让你得到一个概览,那就是学习RxJava 2 for Android的例子。


处理器——线程之间的通信媒介。在android中,它主要用于通过处理器创建和发送消息来与主线程通信

AsyncTask -用于在后台线程中执行长时间运行的应用程序。使用nAsyncTask,你可以在后台线程中执行操作,并在应用程序的主线程中获得结果。

Thread -是一个轻量级的进程,可以实现并发性和最大的cpu利用率。在android中,你可以使用线程来执行不触及应用程序UI的活动


public class RequestHandler {

    public String sendPostRequest(String requestURL,
                                  HashMap<String, String> postDataParams) {

        URL url;

        StringBuilder sb = new StringBuilder();
        try {
            url = new URL(requestURL);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(15000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);


            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(os, "UTF-8"));
            writer.write(getPostDataString(postDataParams));

            writer.flush();
            writer.close();
            os.close();
            int responseCode = conn.getResponseCode();

            if (responseCode == HttpsURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                sb = new StringBuilder();
                String response;
                while ((response = br.readLine()) != null){
                    sb.append(response);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (first)
                first = false;
            else
                result.append("&");

            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }

        return result.toString();
    }

}

线程:

你可以在不影响UI线程的情况下使用新的线程来执行长期运行的后台任务。从java线程,你不能更新UI线程。

由于普通线程在Android架构中用处不大,因此引入了线程的辅助类。

您可以在线程性能文档页面中找到查询的答案。

处理程序:

Handler允许您发送和处理与线程的MessageQueue关联的Message和Runnable对象。每个Handler实例都与单个线程和该线程的消息队列相关联。

Handler有两个主要用途:

将消息和可运行程序安排在未来的某个时间点执行; 将要在与自己的线程不同的线程上执行的操作排队。

AsyncTask:

AsyncTask允许正确和简单地使用UI线程。该类允许您执行后台操作并在UI线程上发布结果,而无需操作线程和/或处理程序。

缺点:

默认情况下,应用程序将它创建的所有AsyncTask对象推入一个线程。因此,它们以串行方式执行,与主线程一样,一个特别长的工作包会阻塞队列。由于这个原因,使用AsyncTask来处理持续时间短于5毫秒的工作项。 AsyncTask对象也是隐式引用问题的最常见的肇事者。AsyncTask对象也存在与显式引用相关的风险。

HandlerThread:

您可能需要一种更传统的方法来在长时间运行的线程上执行工作块(不像AsyncTask,它应该用于5ms的工作负载),并且需要一些手动管理工作流的能力。处理程序线程实际上是一个长时间运行的线程,它从队列中获取工作并对其进行操作。

ThreadPoolExecutor:

该类管理一组线程的创建,设置它们的优先级,并管理如何在这些线程之间分配工作。随着工作负载的增加或减少,该类将启动或销毁更多的线程以适应工作负载。

如果工作负载比较大,单个HandlerThread不够用,那么可以使用ThreadPoolExecutor

然而,我想有一个套接字连接运行在服务。这应该运行在一个处理程序或线程,甚至一个AsyncTask?UI交互根本不需要。它对我使用的性能有影响吗?

因为UI交互不是必需的,你可能不需要AsyncTask。普通线程用处不大,因此HandlerThread是最好的选择。因为你必须维护套接字连接,主线程上的Handler一点用都没有。创建一个HandlerThread并从HandlerThread的循环程序中获取一个Handler。

 HandlerThread handlerThread = new HandlerThread("SocketOperation");
 handlerThread.start();
 Handler requestHandler = new Handler(handlerThread.getLooper());
 requestHandler.post(myRunnable); // where myRunnable is your Runnable object. 

如果希望与UI线程通信,可以使用另外一个Handler来处理响应。

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Foreground task is completed:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

在Runnable中,您可以添加

responseHandler.sendMessage(msg);

关于实现的更多细节可以在这里找到:

Android:在线程中吐司


线程

当你启动一个应用程序时,会创建一个进程来执行代码。为了有效地利用计算资源,可以在进程内启动线程,以便同时执行多个任务。所以线程允许你通过有效地利用cpu而没有空闲时间来构建高效的应用程序。

在Android中,所有组件都在一个称为主线程的线程上执行。Android系统将任务排队,并在主线程中逐个执行。当长时间运行的任务执行时,应用程序变得无响应。

为了防止这种情况,您可以创建工作线程并运行后台或长时间运行的任务。

由于android使用单线程模型,UI组件是创建非线程安全的,这意味着只有它创建的线程应该访问它们,这意味着UI组件应该只在主线程上更新。由于UI组件运行在主线程上,运行在工作线程上的任务不能修改UI组件。这就是Handler出现的地方。Handler在Looper的帮助下可以连接到新线程或现有线程,并在连接的线程上运行它包含的代码。

处理器使线程间通信成为可能。后台线程可以通过Handler将结果发送给后台线程,连接到主线程的Handler可以更新主线程上的UI组件。

AsyncTask

AsyncTask提供的android使用线程和处理程序,使运行简单的任务在后台和更新结果从后台线程到主线程容易。

请参见android thread, handler, asynctask和线程池的例子。


这取决于选择哪一个是基于需求的

Handler主要用于从其他线程切换到主线程,Handler附加到一个循环器,它在队列中发布其可运行任务。 所以如果你已经在其他线程和切换到主线程,那么你需要处理而不是异步任务或其他线程

如果在主线程之外创建的Handler不是一个looper,则不会在线程创建Handler时给出错误,该线程需要被创建为lopper

AsyncTask用于执行在后台线程上运行的代码,并将其结果传递给主线程 ** *异步任务限制 1. 异步任务不附加到活动的生命周期,即使它的活动被破坏,它也会继续运行,而加载器没有这个限制 2. 所有异步任务共享相同的后台线程执行,这也会影响应用程序的性能

线程在应用程序中用于后台工作,但它在主线程上没有任何回调。 如果要求适合一些线程,而不是一个线程,需要给任务很多次,那么线程池执行器是更好的选择。Eg要求图像加载从多个url像滑翔。