普通视图

发现新文章,点击刷新页面。
昨天以前首页

HarmonyOS Next鸿蒙开发:下载文件

2025年1月17日 07:48

我们做项目过程中难免会有下载文件的场景,那么下载文件会涉及到一个是文件保存到DocumentViewPicker选择器,还有文件流保存的知识。

选择目录组件

项目业务需求中,有选择文件的需求。 选择文件,系统提供了DocumentViewPicker.save()方法。

 //直接强转为文件流数据
  let dvp=new picker.DocumentViewPicker()
   //打开保存文件操作
  let result= await dvp.save({newFileNames:[Date.now()+'1.png']})

我这里是用到了axios的网络请求下载,当然也可以用官方的http请求方式进行网络请求,需要增加网络请求权限,axios安装也很简单。

网络请求

 安装axios
 ohpm i @ohos/axios 

网络申请权限,在resource目录下的module.json5文件下module节点下添加即可。

"requestPermissions":[
    {
       "name":"ohos.permission.INTERNET"
    }
 ]

文件流-保存文件

关于文件流的介绍请点击官方查看,这里要注意就是看是否更新,因鸿蒙发展很快,有很多时候,不注意看,就用旧的组件,比如官方不推荐@ohos.fileio,而推荐@ohos.file.fs

image.png

保存文件

let f = fs.openSync(path,fs.OpenMode.CREATE|fs.OpenMode.WRITE_ONLY)
fs.writeSync(f.fd,res.data)
fs.closeSync(f)//关闭文件

完整代码

import axios, { AxiosResponse } from '@ohos/axios';
import { fileIo as fs, picker } from '@kit.CoreFileKit';
import promptAction from '@ohos.promptAction';

@Entry
@Component
struct DownloadPage {
  @State message: string = 'Hello World';

  @State isShowProgress: boolean = false;


