Qt for Android (三) 開啟Android相簿並選一個圖片進行顯示
阿新 • • 發佈:2020-05-08
這兩天弄了一下android相簿的相關功能。還是花了挺長時間的,這裡總結一下,避免以後再踩坑。同時也在這篇文章裡面補齊一些android開發的基礎支援
## 開啟Android相簿並選一個圖片進行顯示
**分為幾個步驟:**
1. QtCreator新建Android工程
本例使用的是arm64-v8 Android開發套件。
2. 構建工程並在構建目錄中找到AndroidManifest.xml
建立的Android工程build之後都會在**android-build**根目錄下生成一個AndroidManifest.xml檔案。這個檔案是android開發很重要個的一個檔案,是應用清單。專案中引用的java包、app的橫屏和豎屏、app的是否全屏等等很多功能都是在裡面設定的。下面有一些詳細的參考文章:
[AndroidManifest.xml詳解](https://www.jianshu.com/p/3b5b89d4e154)
3. 在工程中新增AndroidManifest.xml和java檔案。
java檔案是自己建立的用來寫一些java程式碼呼叫android原生功能的相當於c++中的一個類的檔案。
java檔案可以從網上找一個來參考著寫。等會我會附上gitee的地址供大家參考。
放出java的程式碼簡單看一下吧:
```java
public class OpenAndroidAlbum extends QtActivity
{
public static native void fileSelected(String fileName);
static final int REQUEST_OPEN_IMAGE = 1;
public String lastCameraFileUri;
static final int REQUEST_CAPTURE_IMAGE = 2;
private static OpenAndroidAlbum m_instance;
public OpenAndroidAlbum()
{
m_instance = this;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy()
{
super.onDestroy();
}
static void openAnImage()
{
m_instance.dispatchOpenGallery();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
System.out.println("===dispatchOpenGallery1===");
if (resultCode == RESULT_OK)
{
if(requestCode == REQUEST_OPEN_IMAGE)
{
String filePath = getRealPathFromURI(getApplicationContext(), data.getData());
fileSelected(filePath);
}
}
else
{
// fileSelected(":(");
}
super.onActivityResult(requestCode, resultCode, data);
}
private void dispatchOpenGallery()
{
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_OPEN_IMAGE);
}
public String getRealPathFromURI(Context context, Uri contentUri)
{
Cursor cursor = null;
try
{
String[] proj = { MediaStore.Images.Media.DATA };
cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
System.out.println(column_index);
return cursor.getString(column_index);
}
finally
{
if (cursor != null)
{
cursor.close();
}
}
}
}
```
* **fileSelected**這個靜態函式是我們在c++程式碼中定義的。java和c++的混合程式設計是通過JNI來實現的,
```c++
#ifdef Q_OS_ANDROID
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL
Java_org_qtproject_example_OpenAndroidAlbum_OpenAndroidAlbum_fileSelected(JNIEnv */*env*/,
jobject /*obj*/,
jstring results)
{
selectedFileName = QAndroidJniObject(results).toString();
qDebug() << "fileName = " << selectedFileName;
}
#ifdef __cplusplus
}
#endif
#endif
```
名字看起來很長*Java*是固定頭部,*org_qtproject_example_OpenAndroidAlbum*這個是java包名,*OpenAndroidAlbum*是類名,最後*fileSelected*這個才是函式名。需要注意的是**由於jni函式名對映成java函式名的時候是依靠“_”來間隔包、類、方法的,如果你的函式中有“_”字元的話,jni必須能夠區分函式名中的“_”是字元還是分隔符,所以在函式名前面需要加1用於區分。**
由於JNI的函式是c函式,所以要加上`extern "C"`。這樣定義好之後的函式就可以在java中直接呼叫了,還是很方便的。
* **openAnImage**是我們定義開啟圖片按鈕的響應函式
java中定義的函式在c++中呼叫的方法是通過Qt的**QAndroidJniObject**類的一個靜態方法實現的:
```c++
QAndroidJniObject::callStaticMethod("org/qtproject/example/OpenAndroidAlbum/OpenAndroidAlbum",
"openAnImage",
"()V");
```
第一個引數是類名其實也是包名,是在java檔案中通過
`package org.qtproject.example.OpenAndroidAlbum;`
定義的。
* **dispatchOpenGallery**這個方法用來呼叫相簿
通過*Intent*物件和*startActivityForResult*實現呼叫。這裡有一個坑,`Intent intent = new Intent(Intent.ACTION_PICK);`建立物件的時候**ACTION_PICK**這個列舉要用對,4.4以後的版本好像要用這個,我也是之前怎麼都打不開相簿,改了這個列舉之後就可以了。
* **onActivityResult**在相簿中選中一張圖片之後會呼叫這個回撥
很自然就會想到我們在c++中定義的*fileSelected*函式要在這個地方呼叫了。把路徑轉換成java的String型別,呼叫`fileSelected(filePath)`就可以在Qt程式碼中處理圖片路徑了。
4. 在Qt程式碼中呼叫java的開啟相簿的方法,同時利用JNI定義一個c++的處理方法
這個我們在上一條中也提到了。這裡提一下編碼中容易出錯的地方
```c++
QAndroidJniObject::callStaticMethod("org/qtproject/example/OpenAndroidAlbum/OpenAndroidAlbum",
"openAnImage",
"()V");
```
第一個字串代表java包,相當於一個c++的類。如果遇到編譯過程中遇到**“找不到類"**的類似錯誤提示檢查一下第一個字串,最後是以**OpenAndroidAlbum.java**包的字首結尾的,切記!!!
5. AndroidManifest.xml要做相應的修改
上面也提到了,這個檔案是清單列表可以用來指定要呼叫j的ava包
```XML
```
把**package=**這個包名的屬性做對應的修改。
6. 完成了上述5點之後還要修改軟體的許可權,獲取**允許開啟相簿**的許可權之後才能正常的開啟相簿圖片
gitee地址:https://gitee.com/guiguzicom/Demo/tree/master/OpenAndr