相机与拍照


1 使用相机拍摄照片

1.1 用于画面预览SurfaceProvider

<SurfaceProvider
    ohos:id="$+id:sp"
    ohos:height="match_parent"
    ohos:width="match_parent"
    ohos:weight="1"
    />

1.2 权限申请与检测

在config.json中申请相机权限:

"reqPermissions": [
  {
    "name":"ohos.permission.CAMERA"
  }
]

在MainAbility中检查是否已获得相机权限,若未获得且可以获得,则动态申请该权限:

String permission = "ohos.permission.CAMERA";

if (verifySelfPermission(permission) == -1 &&
    canRequestPermission(permission)) {
    List<String> permissions = new ArrayList<>();
    permissions.add(permission);
    requestPermissionsFromUser(
        permissions.toArray(new String[0]), 1001);
}

在该权限的用户响应回调中检查用户是否允许,若允许则调用MainAbilitySlice的initCamera()方法,初始化相机:

public void onRequestPermissionsFromUserResult(
    int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsFromUserResult(
        requestCode, permissions, grantResults);

    if (requestCode == 1001 &&
        grantResults.length > 0 &&
        grantResults[0] == IBundleManager.PERMISSION_GRANTED)
        // 初始化相机
        mainAbilitySlice.initCamera();
}

在MainAbilitySlice中检查是否已获得相机权限,若已获得则直接调用initCamera()方法,初始化相机,否则显示拒绝页面,并将动态申请该权限的工作交给MainAbility:

if (verifySelfPermission("ohos.permission.CAMERA") == 0)
    // 初始化相机
    initCamera();
else {
    super.setUIContent(ResourceTable.Layout_ability_deny);
    ((MainAbility)getAbility()).setMainAbilitySlice(this);
}

1.3 MainAbilitySlice中的成员级对象

// 实时预览Surface对象
private Surface surface;

// 相机事件处理器对象
private EventHandler eventHandler;

// 相机对象
private Camera camera;

// 照片接收器对象
private ImageReceiver imageReceiver = ImageReceiver.create(
    4096, 3072, ImageFormat.JPEG, 5);

// 相机状态回调对象
private CameraStateCallback cameraStateCallback =
    new CameraStateCallback() {
        // 创建相机对象成功
        @Override
        public void onCreated(Camera c) {
            // 得到相机对象
            super.onCreated(camera = c);

            // 配置相机对象
            CameraConfig.Builder builder =
                camera.getCameraConfigBuilder();
            if (builder != null) {
                // 添加实时预览Surface对象
                builder.addSurface(surface);
                // 添加照片显示Surface对象
                builder.addSurface(
                    imageReceiver.getRecevingSurface());
                // 开始配置
                camera.configure(builder.build());
            }
        }

        // 创建相机对象失败
        @Override
        public void onCreateFailed(String cameraId, int errorCode) {
            super.onCreateFailed(cameraId, errorCode);

            HiLog.info(label,
                "Unable to create camera: %{public}d",
                errorCode);
        }

        // 配置相机对象成功
        @Override
        public void onConfigured(Camera camera) {
            super.onConfigured(camera);

            // 配置实时预览帧
            FrameConfig.Builder builder =
                camera.getFrameConfigBuilder(
                    FrameConfigType.FRAME_CONFIG_PREVIEW);
            // 添加实时预览Surface对象
            builder.addSurface(surface);
            // 开始循环帧捕获
            camera.triggerLoopingCapture(builder.build());
        }

        // 配置相机对象失败
        @Override
        public void onConfigureFailed(Camera camera, int errorCode) {
            super.onConfigureFailed(camera, errorCode);

            HiLog.info(label,
                "Unable to configure camera: %{public}d",
                errorCode);
        }
    };

1.4 MainAbilitySlice中负责初始化相机的方法

