欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Kotlin入门(21)活动页面的跳转处理

程序员文章站 2022-03-18 14:49:50
Activity的活动页面跳转是App最常用的功能之一,在前几章的demo源码中便多次见到了,常常是点击界面上的某个按钮,然后跳转到与之对应的下一个页面。对于App开发者来说,该功能的实现非常普通,使用Java编码不过以下两行代码而已: 上面代码的关键之处在于Intent的构造函数,其中第一个参数指 ......

activity的活动页面跳转是app最常用的功能之一,在前几章的demo源码中便多次见到了,常常是点击界面上的某个按钮,然后跳转到与之对应的下一个页面。对于app开发者来说,该功能的实现非常普通,使用java编码不过以下两行代码而已:

    intent intent = new intent(mainactivity.this, linearlayoutactivity.class);
    startactivity(intent);

 

上面代码的关键之处在于intent的构造函数,其中第一个参数指定了页面跳转动作的来源,即mainactivity这个源页面,mainactivity.this通常简写为this;构造intent的第二个参数则表示页面跳转动作的目的地,即linearlayoutactivity这个目标页面。倘若把这两行java代码转换为kotlin代码(复制这两行然后粘贴到kt文件中,android studio就会自动完成转换),则可看到活动跳转的kotlin代码如下所示:

    val intent = intent(this@mainactivity, linearlayoutactivity::class.java)
    startactivity(intent)

 

对比之下,这里的kotlin代码与java代码主要有两点不同之处:
1、在类内部指代自身的this关键字,java的完整写法是“类名.this”,而kotlin的完整写法是“this@类名”,当然二者均可简写为“this”;
2、获取某个类的class对象,java的写法是“类名.class”,而kotlin的写法是“类名::class.java”,一看便知带有浓浓的java风味;
看起来,kotlin代码与java代码半斤八两,未有明显的简化,令人产生小小的失望。但细心的读者也许已经注意到了,本书附录源码里的活动跳转,并非上述的kotlin正宗写法,而是下面这种简化版的写法:

    startactivity<linearlayoutactivity>()

 

究其原因,乃是anko库利用kotlin的扩展函数,给context类新增了名为startactivity的新方法。故而使用简化版的写法之前,必须先导入anko库的指定文件,即在kt文件头部添加下面一行导入语句:

import org.jetbrains.anko.startactivity

 

活动页面跳转的时候,往往还要携带一些请求参数,如果使用java编码,可以很轻松地调用intent对象的putextra方法,通过“putextra(参数名, 参数值)”的方式传递消息,就像下面代码那样:

    intent intent = new intent(this, actsecondactivity.class);
    intent.putextra("request_time", dateutil.getnowtime());
    intent.putextra("request_content", et_request.gettext().tostring());
    startactivity(intent);

 

如果使用anko的简化写法,其实也很容易,只要在startactivity后面的括号中依次填上每个参数字段的字段名和字段值,具体的kotlin跳转代码如下所示:

    //第一种写法,参数名和参数值使用关键字to隔开
    startactivity<actsecondactivity>(
            "request_time" to dateutil.nowtime,
            "request_content" to et_request.text.tostring())

 

注意到上面的写法使用关键字to隔开参数名和参数值,感觉不够美观,而且容易使人迷惑,to后面究竟要跟着字段名还是字段值呢?所以anko库提供了另一种符合习惯的写法,也就是利用pair类把参数名和参数值进行配对,pair的第一个参数为字段名,第二个参数为字段值。据此改写后的kotlin跳转代码如下所示:

    //第二种写法,利用pair把参数名和参数值进行配对
    startactivity<actsecondactivity>(
            pair("request_time", dateutil.nowtime),
            pair("request_content", et_request.text.tostring()))

 

不管哪种写法,在下一个活动中解析请求参数的方式都一样,都得先获取bundle对象,然后分别根据字段名称获取对应的字段值。具体的请求参数解析代码如下所示:

class actsecondactivity : appcompatactivity() {

