很多朋友在论坛和QQ群里问到这个,今天有时间写了个简单的示例。
功能很简单,允许你输入一个web页面地址,使用Java的下载类库下载后用QTextEdit显示出来。
版权所有:foruok。转载请注明出处:http://blog.csdn.net/foruok。
效果展示
初始效果如图1所示:
图1 useJar示例初始效果
图2为点击"GET"按钮后下载到对应页面的效果:
图2 下载页面成功
下载部分,为了显示如何使用jar包,我用了asynchttpclient,参考我的博文:Android开源框架AsyncHttpClient (android-async-http)使用。
项目创建
参考《Qt on Android:图文详解Hello World全过程》吧,没什么特别可说的。
pro文件内添加“QT += androidextras”。
创建一个AndroidManifest,package命名为an.qt.useJar。
版权所有:foruok。转载请注明出处:http://blog.csdn.net/foruok。
添加Java源码
你可以任意的文本编辑器中编辑java源码,然后通过Qt Creator项目视图加到项目里,在其它文件那里鼠标右键点击,选择添加现有文件即可。参考下面几张图吧。
图3 添加Java源码之右键菜单
图4 添加Java源文件之选择Java源文件
图5 添加Java源文件OK
修改AndroidManifest,把activity标签的android:name属性值修改为an.qt.useJar.ExtendsQtWithJava。这是必须的,因为我们的ExtendsQtWithJava.java实现的Activity就是这个名字。
好了,Java代码添加结束。
添加第三方jar包
这个没什么好说的,放在android/libs目录下即可。看图:
图6 放jar包
只要放好位置,Qt Creator编译项目时就会把这个jar包打包到APK里。
Java源码使用jar包
这是java编程的内容了,import包名,然后使用即可。
源码分析
咱先看Java侧的代码吧。
Java代码
ExtendsQtWithJava.java:
package an.qt.useJar; import java.lang.String; import android.content.Context; import android.content.Intent; import android.app.PendingIntent; import android.os.Handler; import android.os.Message; import android.util.Log; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.location.Criteria; import android.provider.Settings; import android.os.Bundle; import android.os.Environment; import java.io.File; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; public class ExtendsQtWithJava extends org.qtproject.qt5.android.bindings.QtActivity { private static ExtendsQtWithJava m_instance; private final static String TAG = "extendsQt"; private static String m_pageUri = null; private static Handler m_handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case 1: if(m_pageUri == null){ m_pageUri = (String)msg.obj; m_instance.downloadText(m_pageUri); }else{ m_instance.notifyQt(0, (String)msg.obj, "Downloader is Busy now!"); } break; }; } }; public ExtendsQtWithJava(){ m_instance = this; } public static int networkState(){ ConnectivityManager conMan = (ConnectivityManager) m_instance.getSystemService(Context.CONNECTIVITY_SERVICE); return conMan.getActiveNetworkInfo() == null ? 0 : 1; } public static AsyncHttpClient m_httpc = new AsyncHttpClient(); public static ExtendsQtNative m_nativeNotify = null; public void downloadText(String uri){ Log.d(TAG, "start downloadText"); m_httpc.get(uri, null, new AsyncHttpResponseHandler(){ @Override public void onSuccess(String data){ notifyQt(1, m_pageUri, data); m_pageUri = null; } @Override public void onFailure(Throwable e, String data){ notifyQt(-1, m_pageUri, data); m_pageUri = null; } }); } public static void downloadWebPage(String uri){ Log.d(TAG, "downloadWebPage"); m_handler.sendMessage(m_handler.obtainMessage(1, uri)); } private void notifyQt(int result, String uri, String data){ if(m_nativeNotify == null){ m_nativeNotify = new ExtendsQtNative(); } m_nativeNotify.OnDownloaded(result, uri, data); } }
ExtendsQtNative.java:
package an.qt.useJar; import java.lang.String; public class ExtendsQtNative { public native void OnDownloaded(int result, String url, String content); }
基本思路是酱紫的:
Qt调用java的downloadWebPage,Java代码使用asynchttpclient下载一个网页,然后调用ExtendsQtNative通知Qt C++代码。
C++代码
分两部分,一部分是实现JNI方法。另一部分是调用Java类的方法。
实现JNI方法并注册
先看与ExtendsQtNative对应的JNI实现,在main.cpp中,都列出吧:
#include "widget.h" #include <QApplication> #include <QAndroidJniEnvironment> #include <QAndroidJniObject> #include <jni.h> #include "../simpleCustomEvent.h" #include <QDebug> QObject *g_listener = 0; // result: -1 failed; 1 success; 0 busy; static void onDownloaded(JNIEnv *env, jobject thiz,int result, jstring uri, jstring data) { QString qstrData; const char *nativeString = env->GetStringUTFChars(data, 0); qstrData = nativeString; env->ReleaseStringUTFChars(data, nativeString); QCoreApplication::postEvent(g_listener, new SimpleCustomEvent(result, qstrData)); } bool registerNativeMethods() { JNINativeMethod methods[] { {"OnDownloaded", "(ILjava/lang/String;Ljava/lang/String;)V", (void*)onDownloaded} }; const char *classname = "an/qt/useJar/ExtendsQtNative"; jclass clazz; QAndroidJniEnvironment env; QAndroidJniObject javaClass(classname); clazz = env->GetObjectClass(javaClass.object<jobject>()); qDebug() << "find ExtendsQtNative - " << clazz; bool result = false; if(clazz) { jint ret = env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])); env->DeleteLocalRef(clazz); qDebug() << "RegisterNatives return - " << ret; result = ret >= 0; } if(env->ExceptionCheck()) env->ExceptionClear(); return result; } int main(int argc, char *argv[]) { QApplication a(argc, argv); SimpleCustomEvent::eventType(); registerNativeMethods(); Widget w; g_listener = qobject_cast<QObject*>(&w); w.show(); return a.exec(); }
注册JNI方法,设置一个全局的对象接收通知。具体的,参考Qt帮助来理解。
调用Java方法
对Java方法的调用在Widget.cpp中。直接看代码吧。
widget.h:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QLineEdit> #include <QTextEdit> #include <QLabel> class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = 0); ~Widget(); bool event(QEvent *e); public slots: void onGet(); private: QLineEdit * m_urlEdit; QTextEdit * m_resultView; QLabel * m_stateLabel; }; #endif // WIDGET_H
都是界面相关的,没什么好说的。看widget.cpp:
#include "widget.h" #include <QVBoxLayout> #include <QPushButton> #include "../simpleCustomEvent.h" #include <QAndroidJniObject> #include <QAndroidJniEnvironment> Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout(this); QHBoxLayout *getLayout = new QHBoxLayout(); layout->addLayout(getLayout); m_urlEdit = new QLineEdit("http://blog.csdn.net/foruok"); getLayout->addWidget(m_urlEdit, 1); QPushButton *getButton = new QPushButton("GET"); getLayout->addWidget(getButton); connect(getButton, SIGNAL(clicked()), this, SLOT(onGet())); m_resultView = new QTextEdit(); m_resultView->setReadOnly(true); layout->addWidget(m_resultView, 1); m_stateLabel = new QLabel(); layout->addWidget(m_stateLabel); } Widget::~Widget() { } bool Widget::event(QEvent *e) { if(e->type() == SimpleCustomEvent::eventType()) { e->accept(); SimpleCustomEvent *sce = (SimpleCustomEvent*)e; switch(sce->m_arg1) { case 1: m_resultView->setText(sce->m_arg2); m_stateLabel->setText("Success!"); break; case 0: m_resultView->setText(sce->m_arg2); m_stateLabel->setText("Failed!"); break; case -1: m_stateLabel->setText(sce->m_arg2); break; } return true; } return QWidget::event(e); } void Widget::onGet() { #ifdef WIN32 m_resultView->setText("Sorry, Just for Android!"); #elif defined(ANDROID) QString url = m_urlEdit->text(); QAndroidJniObject javaAction = QAndroidJniObject::fromString(url); QAndroidJniObject::callStaticMethod<void>("an/qt/useJar/ExtendsQtWithJava", "downloadWebPage", "(Ljava/lang/String;)V", javaAction.object<jstring>()); m_stateLabel->setText("Downloading..."); #endif }
调用Java的代码在onGet()槽中,很简单,不解释了。有疑问看Qt帮助手册有关QAndroidJniObject类的说明。
OK,到此结束。
版权所有:foruok。转载请注明出处:http://blog.csdn.net/foruok。
我的Qt on Android系列文章:
- Qt on Android:图文详解Hello World全过程
- Windows下Qt 5.2 for Android开发入门
- Qt for Android 部署流程分析
- Qt on Android:将Qt调试信息输出到logcat中
- Qt on Android: Qt 5.3.0 发布,针对 Android 改进说明
- Qt on Android Episode 1(翻译)
- Qt on Android Episode 2(翻译)
- Qt on Android Episode 3(翻译)
- Qt on Android Episode 4(翻译)
- Qt for Android 编译纯C工程
- Windows下Qt for Android 编译安卓C语言可执行程序
- Qt on Android: Android SDK安装
- Qt on Android: http下载与Json解析
- Qt on Android 之设置应用名为中文
- Qt on Android:让 Qt Widgets 和 Qt Quick 应用全屏显示
- Qt on Android:怎样适应不同的屏幕尺寸