`
eric_weitm
  • 浏览: 243602 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

android中的多线程

阅读更多

android中的多线程

一、基于消息队列的handler机制,别的线程与自己进行交互,需要使用消息队列,这样可以实现功能的分离和处理的异步,

Android中对消息队列进行了封装,具体的:

1、Looper 负责维护并发安全的消息队列

2、handler 负责进行消息的入队、出队,以及消息的处理函数 void handleMessage(Message msg)

3、Message 是OS系统内抽象的数据结构

4、相互关系:handler操作的是具体Looper代表的消息队列(不指定时默认是当前线程的looper),并且每个线程有自己的消息队列,因此别的线程可以通过handler来操作主线程

  5、Loop.myLooper()得到当前线程的Looper对象,通过Loop.getMainLooper()可以获得当前进程的主线程的 Looper对象

6、注意:Looper对message的处理是同步的,即一个handler会阻塞别的looper,且会阻塞后面所有消息的处理,所以注意 handleMessage中不能有耗时的操作(可以做完后发送消息来实现)

7、post过去的Runnable是接口,不会再创建新的线程

8、Looper.Callback 以Runnable为接口

 

1、handler机制是常见的消息队列的方式,但是每个回调都是同步的,例子如下(代码来自网络,但不知道是谁写的):

 

package com.weitm.testhandler;

 

import android.os.Bundle;

import android.os.Handler;

import android.os.Looper;

import android.os.Message;

import android.app.Activity;

import android.graphics.Color;

import android.util.Log;

import android.view.Menu;

import android.widget.*;

import android.view.*;

import android.view.View.OnClickListener;

import android.view.ViewGroup.LayoutParams;

 

public class MainActivity extends Activity implements OnClickListener

{

  private String               TAG                  = "HandlerTest";

  private boolean              bpostRunnable        = false;

  private NoLooperThread       noLooperThread       = null;         // 普通线程

  private OwnLooperThread      ownLooperThread      = null;         // 有自己消息队列的线程

 

  private ReceiveMessageThread receiveMessageThread = null;         // 主线程内的子线程(拥有自己的消息队列)

  private Handler              mOtherThreadHandler  = null;         // 主线程内的子线程对应的handler

 

  private EventHandler         mHandler             = null;

 

  private Button               btn1                 = null;

  private Button               btn2                 = null;

  private Button               btn3                 = null;

  private Button               btn4                 = null;

  private Button               btn5                 = null;

  private Button               btn6                 = null;

  private TextView             tv                   = null;

 

  @Override

  protected void onCreate(Bundle savedInstanceState)

  {

super.onCreate(savedInstanceState);

 

LinearLayout layout = new LinearLayout(this);

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(250, 50);

layout.setOrientation(LinearLayout.VERTICAL);

btn1 = new Button(this);

btn1.setId(101);

btn1.setText("UI thread 发给自己");

btn1.setOnClickListener(this);

layout.addView(btn1, params);

 

btn2 = new Button(this);

btn2.setId(102);

btn2.setText("別人发给UI thread");

btn2.setOnClickListener(this);

layout.addView(btn2, params);

 

btn3 = new Button(this);

btn3.setId(103);

btn3.setText("别人发给自己msg");

btn3.setOnClickListener(this);

layout.addView(btn3, params);

 

btn4 = new Button(this);

btn4.setId(104);

btn4.setText("别人发给UI runnable");

btn4.setOnClickListener(this);

layout.addView(btn4, params);

 

btn5 = new Button(this);

btn5.setId(105);

btn5.setText("主线程发给自己的子线程");

btn5.setOnClickListener(this);

layout.addView(btn5, params);

 

btn6 = new Button(this);

btn6.setId(106);

btn6.setText("exit");

btn6.setOnClickListener(this);

layout.addView(btn6, params);

 

tv = new TextView(this);

tv.setTextColor(Color.RED);

tv.setText("");

params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);

params.topMargin = 10;

layout.addView(tv, params);

setContentView(layout);

 

    // 不使用默认的activity内的Looper和handler,而是使用自定义的,以便与主线程相区分

receiveMessageThread = new ReceiveMessageThread();

receiveMessageThread.start();

  }

 

  class ReceiveMessageThread extends Thread

  {

@Override

public void run()

{

 Looper.prepare(); // 有了自己的消息队列

 // 最直接的处理自己的消息队列,但是这个不同于主线程

 mOtherThreadHandler = new Handler() {

@Override

public void handleMessage(Message msg)

{

 // TODO Auto-generated method stub

 super.handleMessage(msg);

 Log.e(TAG, "-------+>" + (String) msg.obj);

 Log.e(TAG, "CurrentThread id:----------+>"+ Thread.currentThread().getId());

}

 };

 

 Log.e(TAG, "ReceiveMessageThread id:--------+>" + this.getId());

 Looper.loop(); // 开始事件循环

}

  }

 

  class NoLooperThread extends Thread

  {

private EventHandler mNoLooperThreadHandler;

 

@Override

public void run()

{

 Looper myLooper = Looper.myLooper();

 Looper mainLooper = Looper.getMainLooper();

 String msgobj;

 

 if (null == myLooper)

 {

// 这里获得的是主线程的Looper,由于NoLooperThread没有自己的looper所以这里肯定会被执行

mNoLooperThreadHandler = new EventHandler(mainLooper);

msgobj = "NoLooperThread has no looper and handleMessage function executed in main thread!";

 } else

 {

mNoLooperThreadHandler = new EventHandler(myLooper);

msgobj = "This is from NoLooperThread self and handleMessage function executed in NoLooperThread!";

 }

 

 mNoLooperThreadHandler.removeMessages(0);

 

 if (bpostRunnable == false)

 {

// send message to main thread

Message msg = mNoLooperThreadHandler.obtainMessage(2, 1, 1, msgobj);

mNoLooperThreadHandler.sendMessage(msg);

Log.e(TAG, "NoLooperThread id:--------+>" + this.getId());

 } else

 {

// 下面new出来的实现了Runnable接口的对象中run函数是在Main

// Thread中执行,不是在NoLooperThread中执行 记得 null == myLooper么

// 注意Runnable是一个接口,它里面的run函数被执行时不会再新建一个线程

// 您可以在run上加断点然后在eclipse调试中看它在哪个线程中执行

mNoLooperThreadHandler.post(new Runnable() {

 public void run()

 {

// TODO Auto-generated method stub

tv.setText("update UI through handler post runnalbe mechanism!");

// 这里打印出来的是main thread的线程id,也就是说Runnable在handler机制中只是作为回调接口

// 并没有创建新的线程

Log.e(TAG, "update UI id:--------+>"+ Thread.currentThread().getId());

noLooperThread.stop();

 }

 

}); // end of post

 } // end of else

}

  }

 

  class EventHandler extends Handler

  {

public EventHandler(Looper looper)

{

 super(looper);

}

 

public EventHandler()

{

 super();

}

 

@Override

public void handleMessage(Message msg)

{

 // TODO Auto-generated method stub

 super.handleMessage(msg);

 Log.e(TAG, "CurrentThread id:----------+>" + Thread.currentThread().getId());

 

 switch (msg.what)

 {

 case 1:

tv.setText((String) msg.obj);

break;

 

 case 2:

tv.setText((String) msg.obj);

noLooperThread.stop();

break;

 

 case 3:

// 不能在非主线程的线程里面更新UI,所以这里通过log打印信息

Log.e(TAG, (String) msg.obj);

ownLooperThread.stop();

break;

 

 default:

Log.e(TAG, (String) msg.obj);

break;

 }

}

  }

 

  class OwnLooperThread extends Thread

  {

private EventHandler mOwnLooperThreadHandler = null;

 

@Override

public void run()

{

 Looper.prepare();

 Looper myLooper = Looper.myLooper();

 Looper mainLooper = Looper.getMainLooper();

 String msgobj;

 

 if (null == myLooper)

 {

mOwnLooperThreadHandler = new EventHandler(mainLooper);

msgobj = "OwnLooperThread has no looper and handleMessage function executed in main thread!";

 

 } else

 {

mOwnLooperThreadHandler = new EventHandler(myLooper);

msgobj = "This is from OwnLooperThread self and handleMessage function executed in !";

 }

 

 mOwnLooperThreadHandler.removeMessages(0);

 

 // 给自己发送消息

 Message msg = mOwnLooperThreadHandler.obtainMessage(3, 1, 1, msgobj);

 mOwnLooperThreadHandler.sendMessage(msg);

 

 // 开始循环

 Looper.loop();

}

  }

 

  public void onClick(View v)

  {

switch (v.getId())

{

case 101:

 // 主线程发送消息给自己

 Looper looper = Looper.myLooper();// get the Main looper related with the

// main thread

 // 如果不给任何参数的话会用当前线程对应的Looper(这里就是Main Looper)为Handler里面的成员mLooper赋值

 mHandler = new EventHandler(looper);

 // 清除整个MessageQueue里的消息

 mHandler.removeMessages(0);

 String obj = "This main thread's message and received by itself!";

 // 消息号是1

 Message msg = mHandler.obtainMessage(1, 1, 1, obj);

 // 将Message对象送入到main thread的MessageQueue里面

 mHandler.sendMessage(msg);

 break;

 

case 102:

 bpostRunnable = false;

 noLooperThread = new NoLooperThread();

 noLooperThread.start();

 break;

 

case 103:

 tv.setText("please look at the error level log for other thread received message");

 ownLooperThread = new OwnLooperThread();

 ownLooperThread.start();

 break;

 

case 104:

 bpostRunnable = true;

 noLooperThread = new NoLooperThread();

 noLooperThread.start();

 break;

 

case 105:

 if (null != mOtherThreadHandler)

 {

tv.setText("这是主线程向自己的子线程发送消息");

String msgObj = "message from mainThread";

Message mainThreadMsg = mOtherThreadHandler.obtainMessage(1, 1, 1, msgObj);

 

mOtherThreadHandler.sendMessage(mainThreadMsg);

 }

 break;

 

case 106:

 finish();

 break;

}

  }

 

  @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;

  }

}

 

2、例子说明

   按钮依次演示了 主线程内的消息处理、子线程内的消息和runnable处理,以及往别的线程中发消息等操作,

并且重点区分了looper所对应的执行线程,以及handler所操作的具体线程等信息。

3、handler机制的问题

  一个looper上可以挂多个handler,且looper内的message是依次进行处理的,这样 同一个message上的handler之间会相互阻塞,而且前一个消息会阻塞后面消息的处理,

这里的阻塞的意思是说只能等着前一个结束了才能进行后一个,如果要实现不阻塞,则只能每个handler都在不同的线程中,这样的话很快就会出现线程太多拖慢系统的问题。

举个应用中的例子:假如我们的app可以允许从网上下载内容,则如果要同时支持多个下载,则必须同时开多个线程,如果同时app支持从远端数据库中查询数据,从淘宝中捞出数据,和别人实时交互... 这里的每一样都需要

开一个新的线程,所以如果app复杂一些,则会有性能问题。解决方案是AsyncTask机制。

 

二、AsyncTask机制

前面说了需要每个handler的回调是异步的,即每次调到这里时可以直接返回,而不是一直堵在那里,那么只能使用异步的消息了(底层是使用线程池来进行调度,所以不会有一个handler占一个线程的问题)。

1、基本的实现思路

异步的基本实现思路是 将每个需要执行的task排队,之后依次取出进行执行,在执行时检查是否完成,没有的话直接返回给监听线程,这样监听线程可以查看别的task执行的情况,这样从总体上来看

好像所有的消息都得到了照顾,但是实际上这个只是个假象,因为实际在干活的只能是有限的worker thread,而且道理上讲 线程越多,系统越慢。

2、AsyncTask的抽象数据结构

  抽象上讲,AsyncTask需要提供 输入的参数、更新时的参数、输出的参数等3个泛型的参数,为了实现异步需要提供 

 1、doInBackground(输入的参数) --- 实际干活的逻辑

 2、onProgressUpdate(更新时的参数类型) --- 主线程要使用的回调

 3、onPreExecute()                      ----- 初始化的工作

 4、onPostExecute(输出时的数据类型)  ------ 返回结果

3、可以使用的有用的函数 publishProgress(更新时的参数) --- 更新返回给调用线程的进度值

4、例子

package com.example.testasync;

 

import java.util.Random;

 

import android.R;

import android.app.Activity;

import android.os.AsyncTask;

import android.os.Bundle;

import android.util.Log;

import android.view.Menu;

import android.view.View;

import android.widget.Button;

import android.widget.LinearLayout;

import android.widget.ProgressBar;

import android.widget.TextView;

 

public class MainActivity1 extends Activity 

{

 

  private static final String TAG = "异步任务";

  private static final String URL = "http://www.google.com.hk/";

  private static final String STEP1 = "步骤1";

  private static final String STEP2 = "步骤2";

  private static final String STEP3 = "步骤3";

  private static final String STEP4 = "步骤4";

  

  private Button execute;

  private Button cancel;

  private ProgressBar progressBar;

  private TextView textView;

  

  private MyTask mTask;

  @Override

  protected void onCreate(Bundle savedInstanceState)

  {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_list_item);

 

LinearLayout layout = new LinearLayout(this);

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(250, 50);

layout.setOrientation(LinearLayout.VERTICAL);

execute = new Button(this);

execute.setId(101);

execute.setText("execute");

execute.setOnClickListener(new View.OnClickListener() {

      public void onClick(View v) {

              //注意每次需new一个实例,新建的任务只能执行一次,否则会出现异常

              mTask = new MyTask();

              mTask.execute(URL);

              

              execute.setEnabled(false);

              cancel.setEnabled(true);

      }

});

layout.addView(execute, params);

 

cancel = new Button(this);

cancel.setId(102);

cancel.setText("cancel");

 

layout.addView(cancel, params);

 

cancel.setOnClickListener(new View.OnClickListener() {

       public void onClick(View v) {

               //取消一个正在执行的任务,onCancelled方法将会被调用

               mTask.cancel(true);

       }

    });

 

    progressBar = new ProgressBar(this);

    layout.addView(progressBar, params);

    

    textView    = new TextView(this);

    layout.addView(textView, params);

    setContentView(layout);

  }

 

  @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;

  }

  

  // 参数依次是输入、更新、输出的参数类型,为了说明问题故意将更新的参数类型设置为string 而不是integer

  class MyTask extends AsyncTask<String, String, String> {

int times;

// onPreExecute方法用于在执行后台任务前做一些UI操作

protected void onPreExecute()

{

 Log.i(TAG, "onPreExecute() called");

 textView.setText("开始执行...");

}

 

// doInBackground方法内部执行后台任务,不可在此方法内修改UI

protected String doInBackground(String... params)

{

 Log.i(TAG, "doInBackground(Params... params) called");

 String result = "";

 

 try{

 

// 模拟消耗时间的操作

for (int j = 0; j < 15;j++)

{

Random random = new Random();

int i = Math.abs(random.nextInt())%4;

result = "步骤" + i;

Thread.sleep(1000);

 

// 本来发布出去的一般是进度,这里故意用string

publishProgress(result);

}

// 随机返回,如果不是 STEP1则显示75%,否则是100%

// 这里是用这个来模拟task内部状态的变化,类似于游戏内的状态机

 return result;

 }

 catch(Exception e)

 {

return null;

 }

}

 

// onProgressUpdate方法用于更新进度信息

protected void onProgressUpdate(String... progresses)

{

 Log.i(TAG, "onProgressUpdate(Progress... progresses) called");

 

 if (progresses[0].equals(STEP1) )

progressBar.setProgress(100);

 else

progressBar.setProgress(20);

 

 textView.setText("loading..." + progresses[0]);

}

 

// onPostExecute方法用于在执行完后台任务后更新UI,显示结果

// 这个result具体的值是由doInBackground来设置的

protected void onPostExecute(String result)

{

 Log.i(TAG, "onPostExecute(Result result) called");

 textView.setText(result);

 

 execute.setEnabled(true);

 cancel.setEnabled(false);

}

 

// onCancelled方法用于在取消执行中的任务时更改UI

protected void onCancelled()

{

 Log.i(TAG, "onCancelled() called");

 textView.setText("cancelled");

 progressBar.setProgress(0);

 

 execute.setEnabled(true);

 cancel.setEnabled(false);

}

}

 

}

 

5、说明 

  例子中演示了AsyncTask中 3个泛型参数的具体化,利用publishProgress实时的返回执行的情况,以及onProgressUpdate中实现的 操作异步化

  

三、内部实现猜测

  尽管AsyncTask内部应该是用线程池来实现的,但是在保证消息处理不被堵住的情况下,异步的方式可以省很多的线程,进而整体上效率会高一点。

这个和网游服务端的处理方式是一样的,实际上协程只是透明化的异步处理方式而已。

 

 

分享到:
评论

相关推荐

    Android中多线程的Handler原理

    Android中多线程的Handler的工作原理,其中涉及到MessageQueue和Looper。详情可以参见博客:http://www.cnblogs.com/plokmju/p/android_Looper.html

    Android中多线程下载原理实现案例

    总的来说,实现Android多线程下载涉及网络请求、线程管理、文件操作、数据同步等多个方面。开发者需要熟悉Android的并发编程模型,了解网络编程的基础知识,并掌握文件I/O的操作。通过这样的实践,不仅可以提高应用...

    Android中多线程机制的探究.pdf

    在Android应用开发中,多线程机制扮演着至关重要的角色,因为它们确保了应用程序的流畅性和响应性。Android系统默认情况下会让所有应用组件在同一个进程和线程中运行,即所谓的主线程或UI线程。这为主线程设计了一个...

    Android多线程文件上传

    本主题聚焦于"Android多线程文件上传",我们将探讨如何利用多线程技术来优化文件上传过程,提高效率,并确保应用的响应性。 一、多线程基础 多线程是并发执行多个任务的能力,它允许应用程序同时处理多个任务,提高...

    android中多线程下载实例

    代码如下: public class MainActivity extends Activity { // 声明控件 // 路径与线程数量 private EditText et_url, et_num; // 进度条 public static ProgressBar pb_thread; // 显示进度的操作 private TextView ...

    浅谈Android中多线程切换的几种方法

    浅谈Android中多线程切换的几种方法 本篇文章主要介绍了Android中多线程切换的几种方法,包括Thread、ThreadPool、Runnable、Callable、Future、Condition、Handler等方法。多线程切换是Android开发中必现的场景,...

    Android开发中的多线程编程技术

    ### Android开发中的多线程编程技术详解 #### 一、多线程编程的重要性与挑战 在Android开发过程中,多线程编程技术对于提高应用程序的性能和用户体验至关重要。...希望本文对您理解和应用Android多线程编程有所帮助。

    Android实现多线程下载

    在Android平台上,多线程下载是一项重要的技术,它允许应用程序同时从服务器获取数据,从而显著提高了文件下载的速度和效率。本教程将深入讲解如何在Android环境中实现多线程下载功能,以及涉及的相关知识点。 首先...

    android——多线程

    标题"android——多线程"和描述"android——Handler与多线程应用范例"暗示我们将深入探讨如何在Android中使用Handler来管理多线程。 Android系统默认运行在一个单线程环境中,即主线程,也被称为UI线程。主线程主要...

    Android多线程分段下载源码

    这个"Android多线程分段下载源码"实例是一个很好的学习资源,它实现了文件的分块下载,并允许用户自定义线程数来控制下载速度和效率。下面我们将详细探讨这一技术。 首先,我们要理解什么是分段下载。传统的单线程...

    Android JNI多线程编程回调JAVA函数

    本话题将深入探讨如何在Android中使用JNI进行多线程编程,并实现native方法对Java函数的回调。 1. **JNI基础知识**: - JNI是Java平台的一部分,为Java应用程序提供了与本地代码交互的能力。开发者可以通过JNI在...

    Android多线程操作

    标题"Android多线程操作"和描述"Android多线程开发实例,对使用多线程的用户有一定的参考价值!"暗示我们将深入探讨Android中的线程管理以及如何在实践中有效利用。 Android系统默认运行在主线程,也被称为UI线程,...

    Android多线程文件夹下载及断点续传

    多线程下载是将一个大文件分成多个部分,每个部分在一个单独的线程中下载。这样可以同时利用多个网络连接,提高下载速度。在`downloadDemo`项目中,可能包含以下关键点: 1. **任务分片**:根据文件大小,计算出每...

    android多线程后台下载

    android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序,android多线程后台下载示例程序

    android多线程下载

    通过以上步骤,我们可以实现一个功能完善的Android多线程下载器,它支持暂停、断点续传,并能够根据用户需求进行定制。在项目实践中,务必注意线程同步和数据一致性,以保证下载的正确性。 最后,提供的...

    Android中的多线程

    Android中多线程的使用,实现多线程对控件的控制,t1,t2测试

    android多线程机制

    ### Android多线程机制详解 #### 一、引言 Android多线程机制是Android开发中非常重要的一部分,尤其是在处理耗时任务(如网络请求、大数据处理等)时,避免阻塞UI线程,保证应用程序的流畅性和响应性。本文将详细...

Global site tag (gtag.js) - Google Analytics