    override fun oncreate(savedinstancestate: bundle?) {
        super.oncreate(savedinstancestate)
        setcontentview(r.layout.activity_act_second)
        val bundle = intent.extras
        val request_time = bundle.getstring("request_time")
        val request_content = bundle.getstring("request_content")
        tv_response.text = "收到请求消息:\n请求时间为${request_time}\n请求内容为${request_content}"
    }
}

下面通过测试界面观察一下消息数据发送之前和发送之后的效果,如下面左图所示,这时第一个页面准备跳转到第二个页面;如下面右图所示,这是跳转后的第二个页面,界面上展示了第一个页面传递过来的参数信息。

Kotlin入门(21)活动页面的跳转处理

Kotlin入门(21)活动页面的跳转处理

activity之间传递的参数类型,除了整型、浮点数、字符串等基本数据类型,还允许传递序列化结构如parcelable对象。这个parcelable对象可不是简单的实体类,而是实现了parcelable接口的实体类,实现接口意味着该类必须重写接口定义的所有方法,不管你愿不愿意都得老老实实地照猫画虎。譬如前面的活动跳转传递了两个字段数据,如果把这两个字段放到parcelable对象中,仅仅包含两个字段的parcelable类对应的java代码也如下面这般冗长:

public class messageinfo implements parcelable {
    public string content;
    public string send_time;

    // 写数据
    @override
    public void writetoparcel(parcel out, int flags) {
        out.writestring(content);
        out.writestring(send_time);
    }

    // 例行公事实现createfromparcel和newarray
    public static final parcelable.creator<messageinfo> creator
            = new parcelable.creator<messageinfo>() {
        // 读数据
        public messageinfo createfromparcel(parcel in) {
            messageinfo info = new messageinfo();
            info.content = in.readstring();
            info.send_time = in.readstring();
            return info;
        }

        public messageinfo[] newarray(int size) {
            return new messageinfo[size];
        }
    };

    @override
    public int describecontents() {
        return 0;
    }
}

看看这架势,如此简单的自定义parcelable类,就得重写包括writetoparcel、createfromparcel、newarray、describecontents在内的四个方法,可谓是兴师动众。由此可见这里又是java的一个痛点,正适合kotlin施展拳脚、好好改进。在第五章的类和对象中,介绍了kotlin对数据类的写法,在类名前面关键字data,kotlin即可自动提供get/set、equals、copy、tostring等诸多方法。那么序列化对象的改造也相当简单,仅需在类名之前增加一行注解“@parcelize”就好了,整个类的kotlin代码只有下面寥寥几行:

@parcelize
data class messageinfo(val content: string, val send_time: string) : parcelable {
}

 

不过若想正常编译,还需修改模块的编译文件build.gradle,在文件末尾添加下面几行,表示增加安卓插件的编译支持:

//@parcelize标记需要设置experimental = true
androidextensions {
    experimental = true
}

 

编译文件修改完毕,现在能在kotlin中使用序列化对象的注解了。虽然自定义的messageinfo类内部没有任何一行代码,但是它除了具备数据类的所有方法,也自动实现了parcelable接口的几个方法。接下来就可以利用该类传输活动跳转的序列化数据了,下面是改写后的kotlin跳转代码:

    val request = messageinfo(et_request.text.tostring(), dateutil.nowtime)
    startactivity<parcelablesecondactivity>("message" to request)

 

跳转后的下一个页面,调用getparcelable即可正常获得原始的序列化数据,具体的数据解析代码如下所示:

class parcelablesecondactivity : appcompatactivity() {

    override fun oncreate(savedinstancestate: bundle?) {
        super.oncreate(savedinstancestate)
        setcontentview(r.layout.activity_parcelable_second)
        val request = intent.extras.getparcelable<messageinfo>("message")
        tv_response.text = "收到打包好的请求消息:\n请求时间为${request.send_time}\n请求内容为${request.content}"
    }
}

同样通过测试界面观察序列化对象的打包和解包效果,如下面左图所示,这时第一个页面准备跳转到第二个页面;如下面右图所示,这是跳转后的第二个页面,界面上展示了第一个页面传递过来的序列化数据。

 Kotlin入门(21)活动页面的跳转处理

Kotlin入门(21)活动页面的跳转处理