// 初始化相机
public void initCamera() {
    super.setUIContent(ResourceTable.Layout_ability_main);

    // 为照片接收器对象设置侦听
    imageReceiver.setImageArrivalListener((ImageReceiver ir) -> {
        // 照片文件名
        String filename = "IMG_" + new SimpleDateFormat(
            "yyyyMMdd_HHmmss").format(System.currentTimeMillis()) +
            ".jpg";
        // 照片文件对象
        final File file = new File(getExternalFilesDir("Camera"),
            filename);

        // 读取照片数据
        final Image image = ir.readNextImage();

        // 异步方式保存照片数据
        eventHandler.postTask(() -> {
            // 通过Component对象读取照片字节序列
            Image.Component component =
                image.getComponent(ComponentType.JPEG);
            byte[] bytes = new byte[component.remaining()];
            component.read(bytes);

            // 通过输出流保存数据
            FileOutputStream fos = null;
            try {
                fos = new FileOutputStream(file);
                fos.write(bytes); // 写照片数据

                HiLog.info(label, file.getAbsolutePath());
                getUITaskDispatcher().asyncDispatch(
                    () -> showToast("拍照成功"));
            }
            catch (Exception exception) {
                HiLog.info(label, exception.getLocalizedMessage());
            }
            finally {
                // 关闭输出流
                if (fos != null)
                    try {
                        fos.close();
                    }
                    catch (Exception exception) {
                        HiLog.info(label,
                            exception.getLocalizedMessage());
                    }

                // 释放照片数据
                image.release();
            }
        });
    });

    // 画面预览SurfaceProvider对象
    SurfaceProvider sp = (SurfaceProvider) findComponentById(
        ResourceTable.Id_sp);
    sp.pinToZTop(true);
    sp.getSurfaceOps().get().addCallback(new Callback() {
        @Override
        public void surfaceCreated(SurfaceOps surfaceOps) {
            // 获取实时预览Surface对象
            surface = surfaceOps.getSurface();
            // 创建相机对象
            createCamera();
        }

        @Override
        public void surfaceChanged(SurfaceOps surfaceOps,
            int i, int i1, int i2) {
        }

        @Override
        public void surfaceDestroyed(SurfaceOps surfaceOps) {
        }
    });

    findComponentById(ResourceTable.Id_btn)
        .setClickedListener(component -> onClick());
}

1.5 MainAbilitySlice中负责创建相机对象的方法

// 创建相机对象
private boolean createCamera() {
    // 获取相机管理器对象
    CameraKit cameraKit = CameraKit.getInstance(this);
    if (cameraKit == null) {
        HiLog.info(label, "Unable to get CameraKit");
        return false;
    }

    // 获取逻辑相机列表
    String[] cameraIds = cameraKit.getCameraIds();
    if (cameraIds == null || cameraIds.length <= 0) {
        HiLog.info(label, "Unable to get CameraIds");
        return false;
    }

    // 创建相机事件处理器对象
    eventHandler = new EventHandler(EventRunner.current());

    // 创建相机对象
    cameraKit.createCamera(
        cameraIds[0], cameraStateCallback, eventHandler);
    return true;
}

1.6 MainAbilitySlice中响应拍照按钮的方法

// 拍照
private void onClick() {
    // 配置照片显示帧
    FrameConfig.Builder builder = camera.getFrameConfigBuilder(
        FrameConfigType.FRAME_CONFIG_PICTURE);
    // 添加照片显示Surface对象
    builder.addSurface(imageReceiver.getRecevingSurface());
    // 照片旋转90度
    builder.setImageRotation(90);

    try {
        // 单帧捕获
        camera.triggerSingleCapture(builder.build());
    }
    catch (Exception exception) {
        HiLog.info(label, exception.getLocalizedMessage());
    }
}

例程:Photograph

...\Photograph\entry\src\main\config.json

{
  ...
  "module": {
    ...
    "reqPermissions": [
      {
        "name":"ohos.permission.CAMERA"
      }
    ]
  }
}

...\Photograph\entry\src\main\resources\base\media\camera.jpg

...\Photograph\entry\src\main\resources\base\layout\toast_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_content"
    ohos:width="match_content"
    ohos:left_padding="10vp"
    ohos:top_padding="5vp"
    ohos:right_padding="10vp"
    ohos:bottom_padding="5vp"
    ohos:background_element="#404040">

    <Text
        ohos:id="$+id:txt"
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text_size="20fp"
        ohos:text_color="#ffffff"
        />

</DirectionalLayout>

...\Photograph\entry\src\main\resources\base\layout\ability_deny.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:alignment="center"
    ohos:orientation="vertical"
    ohos:background_element="#000000">

    <Image
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:image_src="$media:camera"
        />

</DirectionalLayout>

