很多朋友在论坛和里问到这个,今天有时间写了个简单的示例。
功能很简单,允许你输入一个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应用中通过JNI调用第三方Jar包
谷歌官方的例子hellow-libs,andoid studio中JNI调用第三方.so库。
qt on android 关于jni的调用,英文文档,但是还是有帮助的
研究了很久,也看了Qt on Android,试了很多例子,都不能用(很可能是Qt和Android更新换代太快,很多旧的东西不能用了,所以做了这个例子。
Android studio 通过jar调用jni so库.相匹配的还有一个调用测试的demo。链接就在我的下载资源里面。
图文并茂讲述 Android studio jni如何集成第三方库文件
在Qt项目中启动一个监听SD卡插入的Android服务,并通过jni在该服务中发射Qt信号,另外在Qt中通过信号与槽机制成功获取该服务发射的信号。
教你如何生成.h文件,使用window通过NDK编译出.so文件,如何通过JNI调用so文件
一个AndroidStudio项目,通过CMakelist生成jni库文件(so),jni库文件通过头文件调用c编写的第三方库(so),文:https://blog.csdn.net/qq_35532751/article/details/78667984
《Android:JNI调用C++自定义类的详细方法》源码,具体参考:https://blog.csdn.net/chaoqiangscu/article/details/83023762
该实例是我自己写的jni调用第三方dll例子,可以作为参考,运行环境vs2010,其他环境没试过。
研究了很久,终于初步搞定了jni问题,写了一个最简单的jni调用第三方的实例,dll建立的时候全部使用的空项目,为避免其他的干扰,参数传递也选最简单的int型,以便于大家初步了解jni
Android使用JNI调用Python so解释器
有关在android平台上 JNI调用第三方动态库的例子
在QT上使用JNI接口调用JAVA代码,内有2个压缩包一个README文档,1个压缩包是在QT上使用最简单的JNI接口例子,另一个是我写的在QT上使用jNI接口调用源生安卓界面的一些功能,如系统时间设置和以太网设置。
参考网上一些资料,实现了通过JNI调用第三方动态库.so,个人觉得重点在Make文件改写,例外注意确保程序完全正确,我开始就是程序中个字母写错而浪费了好多时间。
AndroidStudio环境下的jni调用(NDK),这个教程可以让完全不会AndroidStudio的人学会jni调用。完全步骤话,非常简单。
简单jni实例调用第三方.so库
一个简单android上的jni使用用例,通俗易懂!直接编译运行即可。
android application framework api源码文件,包含jni的c,c++库文件,api和android.jar包对应