QtAndroid详解(2):startActivity和它的小伙伴们

上一篇,“QtAndroid详解(1):QAndroidJniObject”,我们做了好多好多准备工作,目的就是为使用 QtAndroid 名字空间里的 startActivity() 方法调用 Android 系统功能奠定基础。那这次呢,我们就要来研究如何使用 startActivity 方法了。

在我的书《Qt on Android核心编程》中,讲解 JNI ,介绍如何使用 JNI 扩展 Qt 应用时,是通过重写 QtActivity ,为我们的 Activity 加入静态方法来实现的,实际上从 Qt 5.3.0 以后,有更方便的方法,那就是接下来要介绍的 startActivity 了。

startActivity ,方法名字已经道出了它的功能:启动一个活动(Activity)。简单的说,在 Android 里,Activity就是布满整个窗口或者悬浮于其他窗口上的交互界面。通常用户可见的功能,都是与 Activity 关联的,比如我们用微信、微博、美团,我们看到的那些界面,可操作的东东,都是与 Activity 息息相关的。

行,背景就这么多吧,要是感兴趣,可以问下度娘,或者到 https://developer.android.com/index.html 上看看 Android 的在线文档。不过貌似打不开哈……

我们先详细介绍一下 startActivity 方法,然后再举例来看使用 startActivity 调用一个活动的两种情况。

startActivity方法详解

startActivity 方法原型如下:

void	startActivity(const QAndroidJniObject & intent, int receiverRequestCode, QAndroidActivityResultReceiver * resultReceiver = 0);

如你所见,startActivity 有三个参数。

第一个是 intent ,我们在“QtAndroid详解(1):QAndroidJniObject”中举例时已经介绍了 Android 提供的 Intent 类,这里的 intent 参数实际上就是一个 Java Intent 对象。

第二个参数是 receiverRequestCode ,实际上是一个标识符,用来标记一次 startActivity 调用,当你启动一个 Activity 时,这个 request code 会传递过去,当你调用的 Activity 结束时,你会得到一个通知,这个通知里又把你传的 request code 带回给你,同时呢,这个通知还带回来你调用的那个 Activity 执行的结果,叫作 result code 。更厉害的是,你调用的 Activity ,还可以传递更多的数据回来,而这些数据呢,又是通过一个 Intent 携带的。

为了处理你调起的 Activity 的返回结果,在 Qt 代码中,我们需要一个 QAndroidActivityResultReceiver 对象,这就是第三个参数了。

实际上, Qt 提供的 startActivity 方法是个混搭,根据参数的不同,分别对应了 Android Activity 类的 startActivity(Intent) 和 startActivityForResult(Intent, int) 两个方法。追本溯源,还是来看看 Android 的文档吧,这样更清楚些。

Android 中的 startActivity 和 startActivityForResult

首先看 startActivity ,它是 Activity 类的方法,原型如下:

void startActivity(Intent intent);

在 Android 文档中有两处对 startActivity 的描述:

1. Launch a new activity. You will not receive any information about when the activity exits.

2. The startActivity(Intent) method is used to start a new activity, which will be placed at the top of the activity stack. It takes a single argument, an Intent, which describes the activity to be executed.

我翻译一下,中文如下:

1. 启动一个新活动。当新活动结束时,你收不到任何消息。

2. startActivity(Intent) 方法用来启动一个新活动,这个新活动将被放在活动栈的顶端。这个方法接受一个意图(Intent)作为参数,而作为参数的意图,描述了要执行的活动的相关信息。

哦嘛,就是这啦,startActivity 启动一个与调用者分离的活动,新活动起来后就自生自灭,调用者既不关心它的死活也不关心它干嘛有什么后果。

再来看 startActivityForResult 方法,它也是 Activity 的方法。原型如下:

public void startActivityForResult (Intent intent, int requestCode);