...\Photograph\entry\src\main\resources\base\layout\ability_main.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:alignment="center"
    ohos:orientation="vertical">

    <SurfaceProvider
        ohos:id="$+id:sp"
        ohos:height="match_parent"
        ohos:width="match_parent"
        ohos:weight="1"
        />

    <Button
        ohos:id="$+id:btn"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="$ohos:float:button_radius"
        ohos:background_element="#00a2e8"
        ohos:text="拍照"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

</DirectionalLayout>

...\Photograph\entry\src\main\java\com\minwei\photograph\MainAbility.java

public class MainAbility extends Ability {
    private MainAbilitySlice mainAbilitySlice;

    public void setMainAbilitySlice(MainAbilitySlice slice) {
        mainAbilitySlice = slice;
    }

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setMainRoute(MainAbilitySlice.class.getName());

        requestCameraPermission();
    }

    private void requestCameraPermission() {
        String permission = "ohos.permission.CAMERA";

        if (verifySelfPermission(permission) == -1 &&
            canRequestPermission(permission)) {
            List<String> permissions = new ArrayList<>();
            permissions.add(permission);
            requestPermissionsFromUser(
                permissions.toArray(new String[0]), 1001);
        }
    }

    @Override
    public void onRequestPermissionsFromUserResult(
        int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsFromUserResult(
            requestCode, permissions, grantResults);

        if (requestCode == 1001 &&
            grantResults.length > 0 &&
            grantResults[0] == IBundleManager.PERMISSION_GRANTED)
            // 初始化相机
            mainAbilitySlice.initCamera();
    }
}

...\Photograph\entry\src\main\java\com\minwei\photograph\slice\MainAbilitySlice.java

public class MainAbilitySlice extends AbilitySlice {
    private static final HiLogLabel label = new HiLogLabel(
        HiLog.LOG_APP, 0x00101,
        MainAbilitySlice.class.getCanonicalName());

    // 实时预览Surface对象
    private Surface surface;
    // 相机事件处理器对象
    private EventHandler eventHandler;

    // 相机对象
    private Camera camera;
    // 照片接收器对象
    private ImageReceiver imageReceiver = ImageReceiver.create(
        4096, 3072, ImageFormat.JPEG, 5);

