QtAndroid详解(3):startActivity实战Android拍照功能

在“QtAndroid详解(1):QAndroidJniObject”中,我们介绍了 QAndroidJniObject 这个 Qt JNI 的核心类,在“”中我们介绍了 startActivity 以及与它配套的一些 Android 背景知识,这次我们来看一个实例,演示如何使用 startActivity 来调用 Android 系统功能,同时也演示 QAndroidJniObject 的常见用法。

实例介绍

先看下实例效果,然后再论。

我们只是演示 API 用法,实例设计的很简单。

第一排有个 “Get Info” 按钮,点击会获取 Qt Andorid App 所用的 Activity 的类名,如你所见,为 QtActivity 。除了 Activity 的类名,我还获取了当前 Activity 所对应的 taskId , inst 则对应于 Android Activity 的静态方法 —— getInstanceCount() 。

第二排一个编辑框,一个 “Launch” 按钮。编辑框可以输入一个 action ,点击 Launch 按钮则调用这个 action 对应的活动。调用时不关心结果,没有提供 QAndroidActivityResultReceiver 。

第三排是“Capture Image”按钮,点击它会调用系统的拍照功能来捕获一张图片,并将这张照片显示在界面上。这个功能,我使用QAndroidActivityResultReceiver 来处理结果。因为拍照可能被取消。

源码分析

介绍了示例的功能,现在来看代码吧。

我的示例是基于 Qt Widgets 的,使用新建项目向导时,基类选择了 QWidget ,没有要 ui 文件。创建了一个 AndroidManifest.xml 文件,包名修改为 “an.qt.QtAndroid” ,添加了android.permission.WRITE_EXTERNAL_STORAGE 和android.permission.CAMERA 权限。详细的过程请参考“Qt on Android:图文详解Hello World全过程”和“Windows下Qt 5.2 for Android开发入门”这两篇文章吧。这里我们专注于 Qt JNI 部分的代码分析。

头文件widget.h

头文件 widget.h 如下:

#ifndef WIDGET_H#define WIDGET_H#include <QWidget>#include <QLineEdit>#include <QTextEdit>#include <QLabel>class Widget : public QWidget{Q_OBJECTpublic:Widget(QWidget *parent = 0);~Widget();public slots:void onLaunch();void onGetActivityInfo();void onCapture();private:QLineEdit *m_actionEdit;QLabel*m_activityInfo;QLabel *m_capturedImage;};#endif // WIDGET_H m_actionEdit 用于输入 action 。

m_activityInfo 是显示 Activity 类名等信息的。

m_capturedImage 用来显示捕捉到的照片。

源文件 widget.cpp

源文件 widget.cpp ,内容如下:

#include "widget.h"#include <QtAndroid>#include <QPushButton>#include <QHBoxLayout>#include <QVBoxLayout>#include <QDebug>#include <QAndroidJniEnvironment>#include <QAndroidActivityResultReceiver>#include <QDateTime>#include <QFile>using namespace QtAndroid;#define CHECK_EXCEPTION() \if(env->ExceptionCheck())\{\qDebug() << "exception occured";\env->ExceptionClear();\}class ResultReceiver: public QAndroidActivityResultReceiver{public:ResultReceiver(QString imagePath, QLabel *view): m_imagePath(imagePath), m_imageView(view){}void handleActivityResult(int receiverRequestCode,int resultCode,const QAndroidJniObject & data){qDebug() << "handleActivityResult, requestCode – " << receiverRequestCode<< " resultCode – " << resultCode<< " data – " << data.toString();//RESULT_OK == -1if(resultCode == -1 && receiverRequestCode == 1){qDebug() << "captured image to – " << m_imagePath;qDebug() << "captured image exist – " << QFile::exists(m_imagePath);m_imageView->setPixmap(QPixmap(m_imagePath));}}QString m_imagePath;QLabel *m_imageView;};Widget::Widget(QWidget *parent): QWidget(parent){QVBoxLayout *layout = new QVBoxLayout(this);QHBoxLayout *actInfoLayout = new QHBoxLayout();layout->addLayout(actInfoLayout);QPushButton *getBtn = new QPushButton("Get Info");connect(getBtn, SIGNAL(clicked()), this, SLOT(onGetActivityInfo()));actInfoLayout->addWidget(getBtn);m_activityInfo = new QLabel();m_activityInfo->setWordWrap(true);actInfoLayout->addWidget(m_activityInfo, 1);layout->addSpacing(2);QHBoxLayout *actionLayout = new QHBoxLayout();layout->addLayout(actionLayout);m_actionEdit = new QLineEdit("android.settings.SETTINGS");actionLayout->addWidget(m_actionEdit, 1);QPushButton *launchBtn = new QPushButton("Launch");connect(launchBtn, SIGNAL(clicked()), this, SLOT(onLaunch()));actionLayout->addWidget(launchBtn);layout->addSpacing(2);QPushButton *capture = new QPushButton("CaptureImage");connect(capture, SIGNAL(clicked()), this, SLOT(onCapture()));layout->addWidget(capture);m_capturedImage = new QLabel();m_capturedImage->setScaledContents(true);layout->addWidget(m_capturedImage, 1);}Widget::~Widget(){}void Widget::onLaunch(){QAndroidJniObject action = QAndroidJniObject::fromString(m_actionEdit->text());QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", action.object<jstring>());startActivity(intent, 0);QAndroidJniEnvironment env;CHECK_EXCEPTION()}void Widget::onGetActivityInfo(){QAndroidJniEnvironment env;QAndroidJniObject activity = androidActivity();QAndroidJniObject className =activity.callObjectMethod<jstring>("getLocalClassName");CHECK_EXCEPTION()QString name = className.toString();int index = name.lastIndexOf(‘.’);if(index != -1){name = name.mid(index + 1);}jint taskId = activity.callMethod<jint>("getTaskId");CHECK_EXCEPTION()jlong instanceCount = QAndroidJniObject::callStaticMethod<jlong>("android/app/Activity","getInstanceCount");CHECK_EXCEPTION()QString activityInfo = QString("%1,task-%2,inst-%3").arg(name).arg(taskId).arg(instanceCount);m_activityInfo->setText(activityInfo);m_activityInfo->adjustSize();}void Widget::onCapture(){QAndroidJniEnvironment env;//constuct Intent for IMAGE_CAPTUREQAndroidJniObject action = QAndroidJniObject::fromString("android.media.action.IMAGE_CAPTURE");QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V",action.object<jstring>());//setup saved image locationQString date = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss");QAndroidJniObject fileName = QAndroidJniObject::fromString(date + ".jpg");QAndroidJniObject savedDir = QAndroidJniObject::callStaticObjectMethod("android/os/Environment","getExternalStorageDirectory","()Ljava/io/File;");CHECK_EXCEPTION()qDebug() << "savedDir – " << savedDir.toString();QAndroidJniObject savedImageFile("java/io/File","(Ljava/io/File;Ljava/lang/String;)V",savedDir.object<jobject>(),fileName.object<jstring>());CHECK_EXCEPTION()qDebug() << "savedImageFile – " << savedImageFile.toString();QAndroidJniObject savedImageUri =QAndroidJniObject::callStaticObjectMethod("android/net/Uri","fromFile","(Ljava/io/File;)Landroid/net/Uri;",savedImageFile.object<jobject>());CHECK_EXCEPTION()//tell IMAGE_CAPTURE the output locationQAndroidJniObject mediaStoreExtraOutput= QAndroidJniObject::getStaticObjectField("android/provider/MediaStore","EXTRA_OUTPUT","Ljava/lang/String;");CHECK_EXCEPTION()qDebug() << "MediaStore.EXTRA_OUTPUT – " << mediaStoreExtraOutput.toString();intent.callObjectMethod("putExtra","(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;",mediaStoreExtraOutput.object<jstring>(),savedImageUri.object<jobject>());//launch activity for resultResultReceiver *resultReceiver =new ResultReceiver(savedImageFile.toString(), m_capturedImage);startActivity(intent, 1, resultReceiver);CHECK_EXCEPTION()} 构造函数不说了吧,都是使用 Qt Widgets 编程的老相识了。我们就说其它的几部分:

其实代码本身很简单,只是牵涉到 JNI 和 Java 类库,C++的朋友可能不熟悉,所以我们展开讲一下。

其实只要你愿意,一切都可以变得很容易。

QtAndroid详解(3):startActivity实战Android拍照功能

相关文章:

你感兴趣的文章:

标签云: