展会信息港展会大全

android开发 Handler多进程之间的通信和数据交换
来源:互联网   发布日期:2016-01-19 12:24:18   浏览:2262次  

导读:说到Android的IPC(Inter-Process Conmmunication)首先想到的就是Handler和Looper,Handler用于多进程之间的通信和数据交换,将各进程之间通信的数据 Message放置到Message Queue里,而Looper用于创建各进程 ...

说到Android的IPC(Inter-Process Conmmunication)首先想到的就是Handler和Looper,Handler用于多进程之间的通信和数据交换,将各进程之间通信的数据 Message放置到Message Queue里,而Looper用于创建各进程自身的message queue,然后在适当的时候分发给相应的进程。

我们知道在Android中,每一个UI线程是一个主线程(Main Thread),Android为每一个主线程维护一个Message Queue,当用户需要长时间的背景线程操作的时候,需要create自己的new thread,这样的new thread是没有自己的message queue的,只能共享主线程的message queue并且将所做的运算结果和数据通过Handler发送到主线程的message queue里,被主线程共享。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<ProgressBar

android:id="@+id/ProgressBar01"

android:layout_width="150dip"

android:layout_height="wrap_content"

style="?android:attr/progressBarStyleHorizontal">

</ProgressBar>

</LinearLayout>

这个xml文件创建了一个progressbar,并且将style设置成水平,

style="?android:attr/progressBarStyleHorizontal

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="waterlife.ipc.demo"

android:versionCode="1"

android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">

<activity android:name=".IPCConmunication"

android:label="@string/app_name">

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

</application>

<uses-permission android:name="android.permission.INTERNET" />

</manifest>

为了访问网络,需要在manifest file里设置access internet的permission,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

<uses-permission android:name="android.permission.INTERNET" />

package waterlife.ipc.demo;

import java.io.InputStream;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Looper;

import android.os.Message;

import android.widget.ProgressBar;

public class IPCConmunication extends Activity {

static ProgressBar pb;

final int UPDATE_PROGRESS_BAR = 1000;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

pb = (ProgressBar)findViewById(R.id.ProgressBar01);

Download dl = new Download();

new Thread(dl).start();

}

Handler mHandle = new Handler()

{

public void handleMessage(Message msg)

{

switch(msg.what)

{

case UPDATE_PROGRESS_BAR:

pb.setProgress(msg.arg1);

break;

default:

break;

}

}

};

class Download implements Runnable

{

@Override

public void run() {

int totalSize = 0;

InputStream recevier = null;

try {

URL myUrl = new URL("http://bbs.nju.edu.cn");

URLConnection urlConn = myUrl.openConnection();

totalSize = urlConn.getContentLength();

recevier = urlConn.getInputStream();

byte[] b =new byte[256];

int length = 0;

length += recevier.read(b);

while(length < totalSize)

{

Message msg = mHandle.obtainMessage(UPDATE_PROGRESS_BAR);

msg.arg1 = (int)(length*100/totalSize);

if(mHandle.hasMessages(UPDATE_PROGRESS_BAR))

{

mHandle.removeMessages(UPDATE_PROGRESS_BAR);

}

mHandle.sendMessage(msg);

length += recevier.read(b);

Thread.sleep(1000);//睡眠1S,这个方法是不值得推荐的,因为它会使线程独占CPU,在以后的例子会使用更加有效的方法

}

recevier.close();

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}catch (Exception ex)

{

ex.printStackTrace();

}

}

}

}

我们create出来的一个new thread,用这个线程去网络上下载数据包,并且把下载的进度更新到UI主线程的progressbar上。两个线程之间的通信是用Handler来传 递的。在这里新的线程Download和UI main thread共用message queue。

当然,我们可以为自己新建的线程设置自身的message queue,方法如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

package waterlife.ipc.demo;

import java.io.InputStream;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.HandlerThread;

import android.os.Looper;

import android.os.Message;

import android.widget.ProgressBar;

public class IPCConmunication extends Activity {

static ProgressBar pb;

final int UPDATE_PROGRESS_BAR = 1000;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

pb = (ProgressBar)findViewById(R.id.ProgressBar01);

Download dl = new Download();

new Thread(dl).start();

}

class Download implements Runnable