    // 相机状态回调对象
    private CameraStateCallback cameraStateCallback =
        new CameraStateCallback() {
            // 创建相机对象成功
            @Override
            public void onCreated(Camera c) {
                // 得到相机对象
                super.onCreated(camera = c);

                // 配置相机对象
                CameraConfig.Builder builder =
                    camera.getCameraConfigBuilder();
                if (builder != null) {
                    // 添加实时预览Surface对象
                    builder.addSurface(surface);
                    // 添加照片显示Surface对象
                    builder.addSurface(
                        imageReceiver.getRecevingSurface());
                    // 开始配置
                    camera.configure(builder.build());
                }
            }

            // 创建相机对象失败
            @Override
            public void onCreateFailed(String cameraId, int errorCode) {
                super.onCreateFailed(cameraId, errorCode);

                HiLog.info(label,
                    "Unable to create camera: %{public}d",
                    errorCode);
            }

            // 配置相机对象成功
            @Override
            public void onConfigured(Camera camera) {
                super.onConfigured(camera);

                // 配置实时预览帧
                FrameConfig.Builder builder =
                    camera.getFrameConfigBuilder(
                        FrameConfigType.FRAME_CONFIG_PREVIEW);
                // 添加实时预览Surface对象
                builder.addSurface(surface);
                // 开始循环帧捕获
                camera.triggerLoopingCapture(builder.build());
            }

            // 配置相机对象失败
            @Override
            public void onConfigureFailed(Camera camera, int errorCode) {
                super.onConfigureFailed(camera, errorCode);

                HiLog.info(label,
                    "Unable to configure camera: %{public}d",
                    errorCode);
            }
        };

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);

        if (verifySelfPermission("ohos.permission.CAMERA") == 0)
            // 初始化相机
            initCamera();
        else {
            super.setUIContent(ResourceTable.Layout_ability_deny);
            ((MainAbility)getAbility()).setMainAbilitySlice(this);
        }
    }
    ...
    // 初始化相机
    public void initCamera() {
        super.setUIContent(ResourceTable.Layout_ability_main);

        // 为照片接收器对象设置侦听
        imageReceiver.setImageArrivalListener((ImageReceiver ir) -> {
            // 照片文件名
            String filename = "IMG_" + new SimpleDateFormat(
                "yyyyMMdd_HHmmss").format(System.currentTimeMillis()) +
                ".jpg";
            // 照片文件对象
            final File file = new File(getExternalFilesDir("Camera"),
                filename);

            // 读取照片数据
            final Image image = ir.readNextImage();

            // 异步方式保存照片数据
            eventHandler.postTask(() -> {
                // 通过Component对象读取照片字节序列
                Image.Component component =
                    image.getComponent(ComponentType.JPEG);
                byte[] bytes = new byte[component.remaining()];
                component.read(bytes);

                // 通过输出流保存数据
                FileOutputStream fos = null;
                try {
                    fos = new FileOutputStream(file);
                    fos.write(bytes); // 写照片数据

                    HiLog.info(label, file.getAbsolutePath());
                    getUITaskDispatcher().asyncDispatch(
                        () -> showToast("拍照成功"));
                }
                catch (Exception exception) {
                    HiLog.info(label, exception.getLocalizedMessage());
                }
                finally {
                    // 关闭输出流
                    if (fos != null)
                        try {
                            fos.close();
                        }
                        catch (Exception exception) {
                            HiLog.info(label,
                                exception.getLocalizedMessage());
                        }

                    // 释放照片数据
                    image.release();
                }
            });
        });

        // 画面预览SurfaceProvider对象
        SurfaceProvider sp = (SurfaceProvider) findComponentById(
            ResourceTable.Id_sp);
        sp.pinToZTop(true);
        sp.getSurfaceOps().get().addCallback(new Callback() {
            @Override
            public void surfaceCreated(SurfaceOps surfaceOps) {
                // 获取实时预览Surface对象
                surface = surfaceOps.getSurface();
                // 创建相机对象
                createCamera();
            }

            @Override
            public void surfaceChanged(SurfaceOps surfaceOps,
                int i, int i1, int i2) {
            }

            @Override
            public void surfaceDestroyed(SurfaceOps surfaceOps) {
            }
        });

        findComponentById(ResourceTable.Id_btn)
            .setClickedListener(component -> onClick());
    }

    private void showToast(String text) {
        Component component = LayoutScatter.getInstance(this).parse(
            ResourceTable.Layout_toast_dialog, null, false);
        ((Text)component.findComponentById(ResourceTable.Id_txt))
            .setText(text);
        new ToastDialog(this)
            .setContentCustomComponent(component)
            .setSize(LayoutConfig.MATCH_CONTENT,
                LayoutConfig.MATCH_CONTENT)
            .setDuration(5000)
            .setAlignment(LayoutAlignment.BOTTOM)
            .setOffset(0, AttrHelper.vp2px(60, this))
            .show();
    }

    // 创建相机对象
    private boolean createCamera() {
        // 获取相机管理器对象
        CameraKit cameraKit = CameraKit.getInstance(this);
        if (cameraKit == null) {
            HiLog.info(label, "Unable to get CameraKit");
            return false;
        }

        // 获取逻辑相机列表
        String[] cameraIds = cameraKit.getCameraIds();
        if (cameraIds == null || cameraIds.length <= 0) {
            HiLog.info(label, "Unable to get CameraIds");
            return false;
        }

        // 创建相机事件处理器对象
        eventHandler = new EventHandler(EventRunner.current());

        // 创建相机对象
        cameraKit.createCamera(
            cameraIds[0], cameraStateCallback, eventHandler);
        return true;
    }

    // 拍照
    private void onClick() {
        // 配置照片显示帧
        FrameConfig.Builder builder = camera.getFrameConfigBuilder(
            FrameConfigType.FRAME_CONFIG_PICTURE);
        // 添加照片显示Surface对象
        builder.addSurface(imageReceiver.getRecevingSurface());
        // 照片旋转90度
        builder.setImageRotation(90);

        try {
            // 单帧捕获
            camera.triggerSingleCapture(builder.build());
        }
        catch (Exception exception) {
            HiLog.info(label, exception.getLocalizedMessage());
        }
    }
}

运行效果如下图所示:

2 访问外部存储中的多媒体文件

在鸿蒙设备中用于应用程序存储文件的位置有两个:

/data/user/0/<bundle_name>/ - 沙盒目录,getDataDir()
|
|_ cache/                   - 缓存目录,getCacheDir()
|_ code_cache/              - 代码缓存,getCodeCacheDir()
|_ files/                   - 文件目录,getFilesDir()
/storage/emulated/0/         \
或                           | - 外部存储
/storage/emulated/sdcard/    /
|
|_ Android/data/<bundle_name>/ - 私有目录,用户能访问,其它应用不能访问
|  |
|  |_ cache/                   - 缓存目录,getExternalCacheDir()
|  |_ <name1>/                 - 自建目录,getExternalFilesDir(<name1>)
|  |_ <name2>/                 - 自建目录,getExternalFilesDir(<name2>)
|  |_ ...                      - ...
|
|_ ...                         - 公有区域,用户和其它应用都能访问

应用程序访问沙盒目录和外部存储私有目录中的文件,不需要任何特殊权限,直接
使用Java语言提供的文件操作接口即可。但如果需要访问外部存储公有区域中的文
件,则必须借助于DataAbility。

鸿蒙系统在外部存储的公有区域中,为图像、视频、音频等多媒体文件划定了专门
的存储目录。借助DataAbilityHelper和相应的URI常量,可以很方便地访问这些目
录中的文件。

DataAbilityHelper helper = DataAbilityHelper.creator(this);
ResultSet result = null;

try {
    result = helper.query(Images.Media.EXTERNAL_DATA_ABILITY_URI,
        new String[]{Images.Media.ID}, null);
    HiLog.info(label, "图像文件数量:%{public}d",
        result.getRowCount());

    HiLog.info(label, "图像文件列表:");
    while (result.goToNextRow()) {
        int id = result.getInt(0);
        Uri uri = Uri.appendEncodedPathToUri(
            Images.Media.EXTERNAL_DATA_ABILITY_URI,
            String.valueOf(id));
        HiLog.info(label, uri.toString());
        /*
        FileDescriptor fd = helper.openFile(uri, "r");
        FileReader fr = new FileReader(fd);
        // ...
        */
    }
}
catch (Exception exception) {
    HiLog.info(label, exception.getLocalizedMessage());
}
finally {
    if (result != null)
        result.close();
}

例程:AVStorage

...\AVStorage\entry\src\main\resources\base\graphic\background_button.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:shape="rectangle">
    <corners ohos:radius="100"/>
    <solid ohos:color="#ff7f27"/>
</shape>

...\AVStorage\entry\src\main\resources\base\layout\ability_main.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:left_padding="80vp"
    ohos:right_padding="80vp"
    ohos:alignment="center"
    ohos:orientation="vertical">

    <Text
        ohos:height="match_content"
        ohos:width="match_content"
        ohos:text="媒体存储"
        ohos:text_size="28fp"
        ohos:text_color="#ff7f27"
        />

    <Text
        ohos:height="2vp"
        ohos:width="match_parent"
        ohos:top_margin="10vp"
        ohos:bottom_margin="5vp"
        ohos:background_element="#ff7f27"
        />

    <Button
        ohos:id="$+id:btnImages"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="图像文件"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnVideo"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="视频文件"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnAudio"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="音频文件"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

    <Button
        ohos:id="$+id:btnDownloads"
        ohos:height="match_content"
        ohos:width="match_parent"
        ohos:padding="8vp"
        ohos:top_margin="10vp"
        ohos:background_element="$graphic:background_button"
        ohos:text="下载文件"
        ohos:text_size="24fp"
        ohos:text_color="#ffffff"
        />

</DirectionalLayout>

...\AVStorage\entry\src\main\java\com\minwei\avstorage\slice\MainAbilitySlice.java

public class MainAbilitySlice extends AbilitySlice {
    private static final HiLogLabel label = new HiLogLabel(
        HiLog.LOG_APP, 0x00101,
        MainAbilitySlice.class.getCanonicalName());

