作者:韩茹
公司:程序咖(北京)科技有限公司
程序咖:IT职业技能评测平台
前面我们已经搞明白了鸿蒙应用开发过程中的线程之间是如何通信的。就是利用EventHandler,InnerEvent,EventRunner等。
我们想实现的内容是,点击按钮进行下载网络上的图片,图片显示前先显示进度条。当图片下载完毕后,进度条消失,显示图片。
先来看一下效果:
因为是在EventHandler这个Demo上随手写的,我没有重新创建工程。
一、XML布局
在layout目录下新建xml布局文件,demo4_eventhandler_image.xml,代码如下:
这里我们先放好一个进度条RoundProgressBar,但是不让它显示。
二、AbilitySlice中的Java代码
我们在slice目录下新建一个AbilitySlice文件,FourAbilitySlice.java:
1、首先设置一下该AbilitySlice所对应的xml布局文件:
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_demo4_eventhandler_image);
}
2、首先应该先获取xml布局中的UI控件。定义一个初始化UI控件的方法,并在onStart()中进行调用。
public class FourAbilitySlice extends AbilitySlice{
private Image image;
private RoundProgressBar roundProgressBar;
private Button btn;
protected void onStart(Intent intent) {
...
initComponent();
}
// 获取UI组件
private void initComponent(){
btn= (Button) findComponentById(ResourceTable.Id_btn1);
image = (Image) findComponentById(ResourceTable.Id_image1);
roundProgressBar = (RoundProgressBar)findComponentById(ResourceTable.Id_round_progress_bar1);
}
}
3、定义一个内部类DownLoadImageEventHandler用于下载图片。
// step1:创建自定义的EventHandler子类
//1.创建自定义的EventHandler子类
private class DownLoadImageEventHandler extends EventHandler{
//2.添加构造方法
public DownLoadImageEventHandler(EventRunner runner) {
super(runner);
}
//3.重写processEvent()方法
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
}
}
}
4、创建一个方法,用于初始化EventRunner和EventHandler对象,并在onStart()中进行调用:
//step2:示例化EventHandler和EventRunner对象,并在onStart()方法中调用该初始化方法。
private void initHandler() {
eventRunner = EventRunner.create("TestRunner");
handler = new DownLoadImageEventHandler(eventRunner);
}
onStart()方法:
protected void onStart(Intent intent) {
...
initComponent();
initHandler();
}
5、给按钮添加点击事件,发送InnerEvent到子线程:
// 先定义全局变量
private static final int EVENT_MESSAGE_NORMAL = 1;
onStart()中为按钮添加点击事件:
//点击按钮,下载图片
btn.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
// step3:发送事件到子线程
long param = 0;
InnerEvent innerEvent = InnerEvent.get(EVENT_MESSAGE_NORMAL, param, EventRunner.current());
handler.sendEvent(innerEvent, EventHandler.Priority.IMMEDIATE);
System.out.println("UI线程-->InnerEvent已发送。。");
roundProgressBar.setVisibility(Component.VISIBLE);
}
});
6、接下来我们就该去进行网络操作了。重写DownLoadImageEventHandler中的processEvent()方法。
我们先捋顺一下思路:
1,应该先设置一个图片地址
2,创建URL对象
3,通过HttpURLConnection链接下载图片
4,因为我们需要边下载边显示进度条,所以应该先获取图片的总长度
5,下载图片的同时,计算已经下载的数据量,除以总长度,就是进度条的百分比,我们需要将这个数据回传给UI线程,进行设置进度条。当然这一步也需要使用EventHandler对象。
6,当图片下载完毕后,我们应该将下载到的字节数组的数据,编码成一个图片对象PixelMap。
7,将图片对象回传给UI线程,显示图片,并且让进度条消失。
大概,就这么个思路
这里还要强调一下,因为目前的网络再怎么烂,下载一张图片也是嗖嗖的,所以为了能够让进度条显示一会儿,我边下载边睡眠。
示例代码:
//3.重写processEvent()方法
@Override
protected void processEvent(InnerEvent event) {
super.processEvent(event);
if (event == null) {
return;
}
switch (event.eventId){
// step4:子线程中处理网络下载
case EVENT_MESSAGE_NORMAL:
//下载网络图片
try {
System.out.println("----开始网络下载---");
URL url = new URL(IMAGE_PATH);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
if(connection.getResponseCode()==HttpURLConnection.HTTP_OK){
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
//获取总长度
long total = connection.getContentLengthLong();
System.out.println("total---->"+total);
byte[] bs = new byte[1024];
int len =0;
long sum = 0;
//将图片回传到UI线程,设置在Image上
EventRunner runner = (EventRunner) event.object;
while((len=inputStream.read(bs))!=-1){
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
baos.write(bs, 0, len);
sum += len;
long percent = sum*100 / total;
System.out.println("percent-->"+percent);
//回传UI线程
EventHandler eventHandler = new EventHandler(runner) {
@Override
protected void processEvent(InnerEvent event) {
int data = (int)event.param;
roundProgressBar.setProgressValue(data);
}
};
int testEventId = 1;
long testParam = percent;
Object testObject = null;
InnerEvent innerEvent = InnerEvent.get(testEventId, testParam, testObject);
eventHandler.sendEvent(innerEvent);
}
byte[] data = baos.toByteArray();
System.out.println("图片数据。。"+data.length);
//处理图片数据
ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
srcOpts.formatHint = "image/png";
ImageSource imageSource = ImageSource.create(data,srcOpts);
ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();
PixelMap pixelMap = imageSource.createPixelmap(decodingOpts);
EventHandler eventHandler = new EventHandler(runner) {
@Override
protected void processEvent(InnerEvent event) {
//循环下载数据结束后:隐藏掉进度条
roundProgressBar.setVisibility(Component.HIDE);
PixelMap pixelMap = (PixelMap) event.object;
System.out.println("--->>>>>>>test:"+data);
image.setPixelMap(pixelMap);
}
};
int testEventId = 1;
long testParam = 0;
Object testObject = pixelMap;
InnerEvent innerEvent = InnerEvent.get(testEventId, testParam, testObject);
eventHandler.sendEvent(innerEvent);
System.out.println("---------");
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
三、设置网络访问权限
因为我们有访问网络,所以要在配置文件中添加访问网络的权限。打开config.json。
{
"app": {
"bundleName": "com.example.hanrueventhandler",
"vendor": "example",
"version": {
"code": 1000000,
"name": "1.0.0"
},
"apiVersion": {
"compatible": 4,
"target": 5,
"releaseType": "Release"
}
},
"deviceConfig": {},
"module": {
"package": "com.example.hanrueventhandler",
"name": ".MyApplication",
"deviceType": [
"phone"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "entry",
"moduleType": "entry"
},
"abilities": [
{
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
],
"orientation": "unspecified",
"name": "com.example.hanrueventhandler.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "$string:app_name",
"type": "page",
"launchType": "standard"
}
],
"reqPermissions": [
{
"name": "ohos.permission.GET_NETWORK_INFO"
},
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.SET_NETWORK_INFO"
}
]
}
}
最后几行就是网络的权限了。
最后修改一下程序的入口:
public class MainAbility extends Ability {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setMainRoute(FourAbilitySlice.class.getName());//要显示的哪个AbilitySlice
}
}