AIDE手机编程初级教程(零基础向) 3.3.2 优化信息显示 下篇

第三章 优化小游戏

系列教程导航

3.3 优化信息显示

3.3.2 下篇


文章目录




适配器

    在上篇的最后,我提到了适配器这个概念。这里,我来简单讲解一下。

    还记得吗?我们为了实现上下滑动的效果,选择了ListView,它可以用来存放我们的消息框控件(其实也就是一些TextView)。由于ListView这个容器里面存储的数据比较复杂,Java提供了适配器来帮助将各种数据显示在ListView里面。简单来说,适配器起到了一个桥梁的作用,将各种数据和ListView联系在一起。




数组适配器

    讲完了适配器是什么,我们接下来就来实际操作它。这里我们选择比较简单的ArrayAdapter,也就是数组适配器。顾名思义,ArrayAdapter像数组一样,里面可以存放一些数据,再把这些数据显示到ListView里面。

    不过,ArrayAdapter一些局限性。首先,ArrayAdapter里面的每个列表项只能是TextView(也就是说只能显示文本),好在我们暂时也是只需要显示文本。所以我们还是会选择ArrayAdapter

    接下来,我们开始使用ArrayApater。

    首先,我们新建一个Java文件:

在这里插入图片描述

    MsgAdapter这个类就是我们的适配器。为了使这个类具有ArrayAdapter的功能,我们用extends关键字,使它继承ArrayAdapter类。

在这里插入图片描述

    由于ArrayAdapter里面存储的是消息框,所以我们需要消息框的布局文件(这个我们在上文已经写好)。为了找到消息框的布局文件,我们需要知道其id。于是,我们定义一个变量用来存储消息框的布局文件的id。

在这里插入图片描述

    然后写构造函数:

在这里插入图片描述

    这里用到了一个新的关键字:super。那么super是什么呢?为了保持进度,这个知识点我会放到本文的末尾。此处大家只需要简单的理解即可:super函数其实指的是子类对应的父类的构造函数。

    接下来我们就要进入最关键的部分了:写getView函数。ListView可以上下滑动,里面有若干个子项,每个子项都有对应的一个View,而getView函数就是用来获取这些view对象,然后显示在屏幕上的。下图中,msg变量里面存储的自然就是listview的对应位置上的消息对象了,而view变量则是存储着我们需要显示在屏幕上面的view视图,事实上,getView方法的返回值也就是这个view。注意这里我们只是先声明了一下view变量,并没有给它初始化。这是因为我们不知道是否需要创建一个新的view对象。具体的原因大家可以在后文找到答案。

在这里插入图片描述

    下面我来解释一下getView函数的三个参数:

  1. position,顾名思义,就是代表该view对象位于listview的位置(或者说是它告诉我们这个view位于listview的第几项)
  2. flagview,简单来说,它可以缓存滑到屏幕之外的项目,这样在我们下一次滑到这个项目的时候,就不需要重新加载了。正因如此,我们在加载view的时候,首先应该判断一下flagview是不是null,如果不是null的话就不需要重新加载view了
  3. parent,其实就是我们的listview啦

    判断flagview是否为null

在这里插入图片描述

    为了更好的讲解接下来的内容,我们简单复习一下实现聊天消息显示效果的基本思路

在定义消息布局的时候,将左右的消息框都定义出来,然后在发送消息的时候进行判断,如果是我们自己发的消息,就把左边的消息框隐藏;反之,如果是程序发送的消息,就把右边的消息框隐藏

    事实上,listview的每一项里面都有很多控件。如果按照一般思路,我们会依次创建这些对象,然后把这些对象“装”到列表项里面。但是,仔细一想,这样会有很多坏处。创建大量的控件对象会在一定程度上影响程序的运行速度,还会占用大量内存。

    究其原因,就在于我们创建了很多变量,用来存储控件对象,而这些变量只是加载当前的view的时候有用,之后就没有用了。所以说我们可以引入一个“容器”来帮忙存储这些变量,这样就不用每次都创建新的变量来存储控件对象,只需要把这些变量的值变化即可。一般来讲,我们会使用一个类来存储这些变量,这个类就是ViewHolder

    ViewHolder类和我们平常见到的类其实差不多,只不过,它里面一般只有属性,没有方法。所以说,它只是充当一个容器而已。这里我把它直接写在了MsgAdapter.java文件中,代码如下:

