做过asp.net或其他web开发的朋友都知道,想要在两个网页间做转换,只要利用超链接就可以实现。但在手机里,要如何实现手机页面之间的转换呢?最简单的方法就是改变Activity的Layout。首先准备两个布局文件Main.axml和Layout2.axml。在Layout1中放置一个按钮,当单击时,显示Layout2,同样地,在Layout2里也放一个按钮,当单击时回到Main.
然后在Activity1.cs中的OnCreate方法里加入如下代码:
运用改变Activity的Layout这个技巧,就可以做出手机页面转换的效果,当然也可以搭配之前介绍的Style设置,进行更加灵活的布局配置运用。再者,利用SetContentView来置换页面还有一个特别的优点,即所有程序里的变量皆存在相同的状态,无论是类成员、类方法等,都在一个Activity的状态中直接取得,并没有参数传递的问题。比如要进行分步导航的页面,从第一个页面得到的信息无需传递到第二个页面,而是一直存放在当前Activity的成员中,可以随时拿来使用。
如果要转换的页面不单只是背景,颜色或文字的内容的不同,而是Activity的置换,那就不是单单改变Layout就能完成的了。尤其是需要传递的数据不像网页可以通过Session或Cache来实现,在程序里移交主控权到另一个Activity,光靠先前的Layout技巧是办不到的。
那要如何解决Activity控制权的移交呢?在MonoDroid里,可以在主程序中使用StartActivity方法来调用另一个Activity(主程序本身就是一个Activity),但当中的关键并不在StartActivity这个方法,而是Intent这个特有的对象。Intent就如同其英文字义,是“想要”或“意图”之意,在主Activity中,告诉程序自己是什么,并想要前往哪里,这就是Intent对象所处理的事情了。
布局文件与刚才一样,不同的是程序代码,修改Activity.cs如下,在这里教大家另外一个绑定控件事件的方法,在.net程序里,我们要绑定事件,只要在事件名后+=事件处理对象或lambda表达式即可,如btn.Click += (sender, e) => { };在MonoDroid里,为了与Java中的写法保持一致,除了上面这种方式之外,还提供了另外一种方式,即SetOnXXXListener方法。如按钮的Click事件,就调用SetOnClickListener,传入的参数是实现View.IOnClickListener的类。另外,要实现Java中的借口,你的类还要继承Java.Lang.Object类,这样就无需实现IObject的Handle属性了。
在Activity1和Activity2两个类里都调用了Finish()这个方法,它代表这个Activity已经运作完毕,当系统接收到这个命令时,即会关闭此Activity,所以此时单击模拟器的返回(Back)键,并不会回到上一个Activity的画面,如果要让模拟器的返回键有回上一页的效果,可以将此行代码注释掉。同理,在两个Acitivity在切换时,并非真的只有两个Activity在切换,而是在单击按钮时再重新调用一个新的Activity。
若需要在调用另一个Activity的同时传递数据,那么就需要利用Bundle对象来封装数据了。将想要传递的数据或参数通过Bundle来传递不同Intent之间的数据。
我们从Activity1调用Activity2的同时,把一个字符串和一个整型传到Activity2试试,对ClickListener类的OnClick方法增加几行代码:
然后在Activity2中进行接收这两个值,为了在Activity2加载后弹出提示,我们先来封装一个信息框提示类。这里要用到AlertDialog窗口,它常用于“程序提示”,“警告”或“确认”等。
然后我们再在Activity2中使用这个类来显示从Activity1传递过来的参数:
运行结果:
Bundle对象针对不同的数据类型提供了多种方法,例如上面传递string类型的数据,使用了PutString,而要传递double类型的数据,使用PutDouble,反之,要从Bundle对象取出数据,就把Put改为Get即可。我曾经尝试传递非基础类型的数据,即自定义类型的数据,但无论我的对象是实现了Java.IO.ISerializable,然后调用PutSerializable方法,还是实现IParcelable,调用PutParcelable方法,在Get的时候都会报错,实在无奈,如果有哪位朋友能够成功传递自定义类型的数据的话,还请共享一下。
在上一个范例中,好不容易将数据从Activity1传递到Activity2,如果要再回到Activity1,数据该不会要再封装一次吧?而且前一个Activity1早就被destroy了,倘若在Activity1最后以Finish()结束程序,再通过Activity2将数据采用Bundle的方式通过新打开Activity1传递参数,这样的做法虽然也可以恢复用户输入的数据,但并不符合我们的期待,尤其是用户曾经输入过的数据,如果不小心单击回到上一页,数据就消失不见了。
如果要在第二个页面加上一个“回上页”的按钮,而非通过模拟器的返回键,且回上页后又能保留之前的相关信息,那么就必须用StartActivityForResult方法来唤起另一个Activity。要处理Activity2返回的结果,就要在Activity1中重写OnActivityResult方法,程序如下:
运行结果:
就本范例而言,其实使用StartActivity也可以达成相同的效果,仅需在Activity1被Create时判断Intent内有没有数据,有的话,就将数据带入,没有就带入null。但程序还需要做有无值的比较,较为繁琐,既然MonoDroid API提供了更好用的方法,何乐而不为呢?更何况如果系统不是只有几行,而是几百几千行,那不就头大了?