基于鸿蒙分布式跨设备文件服务-信件管理 原创 精华

狼哥Army
发布于 2021-10-27 00:25
浏览
6收藏

一, 前言

    先说说写这个跨设备文件服务信件管理应用前, 都想过做什么, 首先看了梁迪迪的基于分布式文件服务的文本编辑器,也想做一个文档的,比如创建word,excel,pdf文件,然后点击可以打开WPS软件来编辑,可惜搜索了网上找不到打开WPS方法,最后放弃了;然后想到弄一个画板,在画板上画上自己想表达的内容,保存为图片,跨设备可以打开图片查看,开始时保存图片,想用截屏的方法,查看文档没有找到Java调用系统的截屏方式,看到了JS的,但是要API7才支持,最后也放弃了,然而脑子里一闪,想起以前读书时,自习课不用大声说话,很多同学都是通过传纸条,那时也流行写信件,就往这个想法开始撸码,这里有几个知识点,之前没有写过,比如怎么把文本框输入的内容写到信纸上,然后保存为图片,在另一台设备上点击图片,可以查看里面的内容,通过网上搜索,还是找到相似的知识点, 才能在今天里做出了这个跨设备查看文件应用.

    先简单说一下这个跨设备信件管理应用,A手机创建一封信件,生成图片,在A手机显示本地端, 在B手机显示远程端, 同时A,B手机都可以打开查看信件内容,这里使用到了分布式数据库管理,使用列表存储图片名,方便列表显示出来,然后点击相应的图片,获取到图片名,再到分布式文件路径获取到图片,显示出来.

二, 实现效果

开发工具环境下视频:https://www.bilibili.com/video/BV16L4y1i7b1/
手机+手机环境下视频:https://www.bilibili.com/video/BV1mL411g72B/

效果图 平面图
基于鸿蒙分布式跨设备文件服务-信件管理-鸿蒙开发者社区 基于鸿蒙分布式跨设备文件服务-信件管理-鸿蒙开发者社区

三, 创建工程

    在这当作你已经安装好最新版本DevEco-Studio开发工具, 点击File -> New -> New Project… 弹出Create HarmonyOS Project窗口, 这里我选择空白Java模板创建, 上一个视频播放实例是用JS写的界面,这个跨设备信件管理界面就用Java来写,还是JS写界面快,调试也快些.
基于鸿蒙分布式跨设备文件服务-信件管理-鸿蒙开发者社区

Java模块 布局模块
基于鸿蒙分布式跨设备文件服务-信件管理-鸿蒙开发者社区 基于鸿蒙分布式跨设备文件服务-信件管理-鸿蒙开发者社区

四, 主界面开发

    先介绍公共类Java代码,有了这些公共类,以后做类似功能的应用,可以直接复制公共类文件可以使用:

DistributedFileUtil 分布式文件工具类:

package com.army.study.util;

import com.army.study.ResourceTable;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Texture;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImagePacker;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.Size;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 分布式文件工具类
 */
public class DistributedFileUtil {
    // 上下文
    private final Context mContext;

    /**
     * 构造方法
     * @param context
     */
    public DistributedFileUtil(Context context) {
        this.mContext = context;
    }

    /**
     * 写信件
     * @param fileName
     * @param letterContent
     * @return
     */
    public PixelMap writeLetter(String fileName, String letterContent) {
        // 获取分布式文件路径
        String filePath = mContext.getDistributedDir() + File.separator + fileName + ".jpg";
        Texture texture=null;
        try {
            // 从资源文件获取信纸背景图片
            InputStream inputStream = mContext.getResourceManager().getResource(ResourceTable.Media_bg);
            ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
            srcOpts.formatHint = "image/jpeg";
            ImageSource imageSource = ImageSource.create(inputStream, srcOpts);
            // 设置图片参数
            ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
            decodingOptions.desiredSize=new Size(720,1080);
            PixelMap pixelMap = imageSource.createPixelmap(decodingOptions);
            //用于保存画图结果
            texture=new Texture(pixelMap);
            Canvas canvas=new Canvas(texture);
            Paint paint=new Paint();
            paint.setTextSize(50);
            paint.setStrokeWidth(8);
            paint.setColor(Color.BLACK);
            // 把内容写到信纸上
            canvas.drawChars(paint,letterContent.toCharArray(),50,140);
            // 文件输出流
            FileOutputStream fos=new FileOutputStream(filePath);

            ImagePacker imagePacker = ImagePacker.create();
            ImagePacker.PackingOptions packingOptions = new ImagePacker.PackingOptions();
            packingOptions.format = "image/jpeg";//只支持image/jpeg
            packingOptions.quality = 90;
            boolean result = imagePacker.initializePacking(fos, packingOptions);
            if(result)
            {
                //这里获取绘画后的pixelMap用来保存
                result = imagePacker.addImage(texture.getPixelMap());
                if (result) {
                    long dataSize = imagePacker.finalizePacking();
                    System.out.println("文件大小:"+dataSize);
                    ToastUtil.getInstance().showToast(mContext, "创建成功!");
                }
            }

            fos.flush();
            fos.close();
        } catch (IOException | NotExistException e) {
            System.out.println("文件保存出错:"+e.getMessage());
            e.printStackTrace();
        }
        
        return texture.getPixelMap();
    }

    /**
     * 读取信件
     * @param fileName
     * @param letterContent
     * @return
     */
    public PixelMap readImage(String fileName, String letterContent) {
        // 获取分布式文件路径
        String filePath = mContext.getDistributedDir() + File.separator + fileName;
        // 根据分布式文件路径,生成文件
        File file = new File(filePath);
        if (!file.exists()) {
            // 如果文件不存在, 调用写信件
            writeLetter(fileName, letterContent);
        }
        // 图片参数
        ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
        srcOpts.formatHint = "image/jpeg";
        // 创建图片源
        ImageSource imageSource = ImageSource.create(file, srcOpts);
        // 生成图片
        PixelMap pixelMap = imageSource.createPixelmap(null);

        return pixelMap;
    }

    /**
     * 获取文件列表
     * @return
     */
    public List<String> getFileList() {
        // 获取分布式文件列表
        File[] files = mContext.getDistributedDir().listFiles();
        List<File> listFile = new ArrayList<>(Arrays.asList(files));
        // 排序文件顺序
        listFile.sort((file, newFile) -> {
            if (file.lastModified() > newFile.lastModified()) {
                return -1;
            } else if (file.lastModified() == newFile.lastModified()) {
                return 0;
            } else {
                return 1;
            }
        });
        List<String> listFileName = new ArrayList<>();
        // 获取文件列表文件名
        for (File f : listFile) {
            if (f.isFile()) {
                String name = f.getName();
                listFileName.add(name);
            }
        }
        return listFileName;
    }
}

ToastUtil 提示信息框:

package com.army.study.util;


import com.army.study.ResourceTable;
import ohos.agp.components.Component;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;

/**
 * Toast工具类
 *
 */
public class ToastUtil {
    private ToastDialog toastDialog;

    private ToastUtil() {
    }

    public static ToastUtil getInstance() {
        return ToastUtilInstance.INSTANCE;
    }

    private static class ToastUtilInstance {
        private static final ToastUtil INSTANCE = new ToastUtil();
    }

    /**
     * 显示Toast
     *
     * @param context
     * @param content
     */
    public void showToast(Context context, String content) {
        if (toastDialog != null && toastDialog.isShowing()) {
            toastDialog.cancel();
        }

        Component toastLayout = LayoutScatter.getInstance(context)
                .parse(ResourceTable.Layout_layout_toast, null, false);
        Text toastText = (Text) toastLayout.findComponentById(ResourceTable.Id_text_msg_toast);
        toastText.setText(content);
        toastDialog = new ToastDialog(context);
        toastDialog.setComponent(toastLayout);
        toastDialog.setTransparent(true);
        toastDialog.show();
    }
}

预览信件内容:

/**
 * 预览信件内容
 */
public class PreviewLetterDialog extends CommonDialog {

    public PreviewLetterDialog(Context context, PixelMap imgId) {
        super(context);
        Component container = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_dialog_previce_letter, null, false);
        setContentCustomComponent(container);
        setSize(MATCH_PARENT, MATCH_CONTENT);

        setCornerRadius(AttrHelper.vp2px(20, context));

        Image image = (Image) container.findComponentById(ResourceTable.Id_preview);
        image.setPixelMap(imgId);


        Button btnCancel = (Button) container.findComponentById(ResourceTable.Id_button_dialog_create_file_cancel);
        Button btnConfirm = (Button) container.findComponentById(ResourceTable.Id_button_dialog_create_file_confirm);

        btnCancel.setClickedListener(component -> {	destroy();});
        btnConfirm.setClickedListener(component -> { destroy();});
    }

}

写信件对话框:

/**
 * 写信件对话框
 */
public class CreateLetterDialog extends CommonDialog {
    private OnCallBack onCallBack;

    public CreateLetterDialog(Context context) {
        super(context);
        Component container = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_dialog_write_letter, null, false);
        setContentCustomComponent(container);

        Optional<Display> display = DisplayManager.getInstance().getDefaultDisplay(context);
        int width = (int) (display.get().getAttributes().width * 0.9);
        int height = AttrHelper.vp2px(270, context);
        setSize(width, height);
        setCornerRadius(AttrHelper.vp2px(20, context));

        TextField letterContent = (TextField) container.findComponentById(ResourceTable.Id_tf_dialog_create_file_name);
        Button btnCancel = (Button) container.findComponentById(ResourceTable.Id_button_dialog_create_file_cancel);
        Button btnConfirm = (Button) container.findComponentById(ResourceTable.Id_button_dialog_create_file_confirm);
        btnConfirm.setEnabled(false);
        btnConfirm.setAlpha(0.5f);
        letterContent.addTextObserver((text, i, i1, i2) -> {
            if(text.isEmpty()){
                btnConfirm.setEnabled(false);
                btnConfirm.setAlpha(0.5f);
            }else{
                btnConfirm.setEnabled(true);
                btnConfirm.setAlpha(1f);
            }
        });

        btnCancel.setClickedListener(component -> {	destroy();});

        btnConfirm.setClickedListener(component -> {
            if(onCallBack!=null){
                // 设备ID
                String deviceID = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(context))
                        .getLocalDeviceInfo().getId();
                // 组合文件名,方便区分是否为当前设备创造的文件
                String name = deviceID + "-" + letterContent.getText();
                onCallBack.onConfirm(name);
            }
            destroy();
        });
    }

    public void setOnCallBack(OnCallBack onCallBack) {
        this.onCallBack = onCallBack;
    }

    public interface OnCallBack {
        void onConfirm(String name);
    }
}

主界面代码图:
基于鸿蒙分布式跨设备文件服务-信件管理-鸿蒙开发者社区

讲解到此了,不要忘记了config.json文件的权限配置哦,在module下添加

    "reqPermissions": [
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC"
      },
      {
        "name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DEVICE_STATE_CHANGE"
      },
      {
        "name": "ohos.permission.WRITE_MEDIA"
      },
      {
        "name": "ohos.permission.READ_MEDIA"
      }
    ],

五, 总结

    有兴趣的小伙伴可以下载源码查看, 项目代码基本都有注释了,这是一个怀旧读书时写信件,传纸条的信件管理应用。 源码同步到gitee码云。

源码在这: https://gitee.com/army16/distributed-letter

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
12
收藏 6
回复
举报
2条回复
按时间正序
/
按时间倒序
Anzia
Anzia

狼哥yyds,gitee上点了个小star✨

2
回复
2021-10-27 08:58:48
狼哥Army
狼哥Army 回复了 Anzia
狼哥yyds,gitee上点了个小star✨

谢谢,互相学习

回复
2021-10-27 09:55:31
回复
    相关推荐