  build() {
    Row() {
      Column() {

        Button("下载").onClick(async ()=>{
          console.log("1")
          let res:AxiosResponse=await axios(
           // "http://m804.music.126.net/20241117075918/8d6bdbcd1b021f293361ea41f50f9f17/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/9444693488/94b2/45cb/21d6/9e34cbd9902ee8a917e6d0781557b94e.mp3?authSecret=000001933753cb5d08d80a3b19341b18"
            "https://pic.rmb.bdstatic.com/bjh/c305e5a85f66835661f880b24b9876be9233.png"
          )
          //直接强转为文件流数据
          let dvp=new picker.DocumentViewPicker()
          //打开保存文件操作
          let result= await dvp.save({newFileNames:[Date.now()+'1.png']})

          let path=result[0]
          let f = fs.openSync(path,fs.OpenMode.CREATE|fs.OpenMode.WRITE_ONLY)
          fs.writeSync(f.fd,res.data)
          fs.closeSync(f)//关闭文件
          console.log("保存路径为::"+JSON.stringify(result))
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}

image.png

选择文件保存路径:

image.png

打开文件夹-下载目录可以看到下载的图片了 image.png

直接在模拟器上预览图 image.png

HarmonyOS Next鸿蒙开发:数组里面改变对象进行刷新UI视图

2025年1月16日 22:59

有时候我们需要对数组里面数据进行改变,然后进行刷新UI视图,其实也可以用自定义组件和状态变量来做,但是还是有涉及到内存拷贝到情况,这里我们尝试不同的做法,使用内存拷贝来实现下。

问题:在List中点击item项的变量,item属性isLove状态发生改变,但是ui没有刷新 通常在其他语言中可以直接赋值进行改变,所以我们有个误区,就在改变完元数据Bean的状态后,直接需要给List从新赋值,但是没有效果。 通常在点击事件中重新赋值

btnSubmt(item: Item): void {
  item.isLove = !item.isLove
  console.log(" " + item.isLove)

解决办法:使用内存浅拷贝,当然有内存浅拷贝就有内存深拷贝

this.items = [...this.items] //把值赋回去,这样子新开了一个内存浅拷贝,0层级的变化 系统会检测到allList数据发生变化,ui也会重新绘制

理论概述:

浅拷贝:

  • 在堆中为新对象重新创建内存空间。
  • 基本数据类型的值被直接拷贝,互不影响。
  • 引用类型的内存地址被拷贝,因此拷贝前后的对象共享相同的引用类型数据。
  • 修改共享引用类型的数据会影响所有指向该数据的对象。

深拷贝:

  • 完整地从内存中拷贝一个对象,包括其所有属性和嵌套的对象。
  • 在堆内存中开辟新的区域来存储新对象,确保新对象和原始对象完全独立。
  • 修改新对象不会影响原始对象,反之亦然。

对象赋值:

  • 当一个对象赋值给新变量时,实际上复制的是对象在栈中的内存地址,而不是堆中的数据。
  • 两个变量指向同一个堆内存空间,对一个变量的修改会影响另一个变量,因为它们共享存储空间。

完整代码如下:


import Item from '../case/mall/viewmodels/Item';
import promptAction from '@ohos.promptAction'

@Entry
@Component
struct ArrayCopyPage {
  // 数据
  @State items: Array<Item> = [
    new Item('好友1', $r('app.media.head5'), 0, 0, false, "", ""),
    new Item('好友2', $r('app.media.head1'), 0, 0, false, "", ""),
    new Item('好友3', $r('app.media.head3'), 0, 0, false, "", ""),
    new Item('好友6', $r('app.media.head6'), 0, 0, false, "", "")
  ]

  build() {
    Column({ space: 8 }) {
      Row() {
        Text('好友列表')
          .fontSize(18)
      }
      .width('100%')
      .height(20)
      .margin({ bottom: 5, left: 10 })


      List({ space: 8 }) {
        ForEach(
          this.items,
          (i: Item) => {
            ListItem() {

              Row({ space: 10 }) {
                Image(i.image)
                  .width(90)
                Column({ space: 5 }) {
                  if (i.discount) {
                    Text(i.name)
                      .fontSize(18)
                      .fontWeight(FontWeight.Bold)
                  } else {
                    Text(i.name)
                      .fontSize(18)
                      .fontWeight(FontWeight.Bold)
                  }
                }
                .height('100%')
                .alignItems(HorizontalAlign.Start)

                Blank()
                if (i.isLove) {
                  this.CreateIco($r("app.media.icon_red"), i)
                } else {
                  this.CreateIco($r("app.media.icon_col"), i)
                }
              }
              .width('100%')
              .backgroundColor('#FFF')
              .borderRadius(20)
              .height(120)
              .padding(10)
            }
          }
        )
      }
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#EFEFEF')
  }

  @Builder
  CreateIco(icon: Resource, item: Item) {
    Image(icon)
      .width(28)
      .height(28)
      .objectFit(ImageFit.Contain)
      .margin(20)
      .onClick(() => {
        this.btnSubmt(item)
      })
  }

  btnSubmt(item: Item): void {
    item.isLove = !item.isLove
    console.log(" " + item.isLove)
    this.items = [...this.items] //展开数组再合起来,把值赋回去,这样子新开了一个内存浅拷贝,0层级的变化 系统会检测到allList数据发生变化,ui也会重新绘制

    promptAction.showDialog({
      title: '测试',
      message: '当前值 isLove=' + item.isLove,
      buttons: [
        {
          text: '取消',
          color: '#000000',
        },
        {
          text: '确定',
          color: 'red',
        }
      ],

    }, (err, data) => {
      if (err) {
        return;
      }
    })

  }
}


定义的对象如下:

@Observed
export  default class Item {
  name: string
  image: ResourceStr
  price: number
  discount: number
  isLove:boolean
  userName:string
  phone:string

  constructor(name: string, image: ResourceStr, price: number, discount: number = 0,isLove:boolean = false,userName:string,phone:string) {
    this.name = name
    this.image = image
    this.price = price
    this.discount = discount
    this.isLove = isLove
    this.userName = userName
    this.phone = phone
  }
}

效果

第一次点击:对象islove改变进行更换红心变色图片 image.png

第二次点击:对象islove改变进行更换红心变色图片 image.png

❌
❌