基于鴻蒙分布式跨設(shè)備文件服務(wù)-信件管理
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
一. 前言
先說說寫這個跨設(shè)備文件服務(wù)信件管理應(yīng)用前, 都想過做什么, 首先看了梁迪迪的基于分布式文件服務(wù)的文本編輯器,也想做一個文檔的,比如創(chuàng)建word,excel,pdf文件,然后點(diǎn)擊可以打開WPS軟件來編輯,可惜搜索了網(wǎng)上找不到打開WPS方法,最后放棄了;然后想到弄一個畫板,在畫板上畫上自己想表達(dá)的內(nèi)容,保存為圖片,跨設(shè)備可以打開圖片查看,開始時保存圖片,想用截屏的方法,查看文檔沒有找到Java調(diào)用系統(tǒng)的截屏方式,看到了JS的,但是要API7才支持,最后也放棄了,然而腦子里一閃,想起以前讀書時,自習(xí)課不用大聲說話,很多同學(xué)都是通過傳紙條,那時也流行寫信件,就往這個想法開始擼碼,這里有幾個知識點(diǎn),之前沒有寫過,比如怎么把文本框輸入的內(nèi)容寫到信紙上,然后保存為圖片,在另一臺設(shè)備上點(diǎn)擊圖片,可以查看里面的內(nèi)容,通過網(wǎng)上搜索,還是找到相似的知識點(diǎn), 才能在今天里做出了這個跨設(shè)備查看文件應(yīng)用.
先簡單說一下這個跨設(shè)備信件管理應(yīng)用,A手機(jī)創(chuàng)建一封信件,生成圖片,在A手機(jī)顯示本地端, 在B手機(jī)顯示遠(yuǎn)程端, 同時A,B手機(jī)都可以打開查看信件內(nèi)容,這里使用到了分布式數(shù)據(jù)庫管理,使用列表存儲圖片名,方便列表顯示出來,然后點(diǎn)擊相應(yīng)的圖片,獲取到圖片名,再到分布式文件路徑獲取到圖片,顯示出來.
二. 實(shí)現(xiàn)效果
開發(fā)工具環(huán)境下視頻:https://www.bilibili.com/video/BV16L4y1i7b1/
手機(jī)+手機(jī)環(huán)境下視頻:https://www.bilibili.com/video/BV1mL411g72B/
三. 創(chuàng)建工程
在這當(dāng)作你已經(jīng)安裝好最新版本DevEco-Studio開發(fā)工具, 點(diǎn)擊File -> New -> New Project… 彈出Create HarmonyOS Project窗口, 這里我選擇空白Java模板創(chuàng)建, 上一個視頻播放實(shí)例是用JS寫的界面,這個跨設(shè)備信件管理界面就用Java來寫,還是JS寫界面快,調(diào)試也快些.

Java模塊布局模塊
四. 主界面開發(fā)
先介紹公共類Java代碼,有了這些公共類,以后做類似功能的應(yīng)用,可以直接復(fù)制公共類文件可以使用:
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;
- /**
- * 構(gòu)造方法
- * @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);
- // 設(shè)置圖片參數(shù)
- ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
- decodingOptions.desiredSize=new Size(720,1080);
- PixelMap pixelMap = imageSource.createPixelmap(decodingOptions);
- //用于保存畫圖結(jié)果
- texture=new Texture(pixelMap);
- Canvas canvas=new Canvas(texture);
- Paint paint=new Paint();
- paint.setTextSize(50);
- paint.setStrokeWidth(8);
- paint.setColor(Color.BLACK);
- // 把內(nèi)容寫到信紙上
- 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, "創(chuàng)建成功!");
- }
- }
- 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;
- // 根據(jù)分布式文件路徑,生成文件
- File file = new File(filePath);
- if (!file.exists()) {
- // 如果文件不存在, 調(diào)用寫信件
- writeLetter(fileName, letterContent);
- }
- // 圖片參數(shù)
- ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
- srcOpts.formatHint = "image/jpeg";
- // 創(chuàng)建圖片源
- 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();
- }
- }
預(yù)覽信件內(nèi)容:
- /**
- * 預(yù)覽信件內(nèi)容
- */
- 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){
- // 設(shè)備ID
- String deviceID = KvManagerFactory.getInstance().createKvManager(new KvManagerConfig(context))
- .getLocalDeviceInfo().getId();
- // 組合文件名,方便區(qū)分是否為當(dāng)前設(shè)備創(chuàng)造的文件
- 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文件的權(quán)限配置哦,在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"
- }
- ],
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)