从名字就可以看出来,startActivityForResult ,启动一个新活动的目的就是为了拿到新活动的结果。就是说,它对新活动很 care ,你要干个事儿,还得带个结果回来给我。比方说你从通讯录里挑个人儿给我,那你结束时,如果谁也没挑,那就告诉我失败;如果你挑了个人儿,就告诉我成功,并且还得让我有地方获得你挑的那个人儿的信息。

intent 参数与 startActivity 的参数含义完全一样,不必再提。

requestCode 参数,用来标识一次调用,当新 Activity 结束后,这个 requestCode 会通过 onActivityResult() 方法返回给调用方。这里的 requestCode ,与 QtAndroid 提供的 startActivity 的第二个参数是一致的。

那接下来该说到怎么接收新 Activity 的返回结果了。

Android中 Activity 类的 onActivityResult 方法

当我们使用 startActivityForResult 启动一个新的 Activity 时,目的是为了做点什么事儿获取一些信息,那如何知道新 Activity 结束了、执行情况如何、带回什么东东呢? Android 为 Activity 类设计了 onActivityResult 方法,我们在 extends Activity 时可以重写这个方法,根据 requestCode 来区分一次调用,判断调用结果,抽取新 Activity 携带的数据。

onActivityResult 方法原型如下:

protected void onActivityResult (int requestCode, int resultCode, Intent data);

如你所见,它有三个参数。

第一个参数 requestCode 是我们调用 startActivityForResult 时传递的。

第二个参数 resultCode 是新 Activity 的执行结果,有两种,一种是 RESULT_OK(实际上为 -1 ),一种是 RESULT_FAILED(实际上是0)。 这两个值有点诡异啊,不符合我的习惯。当你在 C++ 中来编程时,不使用 RESULT_OK 和 RESULT_FAILED 两个常量,直接使用数字字面量,就容易搞反(C的习惯,0是OK,-1是FAILED)。

第三个参数是一个 Intent 对象,携带了新 Activity 返回的数据。

Android中的Intent

前面不止一次提到 Android 的 Intent ,对 Android 开发人员来讲 Intent 是很熟悉的一种存在,对 Qt 开发人员来讲 Intent 可能还是有些陌生,我们再花点篇幅介绍一下。

Intent 在 android.content 包中,全路径类名为 android.content.Intent ,我们在“QtAndroid详解(1):QAndroidJniObject”中举例时也提到过。

Intent 类是 Android 提供的、用于组件间通信的一种机制。它是待执行操作的一个抽象描述,它可以与 startActivity() 配合来启动一个活动,与 broadcastIntent() 配合来发送一个广播,也可以与 startService() 或 bindService() 配合以便与后台服务进行通信。

Intent 最常见的用途就是启动活动,通过 Intent ,你可以调用其它的系统功能或第三方提供的功能,比如你可以调用拨打电话的功能,可以显示联系人,也可以调用相机。

我们在使用 Intent 时可以指定一个 action ,action 代表你要做的动作,也就是你想干啥;还可以在 Intent 中携带数据给被调用的一方。而被调起的一方(Activity或Service)则可以通过 Intent 的 getData() 、 getBundle() 、 getXxxExtra() 等方法来获取调用者传递过来的数据。Intent 就像 Android 组件之间的信使,可以告诉我们要做什么,以及有哪些数据可用。

Intent 有好几个构造函数,我们可能会用到下面两个:

  • Intent(String action)
  • Intent(String action, Uri uri)

Intent 还提供了很多方法,允许我们设置 action 和 data ,下面列出的仅仅是一小部分:

  • setAction(String action)
  • putExtra(String name, int value)
  • putExtra(String name, CharSequence value)
  • putExtra(String name, Bundle value)
  • setData(Uri data)

要想用 Intent 调用某个组件,就需要指定 action ,那 action 到底是什么玩意儿呢?

