編輯:關於Android編程
前面幾篇我們講解了 QtAndroid 名字空間的基本用法,這次我們使用前面講過的方法和類庫,展示一些簡單的小示例。我在《Qt on Android核心編程》一書中主要通過“繼承 QtActivity ,實現自己的 Activity 並添加 static 方法”這種形式來調用 Android 系統的一些功能。這一系列的文章,我們主要使用 Qt 5.3 裡引入的 QtAndroid 名字空間內的方法和 QAndroidJniObject 類來展示 Qt 中如何進行 JNI 調用,只在必要時才重寫 QtActivity 。
Qt on Android 應用,根據你的需求,經常會調用到 Android 系統提供的一些功能,比如判斷網絡連接、獲取外部存儲路徑,或者緩存文件目錄等等。這些經常被朋友問到,我會在這一系列文章中慢慢把 Qt on Android 開發中經常用到的功能點都演示一下。希望對大家有所幫助。
示例很簡單,使用 Qt Widgets 來展示。下圖是效果:
如上圖所示,界面非常簡陋,點下 Refresh 按鈕,就獲取一些 Android 系統信息和當前應用的一些信息,放在 QListWidget 中。包括下面的內容:
手機的 Android 版本網絡狀態和網絡信息手機的數據目錄手機外部存儲目錄手機的照片、音樂、視頻、鈴聲等目錄應用的路徑安裝後,系統保留的 APK 的位置應用的 files 目錄
代碼沒什麼邏輯可講……都在下面了:
#include widget.h #include#include #include #include #include #include using namespace QtAndroid; #define CHECK_EXCEPTION() if(env->ExceptionCheck()) { qDebug() << exception occured; env->ExceptionClear(); } Widget::Widget(QWidget *parent) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout(this); m_refresh = new QPushButton(Refresh); connect(m_refresh, SIGNAL(clicked()), this, SLOT(onRefresh())); layout->addWidget(m_refresh); m_list = new QListWidget(); layout->addWidget(m_list, 1); } Widget::~Widget() { } void Widget::onRefresh() { m_list->clear(); QAndroidJniEnvironment env; //get Android SDK version m_list->addItem(QString(SDK版本:%1).arg(androidSdkVersion())); QAndroidJniObject activity = androidActivity(); //get network state QAndroidJniObject connectivity = QAndroidJniObject::getStaticObjectField( android/content/Context, CONNECTIVITY_SERVICE, Ljava/lang/String;); if(connectivity.isValid()){ qDebug() << connectivity id - << connectivity.toString(); CHECK_EXCEPTION() QAndroidJniObject connectivityService = activity.callObjectMethod( getSystemService, (Ljava/lang/String;)Ljava/lang/Object;, connectivity.object ()); CHECK_EXCEPTION() qDebug() << got connectivity service - << connectivityService.isValid(); if(connectivityService.isValid()) { QAndroidJniObject networkInfo = connectivityService.callObjectMethod( getActiveNetworkInfo, ()Landroid/net/NetworkInfo;); CHECK_EXCEPTION() qDebug() << got NetworkInfo - << networkInfo.isValid(); if(networkInfo.isValid()) { m_list->addItem(QString(網絡狀態:已連接(%1)).arg(networkInfo.toString())); } else { m_list->addItem(網絡狀態:未連接); } } } //get variable directories of Android System QAndroidJniObject externalStorageDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStorageDirectory, ()Ljava/io/File; ); CHECK_EXCEPTION() m_list->addItem(QString(外部存儲目錄:%1).arg(externalStorageDir.toString())); QAndroidJniObject dataDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getDataDirectory, ()Ljava/io/File; ); CHECK_EXCEPTION() m_list->addItem(QString(數據目錄:%1).arg(dataDir.toString())); QAndroidJniObject dcim = QAndroidJniObject::getStaticObjectField( android/os/Environment, DIRECTORY_DCIM, Ljava/lang/String; ); CHECK_EXCEPTION() QAndroidJniObject dcimDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;)Ljava/io/File;, dcim.object () ); CHECK_EXCEPTION() m_list->addItem(QString(照片目錄:%1).arg(dcimDir.toString())); QAndroidJniObject music = QAndroidJniObject::getStaticObjectField( android/os/Environment, DIRECTORY_MUSIC, Ljava/lang/String; ); CHECK_EXCEPTION() QAndroidJniObject musicDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;)Ljava/io/File;, music.object () ); CHECK_EXCEPTION() m_list->addItem(QString(音樂目錄:%1).arg(musicDir.toString())); QAndroidJniObject movie = QAndroidJniObject::getStaticObjectField( android/os/Environment, DIRECTORY_MOVIES, Ljava/lang/String; ); CHECK_EXCEPTION() QAndroidJniObject movieDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;)Ljava/io/File;, movie.object () ); CHECK_EXCEPTION() m_list->addItem(QString(視頻目錄:%1).arg(movieDir.toString())); QAndroidJniObject ringtones = QAndroidJniObject::getStaticObjectField( android/os/Environment, DIRECTORY_RINGTONES, Ljava/lang/String; ); CHECK_EXCEPTION() QAndroidJniObject ringtonesDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;)Ljava/io/File;, ringtones.object () ); CHECK_EXCEPTION() m_list->addItem(QString(鈴聲目錄:%1).arg(ringtonesDir.toString())); //app's infomation QAndroidJniObject filesDir = activity.callObjectMethod( getFilesDir, ()Ljava/io/File;); CHECK_EXCEPTION() m_list->addItem(QString(應用文件目錄:%1).arg(filesDir.toString())); QAndroidJniObject packageName = activity.callObjectMethod (getPackageName); CHECK_EXCEPTION() m_list->addItem(QString(應用包名:%1).arg(packageName.toString())); QAndroidJniObject appCacheDir = activity.callObjectMethod( getCacheDir, ()Ljava/io/File;); CHECK_EXCEPTION() m_list->addItem(QString(應用緩存目錄:%1).arg(appCacheDir.toString())); QAndroidJniObject appInfo = activity.callObjectMethod( getApplicationInfo, ()Landroid/content/pm/ApplicationInfo;); CHECK_EXCEPTION() QAndroidJniObject appClassName = appInfo.getObjectField (className); CHECK_EXCEPTION() m_list->addItem(QString(應用類名:%1).arg(appClassName.toString())); QAndroidJniObject appLocation = appInfo.getObjectField( sourceDir, Ljava/lang/String;); CHECK_EXCEPTION() m_list->addItem(QString(APK位置:%1).arg(appLocation.toString())); }
其實在 Qt 中通過 JNI 調用 Android 功能,關鍵的就是兩點:
Qt提供的API怎麼用Android類庫怎麼用
Qt 提供的 API ,在“QtAndroid詳解(1):QAndroidJniObject”、QtAndroid詳解(2):startActivity和它的小伙伴們、QtAndroid詳解(3):startActivity實戰Android拍照功能這三篇文章中已有詳細講解,不再贅述了。
Android 類庫這方面,我們搞 C++ 開發的朋友,可能不熟悉。不過沒關系,可以通過 Android 在線 SDK 來學習,另外我這裡提供的 Qt JNI 代碼,都是實測可用的,裡面演示一些功能的代碼,如果需要,可以直接在項目中使用。
好了,我們開始慢慢介紹吧。
這個很貼心,QtAndroid名字空間直接提供了一個方法: androidSdkVersion() 。它返回一個整數值,表示 Android SDK 版本號。
在 Android 中,有一個 ConnectivityManager 類,可以查詢系統的網絡狀態。
ConnectivityManager 類的 getActiveNetworkInfo() 方法可以獲取到當前活躍的網絡連接信息,它返回一個 NetworkInfo 類的實例。如果未聯網,這個方法返回 null 。
ConnectivityManager 在 Android 系統裡以一個服務存在,需要通過 Context 的 getSystemService() 方法來獲取到這個服務。 getSystemService() 接受一個代表服務名字的字符串作為參數。對於網絡連接管理服務,名字是 CONNECTIVITY_SERVICE ,它是 Context 類的靜態成員變量。
獲取網絡連接管理服務的 Java 代碼如下:
Context.getSystemService(Context.CONNECTIVITY_SERVICE);
QAndroidJniObject connectivity = QAndroidJniObject::getStaticObjectField( android/content/Context, CONNECTIVITY_SERVICE, Ljava/lang/String;);
QAndroidJniObject connectivityService = activity.callObjectMethod( getSystemService, (Ljava/lang/String;)Ljava/lang/Object;, connectivity.object());
拿到了 ConnectivityManager 實例,就該調用它的 getActiveNetworkInfo() 方法來獲取當前的活動連接了。下面是代碼:
QAndroidJniObject networkInfo = connectivityService.callObjectMethod( getActiveNetworkInfo, ()Landroid/net/NetworkInfo;);
其它的都是輔助性代碼,看最前面的源碼好了。
示例裡的各種系統級的目錄,都是通過 android.os.Enviroment 這個類獲取的。
我們先說圖片、視頻、鈴聲這些吧,他們通過 getExternalStoragePublicDirectory(String) 方法獲取。Android給每個公共存儲目錄提供了一個字符串類型的名字,定義為 Enviroment 類的靜態成員變量。所以,我們使用 Qt JNI 獲取這些目錄的步驟是:
獲取目錄類型名調用getExternalStoragePublicDirectory
按照這個邏輯來看獲取圖片目錄的代碼,關鍵的就下面兩行:
QAndroidJniObject dcim = QAndroidJniObject::getStaticObjectField( android/os/Environment, DIRECTORY_DCIM, Ljava/lang/String; ); QAndroidJniObject dcimDir = QAndroidJniObject::callStaticObjectMethod( android/os/Environment, getExternalStoragePublicDirectory, (Ljava/lang/String;)Ljava/io/File;, dcim.object() );
當前應用的一些信息,可以通過 Android 裡的 Activity 類獲取。
我們需要一個 Activity 對象,在 Qt on Android 應用裡,對應的類是 QtActivity ,之前在“QtAndroid詳解(3):startActivity實戰Android拍照功能”中我們已經介紹過了。不多說了。
獲取當前應用 files 目錄的代碼如下:
QAndroidJniObject filesDir = activity.callObjectMethod( getFilesDir, ()Ljava/io/File;);
--------
好啦,這次就到這裡吧。下一次我們會展示更有意思的一些實用功能,如讓手機震動、讓屏幕常亮、動態切換橫屏豎屏等。再再往後可能還會介紹調節音量、調整屏幕亮度、使用推送、通知欄、選取聯系人等等,不過要看我的時間哈。
在之前的篇章中,我們完成了Android平台開發環境的配置,也找到了剔除OpenCV Manager API的辦法,那麼接下來我們開始從零開始,完成一個個人的程序,實現功
本文會實現一個類似網易新聞(不說網易新聞大家可能不知道大概是什麼樣子)點擊超多選項卡,選項卡動態滑動的效果。首先來看看布局,就是用HorizontalScrollView
之前在eclipse上顯示百度地圖的時候並沒有發生什麼不愉快的事,但是AS上簡直是RI了DOG。我簡直不能忍Baidu地圖API文檔,丑陋至極。1、新建一個項目,名為Ba
一、問題描述 為提高圖片加載的效率,需要對圖片的采用緩存和異步加載策略,編碼相對比較復雜,實際上有一些優秀的框架提供了解決方案,比如近期在git上比較活躍的xut