在这里插入图片描述

    然后,我们回到MsgAdapter类的getView函数里面,声明一个ViewHolder变量。注意,这里只需要声明即可,不需要创建ViewHolder对象,因为有可能我们需要加载的view对象正好和前一个一样。所以我们应该先判断一下flagView,也就是先前加载的那个view对象,是不是null。如果是null,那就新建一个viewHolder对象,然后赋给viewHolder变量;如果不是null,那就把flagView的viewHolder对象直接赋给viewHolder变量。代码如下:

在这里插入图片描述

    在获取view的viewHolder对象时,我们使用到了getTag函数。这个函数可以获取到对应view对象所绑定的viewHolder对象。不过,这个函数的返回值类型并不是viewHolder,所以我们需要进行强制类型转换。(我们可以大胆猜一猜,既然获取viewHolder对象是用getTag函数,那么绑定viewHolder对象应该就是用setTag之类的函数了)

    接下来,我们思考flagview为null的情况。(事实上,flagview不为null的情况我们已经思考完了。因为那里的view对象和viewHolder对象都已经创建完成)当flagview为空时,我们需要得到view对象和viewHolder对象。首先获取view 对象。之前我们获取一个控件对象的话一般用的都是findViewById方法,不过,这里我们不能用这个方法。因为它的使用前提是,控件所在的界面已经被加载出来了。这里,很明显,getView方法需要返回的控件对象原本不在界面里面,换句话说,getView方法返回的对象是被动态地添加到了界面里面。

    不过,办法总比困难多。获取控件对象 的方法除了findViewById,还有另外一个:使用LayoutInflater类的inflate函数。

    大概的原理就讲到这里,如果有同学雪妖了解的更深一点的话,可以自行查阅有关资料。下面我给出有关的代码:

在这里插入图片描述

    接下来,我们把消息框里面的各种控件全都对应着放到容器——ViewHolder类里面去。注意这里我们可以使用findViewById方法,这是因为这些控件已经随着view对象加载到了界面里面。

在这里插入图片描述

    然后,将viewHolder与这个view对象绑定,使用setTag方法(跟之前猜测的一样,哈哈)

在这里插入图片描述

    到这里,我们完成了view对象的创建工作。不过,现在的view对象并不是最终返回的view对象。简单来讲,我们还需要完成以下任务:

  • 根据msg对象的name属性,判断该消息是由谁发出
  • 如果消息由我们发出,则把左边的线性布局设置为“不可见”,右边的线性布局设为“可见”;反之,如果消息由电脑发出,则把右边的线性布局设置为“不可见”,左边的线性布局设为“可见”
  • 向可见的线性布局里面的控件填充有关信息。比如需要发送的文本等等

    一个一个来解决。首先是msg对象,这个我们在才开始写getView方法的时候就已经搞定了。接下来,如何得到msg的name属性呢?仔细一想,我们之前在Msg里面写过一个方法,叫做getName,就是用来获取msg对象的name属性的。最后,方便起见,我把“我”的名字设为“玩家”。于是,第一点完成。

在这里插入图片描述

    第二点,设置某个线性布局不可见的方法,自然是它自己最清楚了。这里要注意,这个线性布局是被存在viewHolder里面的,所以说我们需要从viewHolder里面取到左边或者右边的线性布局对象。取到线性布局对象之后,使用setVisibility方法,就可以设置该对象是可见还是不可见了。具体代码如下:

在这里插入图片描述

    第三点,我们这里需要填充的信息有两个:名字和消息内容。这两个信息都可以通过msg对象的对应方法来获得。为此,我们只需要分别获取到两个文本框对象,使用setText方法即可。具体代码如下:

在这里插入图片描述

    MsgAdapter类至此编写完成!回头看看自己写的代码,会不会很有成就感呢!




完成

    做完了之前的步骤,本节的任务也终于接近尾声了。下面的内容,全部在MainActivity类中完成。在开始写代码之前,我依然先来分析一下接下来的思路:

  1. 获取到listview控件对象
  2. 我们知道,每一条消息都会被封装为Msg对象,于是我们自然需要一个容器来存储这些Msg对象。用一个数组可以吗?当然不行。因为我们事先并不知道Msg对象的个数,自然也就无法知道这个数组的长度了。不过,如果你想的话,当然也可以把这个数组的长度设置为几千或者几万,不过这样很浪费内存。于是我们需要一个新的容器来存储这些对象。
  3. 创建msgAdapter对象,并把msgAdapter绑定在listview上
  4. 按下“发送”按钮之后,首先应该判断编辑框里面是否为空字符串。然后,根据我们的消息和名字来创建一个Msg对象。接下来,把电脑的消息和名字也封装到一个Msg对象里面。最后把这两个Msg对象添加到存储Msg对象的容器里面
  5. 事情到这里还没完。因为系统其实并不知道消息列表已经改变,所以我们需要“提醒”它对msglist进行刷新。为了更好的阅读体验,我们还需要在发送一条消息之后,把列表自动拉到最底部

    接下来,我们依次完成上面的思路:

    第1点,我们依然是先在onCreate函数的外面声明变量,然后到onCreate函数里面给变量赋值。由于变量show已经没有用了,所以我们把相关的这两句代码删掉

在这里插入图片描述

在这里插入图片描述

    第2点,这个新的容器,叫做集合,它可以存储各种类型的对象,而且,它的长度可以动态的改变。由于集合是很复杂的一个知识点,所以此处我们简单的了解即可,不需要深究。

    声明集合变量

在这里插入图片描述

    大家可能会感到疑惑,那个‹Msg›是什么意思呢?这个东西,叫做泛型。简单来讲,就是一个标识。这里的‹Msg›就标志着msgList这个集合里面存储的是Msg类型的对象。

    接下来,我们在onCreate函数里面创建集合对象,并赋给msgList。

在这里插入图片描述

    和一般的对象一样,我们使用new关键字即可创建这个集合的对象。

    第3点,我们依然是在onCreate函数的外面声明适配器变量(声明变量已经在第1点里面完成),然后回到onCreate函数里面创建适配器对象,赋给适配器变量

在这里插入图片描述

    然后,我们使用listview对象的setAdapter函数,将这个适配器对象与listview绑定。

在这里插入图片描述

    第4点,我们首先看一下按钮绑定的监听器对象。

在这里插入图片描述

    这里,因为我们之前添加消息都是在show这个TextView中进行的,所以我们需要把之前写的有关show的语句都进行一定的改动。简单分析可知,其中涉及show变量的语句有两种:show.setText("...")和show.append("..."),前者是把之前的消息全部删除,然后写下新的消息,后者则是保留原来的消息,并在原来的消息后面追加一条消息。于是我们只需要分别完成这两种功能即可。

    对于show的setText方法的改动:我们首先是调用集合msgList对象的clear函数,清空其中的所有消息;然后再向其中加入一条电脑发送的消息(Msg对象)

在这里插入图片描述

    对于show的append方法的改动:直接使用msgList对象的add方法,将对应的Msg对象存到集合里面即可。注意要删除字符串里面,我们之前写的\n。最后的样子如下图所示

在这里插入图片描述

    下面的需要修改的语句按照相似的方法进行处理即可。下图是完成之后的代码

在这里插入图片描述

    第5点,“提醒”系统刷新界面和自动把页面滑到底部。它们分别对应着两个函数:适配器的notifyDataSetChanged函数和列表视图的setSelection函数。这里同样不需要深究,直接使用即可。见下图:

在这里插入图片描述

    到这里,程序的编写终于可以告一段落了!!