action 实际上是一个字符串,代表了某个组件,当你传递一个 Intent 对象给 startActivity() 等方法时, Android 框架会来解析这个 Intent 的 action ,找到 action 代表的组件并调用它。解析的过程比较复杂,也有很多规则,我们可以简单的理解为 Android 有一张表,登记了系统中的各种组件,当你给出"com.android.settings.SETTINGS"这样的action时,Android就会在这个表中查找到设置组件并启动它。Intent预定义了很多 action ,感兴趣的可以到 Android 在线帮助中查看 Intent 的文档。

好啦,Android 中与 startActivity 相关的背景知识就介绍到这里吧,是时候回过头来看我们的 QtAndroid 了。

QAndroidActivityResultReceiver

Qt 使用 startActivity 一个方法对应了 Android 的 startActivity 和 startActivityForResult 两个方法。当我们提供 requestCode 和 resultReceiver 两个参数时,就对应 Android Activity 的方法 startActivityForResult ,而 resultReceiver 参数就是与 Android Activity 的 onActivityResult 方法适配的,它的类型是 QAndroidActivityResultReceiver 。

QAndroidActivityResultReceiver 是一个纯虚类,定义了一个接口,原型如下:

virtual void	handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject & data) = 0;

看到了吧,handleActivityResult 方法和 Android Activity 的 onActivityResult 是完全匹配的。唯一不同的是,第三个参数转换为了 QAndroidJniObject ,实际上就是一个 Intent 对象。

为了处理 Activity 的返回结果,我们需要实现 QAndroidActivityResultReceiver 接口,比如:

class ResultReceiver: public QAndroidActivityResultReceiver
{
public:
    int requestId;

    void	handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject & data)
    {
        if(receiverRequestCode == requestId)
        {
            if(resultCode == RESULT_OK)
            {
                //some code here
            }
            else
            {
                //some code here
            }
        }
    }
};

需要注意的是,QAndroidActivityResultReceiver 是被异步调用的,因此当你提供一个对象用于接收新调起的 Activity 的返回结果时,这个对象最好是从堆上构造(new),如果你把 QAndroidActivityResultReceiver 放在栈上,很可能带来灾难性的后果,当 Qt 收到被调起的 Activity 的返回结果时,你提供的 receiver 可能已经析构了,你就悲剧了,崩溃吧你。

调用Android活动

我乖,终于来了吗……

OK,要说到如何调用 Android Activity 了,真不容易啊,铺垫忒长。

在 Qt 中调用 Android Activity ,根据是否关注结果来划分,有两种方式:

  • 告知式调用,不管结果
  • 追问式调用,要求结果

不管结果的调用可能是酱紫的:

    QAndroidJniObject action = QAndroidJniObject::fromString("android.settings.SETTINGS");
    QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", action.object<jstring>());
    startActivity(intent, 0);

关注结果的调用可能是酱紫的:

    ResultReceiver *receiver = new ResultReceiver(1);
    QAndroidJniObject action;
    QAndroidJniObject intent("android/content/Intent","(Ljava/lang/String;)V", action.object<jstring>());
    startActivity(intent, 1, receiver);

不知不觉又写了这么长了,看来实例要等到下一次了……

------------

回顾一下:

时间: 2024-08-25 18:37:30

QtAndroid详解(2):startActivity和它的小伙伴们的相关文章

QtAndroid详解(3):startActivity实战Android拍照功能

在"QtAndroid详解(1):QAndroidJniObject"中,我们介绍了 QAndroidJniObject 这个 Qt JNI 的核心类,在""中我们介绍了 startActivity 以及与它配套的一些 Android 背景知识,这次我们来看一个实例,演示如何使用 startActivity 来调用 Android 系统功能,同时也演示 QAndroidJniObject 的常见用法. 实例介绍 先看下实例效果,然后再论. 我们只是演示 API 用法

QtAndroid详解(5):JNI调用Android系统功能(2)

