您的位置:首页 > 移动开发 > Android开发

Kotlin学习记录(三)—— 子线程获取数据,实现简单ListView

2017-06-09 14:54 621 查看
接上篇:Kotlin的变量、属性、类、构造函数、继承、方法上一篇简单介绍了Kotlin的一些基础构成,当然还有像对象声明、操作符等等都未涉及到,这些会在以后用到的过程中进行详细说明。项目中ListView列表出现的频率是很高的,我们就以实现一个简单ListView为目标,介绍一下在子线程中获取数据等问题。首先在layout中新增个listview:
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
在activity中绑定View,之前说了,可以通过 "importkotlinx.android.synthetic.main.activity_main.*" 的方式获取对应layout中的view,可以省略findViewById的代码。那这里我们使用findviewById的方式绑定view:
	val listview:ListView=findViewById(R.id.listview) as ListView
可以看到Java中通过“()”完成类型转换,在这里使用了“as”关键字。创建adapter的布局list_item.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="100dp"android:background="#ffffff"android:id="@+id/ll_item"><TextViewandroid:id="@+id/textView"android:layout_width="match_parent"android:layout_height="50dp"android:layout_weight="1"android:layout_gravity="center"android:gravity="center"android:text="TextView" /></LinearLayout>
新建adapter类ListViewAdapter.kt
class ListViewAdapter ( val datas: List<String>,val context: Context): BaseAdapter(){override fun getCount(): Int {TODO("not implemented") //To change body of created functions use File | Settings | File Templates.}override fun getItem(p0: Int): Any {TODO("not implemented") //To change body of created functions use File | Settings | File Templates.}override fun getItemId(p0: Int): Long {TODO("not implemented") //To change body of created functions use File | Settings | File Templates.}override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {TODO("not implemented") //To change body of created functions use File | Settings | File Templates.}}
可以看到ListViewAdapter类定义了需要传入datas和context两个函数。一个数据和一个上下文。然后我们队这个adapter进行的一定的修改:
class ListViewAdapter ( val datas: List<String>,val context: Context): BaseAdapter(){override fun getCount(): Int=datas.size ?: datas.size ?: 0  //注释一override fun getItem(p0: Int): Any = datas.get(p0)override fun getItemId(p0: Int): Long = 0override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {var viewHodler:ViewHodler?=null //注释二var view:Viewif(convertView==null){view= View.inflate(context,R.layout.list_item,null)viewHodler=ViewHodler(view)view.tag=viewHodler}else{view=convertViewviewHodler=view.tag as ViewHodler}if(getItem(position) is String){//给textview赋值viewHodler.textView.text=getItem(position).toString()//隔行变色,闲着啥事if((position+1)%2!=0)viewHodler.ll_item.setBackgroundColor(context.resources.getColor(R.color.f2f2f2))}return view}class ViewHodler(var view: View){var textView: TextView=view.findViewById(R.id.textView) as TextViewvar ll_item: LinearLayout=view.findViewById(R.id.ll_item) as LinearLayout}}
注释一:getCount()方法大家都知道,是adapter获取item数量的,通过这个数量决定adapter绘制的view个数。这个写法的话,在Kotlin里如果一个方法的返回值可以直接通过计算获得,可以使用等号,不需要括号,这个在前边的文章里有讲过。然后是"datas.size ?: datas.size ?: 0",这句就相当于Java里的"datas.size ? datas.size : 0",这样应该就明白了,?:前边的是判断条件,为true在取datas.size,为false则取0。注释二:这里的?又是干啥的呢,“?”这是kotlin的一个基本概念,之前有提到,kotlin是空安全的,那么在kotlin中,类型系统将可空类型和非空类型进行了区分,例如:String为不可空类型,String?为可空类型,如果将不可空类型赋值null将会编译不通过。
	var str1:String=null //错误	var str2:String="123131"    //正确	var str3:String?=null   //正确
如果此时操作str3,比如获取其长度str3.length也是编译不通过的,操作可空类型时,需要对其进行判断,否则编译不通过:
	var length1:Int=str3.length  //错误	var length2:Int=str3!!.length   //正确
这时候是不是觉得好烦啊,我要知道这个东西是空的,肯定都改了,哈哈,自然不是这样的,我们可以通过下边的方式解决这种可空类型的引用:
	var length3:Int=str3?.length
通过?.调用length,如果str3为空则返回null,否则就返回str3的长度。这样是不是就方便了,也避免了空指针的问题。所以对于可空类型的操作在调用前,需要先检查,因为可能为空,使用?.的形式调用,如果为空在返回null,而使用!!.的形式调用,如果为空则会抛出空指针异常。这就是kotlin的空安全的一种体现。好咯,回到我们的Listview,上边的adapter除了刚才这两个地方,其他的代码相信大家只要是写过adapter的都能看得懂。那么既然是list列表,肯定是要有数据的吧,这里我们就建一个Request的类来模拟服务器端的数据,Request里有个run的方法返回了一个List<String>:
public class Request{public fun run():List<String> {val items= listOf<String>("瓦洛兰","德玛西亚","班德尔城","诺克萨斯","祖安","皮尔特沃夫","艾欧尼亚","李青","阿利斯塔","希维尔","潘森","伊泽瑞尔","雷克顿","古拉加斯","奥利安娜","崔斯塔娜","泰达米尔","马尔扎哈","卡西奥佩娅","艾尼维亚")return items}}
然后我们回到Activity里,给listview绑定adapter:
override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val listview:ListView=findViewById(R.id.listview) as ListView   //绑定listviewval request:Request= Request()  //声明添加数据的对象,var list:List<String>?=request.run()listview.adapter=ListViewAdapter(list!!,this)   //绑定adapter}
listview.adapter就不说了,相当于Java里的:setAdapter,前边的文章里有介绍。那么运行APP,效果图:正常开发的情况下,数据的来源肯定不是这样的,而我们从服务器端获取数据网络请求都是在子线程中进行的,关于Android线程的问题,这里就不做解释了(这是基础常识)。因为kotlin强大的互操作性,之前适用的Java的第三方网络框架都是可以使用的。这里数据和例子都比较简单,就不使用第三方了,只来介绍下kotlin里的线程简单使用。大家比较熟悉的是Java里的AsyncTasks,在kotlin中,Anko库(Anko是JetBrains开发的一个强大的库,包含了很多非常有帮助的函数和属性来避免让你写很多的模板代码)提供了简单的DSL来处理异步任务:
import android.app.Activityimport android.os.Bundleimport kotlinx.android.synthetic.main.activity_main.*import org.jetbrains.anko.asyncimport org.jetbrains.anko.uiThreadclass MainActivity : Activity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)initData()}fun initData(){async() {//可以在此进行网络请求获取数据//我们还使用Request模拟val request:Request= Request()var list:List<String>?=request.run()uiThread {listview.adapter=ListViewAdapter(list!!,this@MainActivity)}}}}
我们通过async函数,在其他线程里执行了网络请求的代码,然后通过uiThread的方式回到主线程给listview绑定了adapter。和Java比有个好处就是如果使用AsyncTasks时,当运行到postExecute的时候Activity被销毁了,那么就会崩溃了,而uiThread不会,如果activity.isFinishing()返回true,uiThread是不会执行的。async基本能够满足我们大部分的需求了。快快尝试一下吧!Kotlin学习记录(四)—— 常用集合的使用

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android Kotlin 线程 Async
相关文章推荐