佳木斯新闻:Qt for Android (三) 打开Android相册并选一个图片举行显示

admin 5个月前 (05-09) 科技 33 0

更新:

  1. 修改了一些逻辑错误
  2. 添加了一些图示说明

这两天弄了一下android相册的相关功效。照样花了挺长时间的,这里总结一下,制止以后再踩坑。同时也在这篇文章内里补齐一些android开发的基础支持

打开Android相册并选一个图片举行显示

分为几个步骤:

  1. QtCreator新建Android工程

    本例使用的是arm64-v8 Android开发套件。

  2. 构建工程并在构建目录中找到AndroidManifest.xml

    建立的Android工程build之后都会在android-build根目录下天生一个AndroidManifest.xml文件。这个文件是android开发很主要个的一个文件,是应用清单。项目中引用的java包、app的横屏和竖屏、app的是否全屏等等许多功效都是在内里设置的。下面有一些详细的参考文章:

    AndroidManifest.xml详解

  3. 在工程中添加AndroidManifest.xml和java文件。

    这里需要详细说一下Qt建立android工程的特殊步骤,如下图所示:

    建立android工程我们需要点击上图的按钮来建立模板,建立好的工程目录如下图:

    QtCreator会自动为我们建立如下一系列文件其中我们暂时用到的是AndroidManifest.xml文件。之后我们要把步骤2中提到的相同文件拷贝到该目录下面做替换。同时我们天生的挪用相册方式的java文件也需要拷贝到这个目录下面,存放的目录结构如下:

    那么这么一长串的目录的建立依据是什么呢,就是我们的java文件内里界说的包名

    package org.qtproject.example.OpenAndroidAlbum;程序运行起来之后会凭据目录结构找到我们的java包。固然我们也可以自己在工程根目录下建立android目录,只放入java后缀的文件和AndroidManifest.xml文件。这个目录的最终作用照样在程序构建的时刻会把目录下面的文件拷贝到我们的构建目录下面,

    佳木斯新闻:Qt for Android (三) 打开Android相册并选一个图片举行显示 第1张

    这里红色框框内里的器械会被我们建立的工程目录下的器械给替换掉,内里的一些文件详细是做什么的感兴趣的小伙伴可以自己去研究一下,总之我们需要的主要就是两个文件。

    java文件是自己建立的用来写一些java代码挪用android原生功效的相当于c++中的一个namespace的文件。

    java文件可以从网上找一个来参考着写。在文章的末尾我会附上gitee的地址供人人参考。

    放出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来实现的,

    #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类的一个静态方式实现的:

    QAndroidJniObject::callStaticMethod<void>("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代码中处置图片路径了。

  1. 在Qt代码中挪用java的打开相册的方式,同时行使JNI界说一个c++的处置方式

    这个我们在上一条中也提到了。这里提一下编码中容易失足的地方

        QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/OpenAndroidAlbum/OpenAndroidAlbum",
                                                  "openAnImage",
                                                  "()V");
    

    第一个字符串代表java包,相当于一个c++的类。若是遇到编译过程中遇到“找不到类"的类似错误提醒检查一下第一个字符串,最后是以OpenAndroidAlbum.java包的前缀末端的,切记!!!

  2. AndroidManifest.xml要做响应的修改

    完成了以上步骤还不算完,若是这时刻直接执行程序会报错:

    JNI DETECTED ERROR IN APPLICATION: JNI GetStaticMethodID called with pending exception java.lang.NullPointerException: Attempt to invoke direct method 'void org.qtproject.example.OpenAndroidAlbum.OpenAndroidAlbum.dispatchOpenGallery()' on a null object reference

    从错误提醒上可以推断出是挪用了空工具的方式导致的。剖析java代码m_instance.dispatchOpenGallery();打开相册的时刻我们挪用了这句话,而m_instance我们是在

     public OpenAndroidAlbum()
        {
            m_instance = this;
        }
    

    组织函数举行初始化的,我们挪用的是静态方式,确实没有举行实例化。这里怎么解决呢?这就要用到两个地方了,我们界说的java类继续于QtActivity,而清单文件AndroidManifest.xml内里有一个activity标签,这个标签就是用来指定activity对应的类的,清单文件此时发挥了它”清单“的作用。此标签先容如下:

    该元素声明一个实现应用可视化界面的Activity(Activity类子类)。这是 元素中需要的子元素。所有Activity都必须由清单文件中的 元素示意。任何未在该处声明的Activity对系统都不可见,而且 永远不会被执行

    作者:闪电的蓝熊猫
    链接:https://www.jianshu.com/p/3b5b89d4e154
    泉源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    我们把activity标签下的属性 修改成org.qtproject.example.OpenAndroidAlbum.OpenAndroidAlbum即可。这个是不是很眼熟呢,没错就是我们在cpp中写的

    QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/OpenAndroidAlbum/OpenAndroidAlbum",
                                                  "openAnImage",
                                                  "()V");
    

    第一个参数。这样的对应关系保证没错的话就可以顺遂打开相册了。

  3. 完成了上述5点之后只是能打开相册而已,若是要读取内里的图片还要修改软件的权限,获取允许打开相册的权限之后才气正常的打开相册图片

gitee地址:https://gitee.com/guiguzicom/Demo/tree/master/OpenAndroidAlbum

,

皇冠APP

皇冠体育APP是一个开放皇冠代理APP下载、皇冠会员APP下载、皇冠线路APP下载、皇冠登录APP下载的平台,皇冠体育APP上最新登录线路、新2皇冠网址更新最快,皇冠体育APP开放皇冠会员注册、皇冠代理开户等业务。

Allbet声明:该文看法仅代表作者自己,与本平台无关。转载请注明:佳木斯新闻:Qt for Android (三) 打开Android相册并选一个图片举行显示

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:709
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1303
  • 评论总数:292
  • 浏览总数:21534