在"QtAndroid详解(4):JNI调用Android系统功能(1)"中我们给出了一些简单的示例,演示了如何使用 Qt JNI 类库访问网络状态.系统资源目录.当前应用信息等等,这次呢,我们提供一些新的示例,这些示例可能更具实际意义.本文的示例包括: 震动 让屏幕常亮 动态改变应用的显示方向(横屏.竖屏) 调节屏幕亮度 设置铃声模式 示例介绍 图1 我们按照界面上的顺序,一个一个来看这些功能如何实现. 源码分析 构建界面的代码在 Widget 类的构造函数里,不说了.这次我们换个搞

QtAndroid详解(6):集成信鸽推送

推送是我们开发移动应用经常用到的功能,Qt on Android 应用也会用到,之前也有朋友问过,这次我们来看看怎么在 Qt on Android 应用中来集成来自腾讯的信鸽推送. 有关信鸽的 SDK 和集成指南,请到这里(http://xg.qq.com/)查看.本文是参考腾讯信鸽的在线帮助完成的.信鸽的 WIKI 和文档已经做得很好了,照着做就是,这里只讲 Qt 中集成信鸽时的步骤和注意事项. 这次我们要写一点点 Java 代码,就几行,如何做,可以参考<Qt on Android核心编程>

QtAndroid详解(1):QAndroidJniObject

Qt 5.3之后,新增了 QtAndroid 名字空间,内有下列四个方法: QAndroidJniObject AndroidActivity() int androidSdkVersion() void startActivity(const QAndroidJniObject & intent, int receiverRequestCode, QAndroidActivityResultReceiver * resultReceiver = 0) void startIntentSende

Kafka Broker常用配置详解

broker的配置文件位于kafka的config/server.properties文件.     Broker基本配置 broker.id:代理Id,必须是唯一的整数.可以是0,1,2,3这样的自定义编号,也可以是IP地址的最后一位,如23,24,25,建议使用后面的编码方式. auto.leader.rebalance.enable:是否允许leader节点自动分配,启用的话,会有后台进程定时检查并触发转移leader操作.默认启用. background.threads:后台处理任务的进

iptables详解之filter

iptables详解之filter iptables令很多小伙伴脑阔疼,下面我们来说说如何使用iptables. 一.iptables格式 1.1.iptables 帮助 通过iptables --help查看一下iptables用法 [[email protected] ~]# iptables --help iptables v1.4.21 Usage: iptables -[ACD] chain rule-specification [options] iptables -I chain

Android四大组件之——Activity的开启:StartActivity()和StartActivityForResult()(图文详解)

            如需转载请在文章开头处注明本博客网址:http://www.cnblogs.com/JohnTsai       联系方式:[email protected]       [Android四大组件学习系列Activity篇]        1.Android四大组件之——Activity(一)定义.状态和后退栈(图文详解) 2.Android四大组件之——Activity的生命周期(图文详解) 3.Android四大组件之——Activity的开启StartActivit

startActivityForResult和setResult详解

原文:startActivityForResult和setResult详解 startActivityForResult与startActivity的不同之处在于:1.startActivity( ) 仅仅是跳转到目标页面,若是想跳回当前页面,则必须再使用一次startActivity( ).2.startActivityForResult( ) 可以一次性完成这项任务,当程序执行到这段代码的时候,假若从T1Activity跳转到下一个Text2Activity,而当这个Text2Activit

Android网络请求框架AsyncHttpClient实例详解(配合JSON解析调用接口)

最近做项目要求使用到网络,想来想去选择了AsyncHttpClient框架开进行APP开发.在这里把我工作期间遇到的问题以及对AsyncHttpClient的使用经验做出相应总结,希望能对您的学习有所帮助. 首先按照惯例先来简单了解一些AsyncHttpClient网络框架的一些知识. 1.简介 Android中网络请求一般使用Apache HTTP Client或者采用HttpURLConnect,但是直接使用这两个类库需要写大量的代码才能完成网络post和get请求,而使用android-a