4、QAndroidJniObject实战(Android拍照、录像功能)

文章目录

  • 第一步:创建拍照和录像的intent对象
  • 第二步:创建照片或者视频的存储目录
  • 第三步:给IMAGE_CAPTURE 组件传递数据
  • 第四步:调用拍照
  • 第五步:handleActivityResult

第一步:创建拍照和录像的intent对象

   m_imagePath = "";
    //constuct Intent for IMAGE_CAPTURE
    QAndroidJniObject action;

    if(isImage)
        action = QAndroidJniObject::fromString(
                    "android.media.action.IMAGE_CAPTURE");
    else
        action = QAndroidJniObject::fromString(
                    "android.media.action.VIDEO_CAPTURE");
    QAndroidJniObject intent("android/content/Intent",
                             "(Ljava/lang/String;)V",
                             action.object<jstring>());

第二步:创建照片或者视频的存储目录

  • 知识点1: java.io.File 类

在 Java 里,目录、文件都通过 java.io.File 类来表示。 File 类有一个构造函数 File(String fileName) ,可以创建一个 File 对象,代表在所指定的目录下的文件fileName是指文件的全路径名)。 File 对象的 toString() 方法会返回它所代表的文件的路径。

代码里的 savedImageFile对象,使用 “(Ljava/lang/String;)V”作为 File 类构造函数的签名,然后用 file.object() 获得全路径名来传递给构造函数。

  • 知识点2: android.net.Uri 类

在我们通过 Intent 调用 IMAGE_CAPTURE 时,要指定的存储位置,是通过 android.net.Uri 类表示的,因此我又调用 Uri 的静态方法 fromFile() 创建了一个 Uri 对象,fromFile()只有一个类型为 File 的入参,返回值则是 Uri ,因此方法签名为“(Ljava/io/File;)Landroid/net/Uri;”。

  //setup saved image location
    QString date = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");

    QString filepath = saveDir + "/asop_img/";
    QDir tmpDir;
    if(!tmpDir.mkpath(filepath))//创建所有不存在的目录
    {
        qDebug() << "mkpath failed";
        return ;
    }
    QAndroidJniObject file;
    if(isImage)
        file = QAndroidJniObject::fromString(filepath + date + ".jpg");
    else
        file = QAndroidJniObject::fromString(filepath + date + ".mp4");
    QAndroidJniObject savedImageFile(
                "java/io/File",
                "(Ljava/lang/String;)V",
                file.object<jstring>());

    qDebug() << "savedImageFile - " << savedImageFile.toString();
    QAndroidJniObject savedImageUri =
            QAndroidJniObject::callStaticObjectMethod(
                "android/net/Uri",
                "fromFile",
                "(Ljava/io/File;)Landroid/net/Uri;",
                savedImageFile.object<jobject>());

第三步:给IMAGE_CAPTURE 组件传递数据

  • 知识点:public Intent putExtra (String name, Parcelable value);

背景:
Android Intent 类提供了一系列的 putExtra 方法,让我们能够把类型为 int 、 float 、 String 、int[] 、double 、char 、 byte 等等的数据存储在 Intent 实例中,带给被调用方。被调用方可以用 getExtra 方法获取到发起调用一方传递的数据。这就是使用 Intent 传递数据的一般用法。

要在两个组件之间传递数据,就要有个约定,因为传递的数据可能不知一个,就需要给每个数据起个名字,这就是 key ,putExtra() 方法的第一个参数类型为字符串,用于指定数据的 key ,接收 Intent 的一方可以根据这个 key 把数据取出来。

IMAGE_CAPTURE
对于 IMAGE_CAPTURE ,它接受的数据是 Uri ,对应的 key 则为 android.provider.MediaStore.EXTRA_OUTPUT ,是 MediaStore 类的静态成员变量。因为我在代码里就先调用 QAndroidJniObject::getStaticObjectField() 方法获取到 EXTRA_OUTPUT 。

上述操作,通知照片的保存路径

    //tell IMAGE_CAPTURE the output location
    QAndroidJniObject mediaStoreExtraOutput
            = QAndroidJniObject::getStaticObjectField(
                "android/provider/MediaStore",
                "EXTRA_OUTPUT",
                "Ljava/lang/String;");
    QAndroidJniObject mediaStoreTimeLimit
            = QAndroidJniObject::getStaticObjectField(
                "android/provider/MediaStore",
                "EXTRA_DURATION_LIMIT",
                "Ljava/lang/String;");


    qDebug() << "MediaStore.EXTRA_OUTPUT - " << mediaStoreExtraOutput.toString();
    qDebug() << "EXTRA_DURATION_LIMIT - " << mediaStoreTimeLimit.toString();

//通知IMAGE_CAPTURE组件照片的存储路径
    intent.callObjectMethod(						
                "putExtra",
                "(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;",
                mediaStoreExtraOutput.object<jstring>(),
                savedImageUri.object<jobject>());

//通知IMAGE_CAPTURE摄影时长限制
    if(!isImage)
    intent.callObjectMethod(
                "putExtra",
                "(Ljava/lang/String;I)Landroid/content/Intent;",
                mediaStoreTimeLimit.object<jstring>(),
                180);  //20220711 sh 录像时长限制从30秒改为3分钟

第四步:调用拍照

创建了一个 QAndroidActivityResultReceiver 对象,传递给 startActivity ,同时也指定 requestCode 为 1。

    m_imagePath = savedImageFile.toString();
    QtAndroid::startActivity(intent, 1, receiver);

第五步:handleActivityResult

手机执行拍照功能后,返回结果的接受函数

void ResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
{
    qDebug() << "handleActivityResult, requestCode - " << receiverRequestCode
             << " resultCode - " << resultCode
             << " data - " << data.toString();
    //RESULT_OK == -1
    if(resultCode == -1 && receiverRequestCode == 1)    //拍照
    {
        emit sig_result(1);
    }
    if (resultCode == -1 && receiverRequestCode == 2)   //获取照片
    {
        QAndroidJniObject url = data.callObjectMethod("getDataString", "()Ljava/lang/String;");
        qDebug() << url.isClassAvailable("java/lang/String");
        qDebug() << "string: "<< url.toString();
        //提取本地文件路径
        QAndroidJniObject uri = data.callObjectMethod("getData", "()Landroid/net/Uri;");
        QAndroidJniObject dadosAndroid = QAndroidJniObject::getStaticObjectField("android/provider/MediaStore$MediaColumns", "DATA", "Ljava/lang/String;");
        QAndroidJniEnvironment env;
        jobjectArray projecao = (jobjectArray)env->NewObjectArray(1, env->FindClass("java/lang/String"), NULL);
        jobject projacaoDadosAndroid = env->NewStringUTF(dadosAndroid.toString().toStdString().c_str());
        env->SetObjectArrayElement(projecao, 0, projacaoDadosAndroid);
        QAndroidJniObject contentResolver = QtAndroid::androidActivity().callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
        QAndroidJniObject cursor = contentResolver.callObjectMethod("query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;", uri.object<jobject>(), projecao, NULL, NULL, NULL);
        jint columnIndex = cursor.callMethod<jint>("getColumnIndex", "(Ljava/lang/String;)I", dadosAndroid.object<jstring>());
        cursor.callMethod<jboolean>("moveToFirst", "()Z");
        QAndroidJniObject resultado = cursor.callObjectMethod("getString", "(I)Ljava/lang/String;", columnIndex);

        m_strData = resultado.toString();

        emit sig_result(2);
    }
}

你可能感兴趣的:(Qt工作积累,android,java,android,studio)