{

@Override

public void run() {

int totalSize = 0;

InputStream recevier = null;

HandlerThread threadLoop = new HandlerThread("Download");

threadLoop.start();

Looper mLooper = threadLoop.getLooper();

Handler mHandle = new Handler(mLooper)

{

public void handleMessage(Message msg)

{

switch(msg.what)

{

case UPDATE_PROGRESS_BAR:

pb.setProgress(msg.arg1);

break;

default:

break;

}

}

};

try {

URL myUrl = new URL("http://bbs.nju.edu.cn");

URLConnection urlConn = myUrl.openConnection();

totalSize = urlConn.getContentLength();

recevier = urlConn.getInputStream();

byte[] b =new byte[256];

int length = 0;

length += recevier.read(b);

while(length < totalSize)

{

Message msg = mHandle.obtainMessage(UPDATE_PROGRESS_BAR);

msg.arg1 = (int)(length*100/totalSize);

if(mHandle.hasMessages(UPDATE_PROGRESS_BAR))

{

mHandle.removeMessages(UPDATE_PROGRESS_BAR);

}

mHandle.sendMessage(msg);

length += recevier.read(b);

Thread.sleep(1000);

}

recevier.close();

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}catch (Exception ex)

{

ex.printStackTrace();

}

}

}

}

HandlerThread是一个专门用于新建Looper的线程类,它实现了 Looper.prepare()和Looper.loop()的方法。HandlerThread ceate一个新的Looper并且绑定到新线程的Handler上,实现了对新线程创建自己的Message queue的目的。

对于Android的IPC来说,除了Handler和Looper之外,还有另外一种简便的方法来实现多线程的通信,那就是AsyncTask。 AsyncTask是一个异步的方法,它允许背景运算并把结果更新到前台的UI线程之上。要实现一个AsyncTask主要有4个步骤,但并不是每一个步 骤都是必需的。

这四个步骤是:

onPreExecute() 执行背景运算前任务的初始化;

doInBackground(Params...)这是AsyncTask最核心的函数,即是做背景运算;它在第一步完成之后被调用,通常在这步中还会 调用方法publishProgress(Progress...)将运算结果更新到UI主线程上;

onProgressUpdate(Progress...)是在publishProgress(Progress...)调用之后被执行的,需要注意 到是这步执行的时间是未定的,通常在这一步中会更新相关UI;

onPostExecute(Result)这一步同样是和UI相关,将运算结果Result当作参数传递给UI。

大家可能已经注意到AsyncTask除了四大步之外,还有三个重要的参数:AsyncTask。三个参数为通用类型,Params是传给任务初始化的参 数,Progress是做背景运算过程中和UI交互的参数,Result是背景运算传递给UI的结果。

利用好这四大步和三个参数,我们可以方便的写出上节例子中的Demo:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

package waterlife.ipc.demo;

import java.io.InputStream;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLConnection;

import android.app.Activity;

import android.os.AsyncTask;

import android.os.Bundle;

import android.widget.ProgressBar;

public class myAsyncTask extends Activity {

static ProgressBar pb;

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

pb = (ProgressBar)findViewById(R.id.ProgressBar01);

Download dl = new Download();

dl.execute();

}

public class Download extends AsyncTask<Void, Integer, Void>

{

@Override

protected Void doInBackground(Void... params) {

// TODO Auto-generated method stub

int totalSize = 0;

InputStream recevier = null;

try {

URL myUrl = new URL("http://bbs.nju.edu.cn/");

URLConnection urlConn = myUrl.openConnection();

totalSize = urlConn.getContentLength();

recevier = urlConn.getInputStream();

byte[] b =new byte[256];

int length = 0;

length += recevier.read(b);

while(length < totalSize)

{

length += recevier.read(b);

publishProgress((int)(length*100/totalSize));

}

recevier.close();

} catch (MalformedURLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}catch (Exception ex)

{

ex.printStackTrace();

}

return null;

}

protected void onProgressUpdate(Integer... progress) {

pb.setProgress(progress[0]);

}

}

}

在这个Demo中只有第二和第三步,只有第二个参数params,是一个整型参量,把下载数据包的进度 更新给UI Progressbar显示。

另外,使用AsyncTask需要注意以下几点:

AsyncTask的实例只能在UI线程中创建;

dl.execute()方法只能在UI线程中调用,并且只能调用一次,否则会抛异常。

原文作者: 军 Army.

原文地址: http://my.eoe.cn/1196982/archive/20809.html

赞助本站

人工智能实验室
AiLab云推荐
展开

热门栏目HotCates

Copyright © 2010-2024 AiLab Team. 人工智能实验室 版权所有    关于我们 | 联系我们 | 广告服务 | 公司动态 | 免责声明 | 隐私条款 | 工作机会 | 展会港