Flex4 - 多线程讲解及开发实例
作者:hangge | 2014-12-04 10:27
1,从Flash Player11.4开始,adobe终于提供了这个众望所归的api - 多线程。
通过使用AS3 Workers让创建真正的多线程应用变得非常简单,只需要几行代码即可。worker的原理是在你主SWF里运行的另一个SWF程序,从而实现多线程效果。
通过使用AS3 Workers让创建真正的多线程应用变得非常简单,只需要几行代码即可。worker的原理是在你主SWF里运行的另一个SWF程序,从而实现多线程效果。
2,使用案例
代码在做某些工作时花了很长时间不说,还因为它让你的用户界面暂停了或是运行的非常卡时,就可以把他当做多线程了。尤其是如果某些代码你仅需要在后台执行。下面有些具体例子:
(1)文字/数据处理(例如:幻灯片加载一个Xml文件,循环一遍,遍历出所有子节点创建图形。)
(2)可视/图像/音频数据处理(例如:任何一个不需要用PixelBender的图片处理算法。)。
(3)在后台运行物理引擎。
代码在做某些工作时花了很长时间不说,还因为它让你的用户界面暂停了或是运行的非常卡时,就可以把他当做多线程了。尤其是如果某些代码你仅需要在后台执行。下面有些具体例子:
(1)文字/数据处理(例如:幻灯片加载一个Xml文件,循环一遍,遍历出所有子节点创建图形。)
(2)可视/图像/音频数据处理(例如:任何一个不需要用PixelBender的图片处理算法。)。
(3)在后台运行物理引擎。
3,开发环境
(1)flash player版本最低建议选择11.5.0
(2)编译参数增加 -swf-version=17
(3)flash builder建议选择4.7版本,因为从4.7版本开始,编辑器提供新建“ActionScript Worker”的功能。
比如我们新建一个叫“MyWorker”的worker,编辑器会自动创建如下图的文件:
4,简单的例子(主应用发消息给子线程,子线程收到消息回复,主线程把回复消息打印出来)
--- 主应用 Main.mxml ---
5,接收多个消息,多个数据(主线程发送add命令及两个参数,子线程获取后相加返回)
--- 主线程interval函数 ---
6,使用byteArray.shareable
传输数据最快的方式就是根本不传输它!Adobe给我们提供可以直接共享ByteArray对象的途径。这是非常强大的,因为我们几乎可以在ByteArray里存储任何数据。
要共享一个byteArray对象,你需要设置byteArray.shareable=true,然后调用messageChannel.send(byteArray)或者worker.setSharedPropert(“byteArray”, byteArray)方法来共享它。
一旦你的byteArray对象是共享的,你可以直接对它写入数据,然后在另一端从它上面直接读取
要把一个对象转换成byteArray,最简单的是使用byteArray.writeObject(myArrayOfObjects)方法即可。不幸的是,这个方法非常慢,最快的方式是手动封装你的数据到ByteArray,我们直接写入Number和String的值到ByteArray对象,而不是写入每个Object。
7,新的BitmapData.copyPixelsToByteArray方法,可以用来快速转换bitmapData到ByteArray。
比如一些费cpu的图像处理操作,我们可以把BitmapData转换成ByteArray来给子线程进行处理。例子如下:
--- 主线程 ---
(1)flash player版本最低建议选择11.5.0
(2)编译参数增加 -swf-version=17
(3)flash builder建议选择4.7版本,因为从4.7版本开始,编辑器提供新建“ActionScript Worker”的功能。
比如我们新建一个叫“MyWorker”的worker,编辑器会自动创建如下图的文件:

--- 主应用 Main.mxml ---
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="init(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected var worker:Worker;
protected var mainToWorker:MessageChannel;
protected var workerToMain:MessageChannel;
protected function init(event:FlexEvent):void
{
//创建worker
worker = WorkerDomain.current.createWorker(Workers.MyWorker);
//为两个方向通信分别创建MessagingChannel
mainToWorker = Worker.current.createMessageChannel(worker);
workerToMain = worker.createMessageChannel(Worker.current);
//注入MessagingChannel实例作为一个共享对象
worker.setSharedProperty("mainToWorker", mainToWorker);
worker.setSharedProperty("workerToMain", workerToMain);
//监听来自Worker的事件
workerToMain.addEventListener(Event.CHANNEL_MESSAGE, onWorkerToMain);
//启动worker(重新实例化文档类)
worker.start();
//设置时间间隔定时worker发送消息
setInterval(function():void{
mainToWorker.send("HELLO");
textArea.text +="[Main] HELLO" +"\n";
}, 1000);
}
//从worker线程接收信息
protected function onWorkerToMain(event:Event):void {
//打印输出worker里接收到的任何消息
textArea.text +="[Worker] " + workerToMain.receive() +"\n";
}
]]>
</fx:Script>
<s:TextArea id="textArea" width="100%" height="100%"/>
</s:Application>
--- 子线程 MyWorker.as ---
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.system.MessageChannel;
import flash.system.Worker;
public class MyWorker extends Sprite
{
protected var mainToWorker:MessageChannel;
protected var workerToMain:MessageChannel;
public function MyWorker()
{
super();
//在worker内部,我们可以使用静态方法获取共享的messgaeChannel对象
mainToWorker = Worker.current.getSharedProperty("mainToWorker");
workerToMain = Worker.current.getSharedProperty("workerToMain");
//监听来自主线程的事件
mainToWorker.addEventListener(Event.CHANNEL_MESSAGE, onMainToWorker);
}
//从主线程接收信息
protected function onMainToWorker(event:Event):void {
var msg:* = mainToWorker.receive();
//当主线程给我们发送"HELLO"时,我们返回"WORLD"
if(msg == "HELLO"){
workerToMain.send("WORLD");
}
}
}
}
运行结果:

--- 主线程interval函数 ---
//设置一个时间间隔让Worker线程做一些数学计算
setInterval(function(){
mainToWorker.send("ADD");
mainToWorker.send(2);
mainToWorker.send(2);
trace("[Main] ADD 2 + 2?");
}, 1000);
--- 子线程监听函数 ---
protected function onMainToWorker(event:Event):void {
var msg:* = mainToWorker.receive();
if(msg == "ADD"){
//接收到两个值,然后把它们相加
var val1:int = mainToWorker.receive();
var val2:int = mainToWorker.receive();
//返回计算结果给主线程
workerToMain.send(val1 + val2);
}
}
传输数据最快的方式就是根本不传输它!Adobe给我们提供可以直接共享ByteArray对象的途径。这是非常强大的,因为我们几乎可以在ByteArray里存储任何数据。
要共享一个byteArray对象,你需要设置byteArray.shareable=true,然后调用messageChannel.send(byteArray)或者worker.setSharedPropert(“byteArray”, byteArray)方法来共享它。
一旦你的byteArray对象是共享的,你可以直接对它写入数据,然后在另一端从它上面直接读取
要把一个对象转换成byteArray,最简单的是使用byteArray.writeObject(myArrayOfObjects)方法即可。不幸的是,这个方法非常慢,最快的方式是手动封装你的数据到ByteArray,我们直接写入Number和String的值到ByteArray对象,而不是写入每个Object。
示例如下:
--- 主线程 ---
//创建共享的ByteArray对象
positionBytes = new ByteArray();
positionBytes.shareable = true;
worker.setSharedProperty("positionBytes", positionBytes);
/**接收worker发过来的消息**/
protected function onMessageFromWorker(event:flash.events.Event):void {
var msg:String = channelToMain.receive();
if(msg == "complete"){
//从byteArray对象里读取更新后的位置信息
var s:Crate;
var ba:ByteArray = positionBytes;
positionBytes.position = 0;
var id:String;
while(positionBytes.bytesAvailable){
//从byteArray对象里读取SpriteID
id = ba.readUTFBytes(ba.readInt());
//更新在屏幕上的Sprite位置
s = spritesById[id];
s.x = ba.readInt();
s.y = ba.readInt();
s.rotation = ba.readInt() * Math.PI / 180;
}
}
}
--- 子线程 ---
//获取共享的ByteArray对象
positionBytes = Worker.current.getSharedProperty("positionBytes");
/**
* 复制NapeSprites的位置信息到byteArray
**/
protected function onEnterFrame(event:Event):void {
var ba:ByteArray = positionBytes;
ba.position = 0;
for(var i:int = 0, l:int = sprites.length; i < l; i++){
ba.writeInt(sprites[i].id.length);
ba.writeUTFBytes(sprites[i].id);
ba.writeInt(sprites[i].x);
ba.writeInt(sprites[i].y);
ba.writeInt(sprites[i].rotation);
}
//通知主线程COMPLETE
channelToMain.send("complete");
}
比如一些费cpu的图像处理操作,我们可以把BitmapData转换成ByteArray来给子线程进行处理。例子如下:
--- 主线程 ---
//转换位图数据并存储到共享的byteArray对象里,与worker线程共享。
imageBytes = new ByteArray();
imageBytes.shareable = true;
origImage.copyPixelsToByteArray(origImage.rect, imageBytes);
worker.setSharedProperty("imageBytes", imageBytes);
//给worker传递初始化图像宽高尺寸
worker.setSharedProperty("imageWidth", origImage.width);
worker.setSharedProperty("imageHeight", origImage.height);
/**worker的完成任务时的响应函数**/
protected function onBackToMain(event:Event):void {
var msg:String = backToMain.receive();
if(msg == "SHARPEN_COMPLETE"){
imageBytes.position = 0;
image.bitmapData.setPixels(image.bitmapData.rect, imageBytes);
}
}
--- 子线程 ---
//从共享属性缓存池里获取位图数据。
imageBytes = worker.getSharedProperty("imageBytes");
var w:int = worker.getSharedProperty("imageWidth");
var h:int = worker.getSharedProperty("imageHeight");
imageBytes.position = 0;
imageData = new BitmapData(w, h, false, 0x0);
imageData.setPixels(imageData.rect, imageBytes);
/**响应主线程的请求**/
protected function onMainToBack(event:Event):void {
if(mainToBack.messageAvailable){
//获取消息类型
var msg:* = mainToBack.receive();
//锐化位图并复制它到byteArray对象里
var data:BitmapData = ImageUtils.SharpenImage(imageData, currentSharpen);
imageBytes.length = 0;
data.copyPixelsToByteArray(data.rect, imageBytes);
//通知主线程锐化操作已经完成
backToMain.send("SHARPEN_COMPLETE");
}
}
全部评论(0)