    @Override
    public void onStart(Intent intent) {
        ...
        findComponentById(ResourceTable.Id_btnImages)
            .setClickedListener(component -> onImages());
        findComponentById(ResourceTable.Id_btnVideo)
            .setClickedListener(component -> onVideo());
        findComponentById(ResourceTable.Id_btnAudio)
            .setClickedListener(component -> onAudio());
        findComponentById(ResourceTable.Id_btnDownloads)
            .setClickedListener(component -> onDownloads());
    }
    ...
    private void onImages() {
        DataAbilityHelper helper = DataAbilityHelper.creator(this);
        ResultSet result = null;

        try {
            result = helper.query(Images.Media.EXTERNAL_DATA_ABILITY_URI,
                new String[]{Images.Media.ID}, null);
            HiLog.info(label, "图像文件数量:%{public}d",
                result.getRowCount());

            HiLog.info(label, "图像文件列表:");
            while (result.goToNextRow()) {
                int id = result.getInt(0);
                Uri uri = Uri.appendEncodedPathToUri(
                    Images.Media.EXTERNAL_DATA_ABILITY_URI,
                    String.valueOf(id));
                HiLog.info(label, uri.toString());
                /*
                FileDescriptor fd = helper.openFile(uri, "r");
                FileReader fr = new FileReader(fd);
                // ...
                */
            }
        }
        catch (Exception exception) {
            HiLog.info(label, exception.getLocalizedMessage());
        }
        finally {
            if (result != null)
                result.close();
        }
    }

    private void onVideo() {
        DataAbilityHelper helper = DataAbilityHelper.creator(this);
        ResultSet result = null;

        try {
            result = helper.query(Video.Media.EXTERNAL_DATA_ABILITY_URI,
                new String[]{Video.Media.ID}, null);
            HiLog.info(label, "视频文件数量:%{public}d",
                result.getRowCount());

            HiLog.info(label, "视频文件列表:");
            while (result.goToNextRow()) {
                int id = result.getInt(0);
                Uri uri = Uri.appendEncodedPathToUri(
                    Video.Media.EXTERNAL_DATA_ABILITY_URI,
                    String.valueOf(id));
                HiLog.info(label, uri.toString());
                /*
                FileDescriptor fd = helper.openFile(uri, "r");
                FileReader fr = new FileReader(fd);
                // ...
                */
            }
        }
        catch (Exception exception) {
            HiLog.info(label, exception.getLocalizedMessage());
        }
        finally {
            if (result != null)
                result.close();
        }
    }

    private void onAudio() {
        DataAbilityHelper helper = DataAbilityHelper.creator(this);
        ResultSet result = null;

        try {
            result = helper.query(Audio.Media.EXTERNAL_DATA_ABILITY_URI,
                new String[]{Audio.Media.ID}, null);
            HiLog.info(label, "音频文件数量:%{public}d",
                result.getRowCount());

            HiLog.info(label, "音频文件列表:");
            while (result.goToNextRow()) {
                int id = result.getInt(0);
                Uri uri = Uri.appendEncodedPathToUri(
                    Audio.Media.EXTERNAL_DATA_ABILITY_URI,
                    String.valueOf(id));
                HiLog.info(label, uri.toString());
                /*
                FileDescriptor fd = helper.openFile(uri, "r");
                FileReader fr = new FileReader(fd);
                // ...
                */
            }
        }
        catch (Exception exception) {
            HiLog.info(label, exception.getLocalizedMessage());
        }
        finally {
            if (result != null)
                result.close();
        }
    }

    private void onDownloads() {
        DataAbilityHelper helper = DataAbilityHelper.creator(this);
        ResultSet result = null;

        try {
            result = helper.query(Downloads.EXTERNAL_DATA_ABILITY_URI,
                new String[]{Downloads.ID}, null);
            HiLog.info(label, "下载文件数量:%{public}d",
                result.getRowCount());

            HiLog.info(label, "下载文件列表:");
            while (result.goToNextRow()) {
                int id = result.getInt(0);
                Uri uri = Uri.appendEncodedPathToUri(
                    Downloads.EXTERNAL_DATA_ABILITY_URI,
                    String.valueOf(id));
                HiLog.info(label, uri.toString());
                /*
                FileDescriptor fd = helper.openFile(uri, "r");
                FileReader fr = new FileReader(fd);
                // ...
                */
            }
        }
        catch (Exception exception) {
            HiLog.info(label, exception.getLocalizedMessage());
        }
        finally {
            if (result != null)
                result.close();
        }
    }
}

运行效果如下图所示:

更多精彩,敬请期待……


达内集团C++教学部 2021年10月8日