线程间通信-使用EventHandler下载网络图片

作者:韩茹

公司:程序咖(北京)科技有限公司

程序咖:IT职业技能评测平台

网址:https://www.chengxuka.com

前面我们已经搞明白了鸿蒙应用开发过程中的线程之间是如何通信的。就是利用EventHandlerInnerEventEventRunner等。

我们想实现的内容是,点击按钮进行下载网络上的图片,图片显示前先显示进度条。当图片下载完毕后,进度条消失,显示图片。

先来看一下效果:

downloadimageyunxing1

因为是在EventHandler这个Demo上随手写的,我没有重新创建工程。

一、XML布局

在layout目录下新建xml布局文件,demo4_eventhandler_image.xml,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:padding="20vp"

    ohos:orientation="vertical">

    <Button
        ohos:id="$+id:btn1"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="下载图片"
        ohos:background_element="#eeeeee"
        ohos:padding="20vp"
        ohos:text_size="20fp"
        />

    <RoundProgressBar
        ohos:id="$+id:round_progress_bar1"
        ohos:height="200vp"
        ohos:width="200vp"
        ohos:progress_width="10vp"
        ohos:top_margin="150vp"
        ohos:progress_hint_text="美女加载中"
        ohos:progress_hint_text_color="#C71585"
        ohos:layout_alignment="center"
        ohos:progress_color="#C71585"/>

    <Image
        ohos:id="$+id:image1"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:top_margin="30vp"
        ohos:layout_alignment="center"
        />

</DirectionalLayout>

这里我们先放好一个进度条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
    }
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值