测试

    我们运行一下这个新的软件。下面是我自己手机上面的运行结果:

在这里插入图片描述

    结果发现消息倒是有了,但是每一条消息都没有名字!大家可以先想一想可能有哪些原因。

    根据我细致的查找,我最后找到了原因:原来我们在写message.xml文件的时候,把显示名字的文本框中的文字颜色设置成了白色!于是我们回去修改一下颜色:

    修改的地方有两处,图中把其中一个划上了黑线,另外一处请大家自行找到,并把#FFFFFF改为#000000

![在这里插入图片描述](https://img-blog.csdnimg.cn/a223c33b1cb147158c2d62d5c8c23847.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAT3dlbl9UZWQ=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

    重试一次:

在这里插入图片描述

    成功!至此,本文所要讲述的主要内容已经结束。




super关键字

    为了更好的理解super关键字,我们需要举一个例子。这里我新建了一个Java程序,并写下了一个父类和一个子类,其中父类的空参数构造函数里面写了一个打印语句,子类的构造函数里面也写了另外的一个打印语句。接着我们在主函数里面通过new关键字,创建一个子类对象。

在这里插入图片描述

    上面的程序运行结果如下:

在这里插入图片描述

    由此可见,在调用子类的构造函数的时候,父类的空参数构造函数也跟着被调用了!

    这是为什么呢?因为在子类构造函数的第一行,其实有一个默认的隐式语句super();,我们可以尝试着&自己把它加上:

在这里插入图片描述

    运行结果同上:

在这里插入图片描述

    现在我们把父类的构造函数进行修改,添加一个参数:

在这里插入图片描述

    然后我们就会发现子类构造函数里面的super();语句出现了错误。这是因为我们在父类中写了一个含有参数的构造函数,原来的空参数构造函数就没有了。于是,我们也应该按照对应的样子,在super语句中传入对应的参数:

在这里插入图片描述

    运行结果如下:

在这里插入图片描述

    由此,我们发现:在子类的实例化过程中,其构造函数会通过super关键字,访问父类的构造函数。为什么会有这种设定呢?这是因为子类继承了父类的属性,所以在使用父类内容之前,要先看一下父类是怎么初始化自己的内容的。这个内容是必须完成的,于是子类的构造函数中会加入一个默认的隐式的super()语句。如果说父类中没有定义空参数的构造函数,那么子类的构造函数里面就必须用super明确需要调用父类中的哪一个构造函数。




后记

    本文,我带领大家完整的体验了一次开发一个简单的消息发送功能的过程。回顾一下这整个过程:我们首先是确定了要使用新的容器,listview;然后编写了消息类Msg,适配器类MsgAdapter;最后在MainActivity文件里面,把前面写的东西组装起来。简单来讲,我们这种是从“部分到整体”,也就是说我们首先完成各个部分,最后组装起来。而有的时候,问题很复杂,我们不知道各个步骤的时候,就要学会“从整体到部分”,也就是说我们首先大致完成整体,看需要哪些部分,然后再去写。当然,我真正开发的时候,很多时候都是两个过程同时进行。

    最后,我在这里祝大家新年快乐!

感谢你的阅读!本教程会长期不定时更新。本人不是大神,也会犯错,如果有建议或者提问的话,欢迎评论留言!

作者头像

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
了解AIDE(3课) 本来以前做PyS60教程是没有介绍开发工具这一节的,由于AIDE专业名词很多,且无可用汉化版(其实汉化版在论坛上是有的,但汉化组们汉化的AIDE由于破坏了软件原有的签名,虽然安装之后可以打开,但写的程序无法run运行,这个大家可以去试试。。) 这里,我开始向大家介绍AIDE的使用和功能,有些截图是截的汉化版的,方便大家对照。 进入主界面如下图: 有的手机第一次打开AIDE时会提示新建一个android项目,可以点不。如上图,点击电脑图标后,会弹出出AIDE的工作区,如下图: 默认工作区弹出的内容是AIDE的项目文件管理器,值得一提是AIDE的项目文件管理器的默认文件目录是在sd卡下的AppProjects目录下的,新建安卓项目最好新建在这个目录下。 工作区里的内容或者说功能可以通过手机菜单键>More(更多)进行切换,More(更多)的内容如下图: 为了防止AIDE以后有更多功能,图片不好对照。下面我给出常用的英文翻译对照: 1、主菜单 Files-->文件夹 GoTo-->跳转 Forward-->前进 Save-->保存 Run-->运行 More-->更多 . 2、More(更多) Go Premium!-->无用的,不管 Show Errors -->显示错误 Show Search Results-->显示搜索结果 Show LogCat-->显示LogCat Show File Location-->显示文件位置 Show Open Files-->显示打开的文件夹 Search in Files-->在文件中搜索 GoTo Class-->跳转到类 GoTo Line-->跳转到行 Export APK-->导出APK Refresh Build-->刷新工程 Refresh Code Analysis-->刷新代码分析 Close Project-->关闭工程 Community-->社区(跳转网页)SDK Help-->社区(跳转到android官方开发帮助) Settings-->设置 Exit-->退出 . 我希望大家在编写第一程序之前先好好的了解一下的我们的开发工具AIDE,还好很多没翻译到的地方可以自己摸索一下,好了,这一节就到这里。
开发手册目录 │ Addison Wesley - JDBC API Tutorial and Reference 3rd Edition (2003).chm │ ajax教程.chm │ AngularJS 中文API参考手册.chm │ Bootstrap-中文-API.chm │ css2.chm │ CSS4.0中文参考手册.chm │ cssv3.4.0.chm │ DHTML_DOC_CN.chm │ DHTML手册.chm │ dom4j.chm │ DOM_help.chm │ DOM中文参考手册CHM·chm.chm │ DOM文档对象模型手册.chm │ DTD.chm │ EasyUI-API+1.3.2.chm │ Ext2.2API中文版.CHM │ Ext3.2中文API.CHM │ Hibernate3.2.chm │ Hibernate3.2API.chm │ html5参考手册.chm │ HTML入门与提高.CHM │ Html标签一览表.chm │ html语法教程.chm │ HTTP1.1.chm │ J2EE_1.5_API.CHM │ J2EE_1.6_API.chm │ Java+EE+6+API+Specifications.CHM │ JavaEE_API_5[1].0.chm │ JavaScript Professional Projects.chm │ JavaScript20.chm │ JavaScript中文手册.CHM │ JavaScript手册.chm │ JavaScript语言中文参考手册.chm │ java_ee_api_中英文对照版.chm │ java_ee_api_中英文对照版.chw │ jBPM 4.4 API.chm │ jdk 1.7_api_doc.CHM │ JDK_API_1_6_zh_CN.CHM │ JDK_API_1_6_zh_CN.chw │ jquery1.7 中文手册.chm │ JQuery_1.4_API.CHM │ jQuery文档.chm │ JSP API.chm │ Jsp帮助文档.chm │ JSP语法.chm │ Linux基础命令教程豪华版.chm │ Linux常用命令大全.chm │ lucene_3.6.1_API.CHM │ MySQL_5.1_zh.chm │ POI_3.8_API.CHM │ Servlet API[China].chm │ Servlet-API.chm │ servlet.chm │ Spring-Reference_zh_CN.chm │ spring2.5.5_API.chm │ Spring3.0.2-RELEASE-API.chm │ Struts2.chm │ struts2中文教程.chm │ struts2标签.chm │ tomcat5.5中文帮助文档.chm │ W3CSchool .chm │ W3CSchool.chm │ w3school完整版.CHM │ WebGL自修教程.chm │ XML+Schema官方教程(9loong中文版)修正版2009.04.chm │ XmlSchema标准参考手册.chm │ XPathTutorial.chm │ 样式表中文手册.chm │ 网页制作完全手册.chm │ 英语资料大全.chm └─hadoop api

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值