Kotlin+Jetpack Compose+Volley+ViewModel Android开发

刚开始接触 kotlin + Jetpack Compose 开发 Android应用, 这里记录下自己的理解

建议看官方中文文档: 

https://developers.google.cn/codelabs/jetpack-compose-basics#0

https://developer.android.google.cn/codelabs/jetpack-compose-state#0

1. 概念

1.1 Jetpack Compose 是Android中一个取代xml的UI框架, 与Kotlin语法配合使用, Compose隶属于Jetpack

1.2 Volley 是一个轻量级的Http请求库, 谷歌官方的, 使用起来比较简单(听说适合纯数据请求, 不太适合图片请求)

1.3 ViewModel 保存数据用, 用来把volley从服务端请求的数据, 传递给compose在页面中显示出来

1.4 ViewModel + Compose的最佳实践是, 将数据的获取逻辑和UI的渲染分开在两个文件中编写, 数据有变化, UI自动变化

1.5 Json解析使用了官方的 json.org 库, 没有使用gson

2. 代码细节

2.1 Compose:

2.1.1 用Android Studio 创建应用的时候, 要选择 "Compose Activity", 这样才能使用Compose相关特性

2.1.2 Compose 中列表UI是 Column(){} 其中小括号中声明这个列表的样式, 花括号中写子控件(其他UI控件也是这个规律), 比如列表中有文本控件(Text(){}) 或 按钮控件(Button(){}) 或 行控件(Row(){})

2.1.3 可以将不同的控件写在一个函数中, 在MainActivity::onCreate()中被调用, 这个函数前边必须用 @Composable 注解

2.1.4 代码举例

@Composable
fun Greeting(name: String) {

    Column(
        modifier = Modifier
            .fillMaxHeight()
            .fillMaxWidth()
            .background(Color.LightGray)
            .padding(5.dp)
        , verticalArrangement = Arrangement.Top
        , horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Hello $name! 111", Modifier.padding(5.dp).background(Color.White).border(1.dp, Color.Green, RoundedCornerShape(4.dp)))
        Text(text = name, Modifier.padding(5.dp), fontSize = 18.sp, maxLines = 2, overflow = TextOverflow.Ellipsis, fontWeight = FontWeight.Bold)
        Divider(color = Color.Black)

        Button(onClick = {}) {
            Text(text = "点击")
        }
    }
}

2.2 Volley

2.2.1 他获取数据的时候, 必须传入上下文, 所以要在 MainActivity中调用并把 this传给他 (不知道还有没有其他调用方式)

2.2.2 用他获取数据, 以及处理数据的代码最好是写在ViewModel类中

2.3 ViewModel

2.3.1 需要新建一个MyxxxModel 继承自 ViewModel; 注意Kotlin继承的两种写法

1. calss MyModel : ViewModel {}

2. class MyModel : ViewModel() {} 

(一个有小括号, 一个没有. 若没有小括号, 就得手工调用父类的构造方法) 

2.3.2 用来存储服务端数据的成员变量(假如叫: data)要定义为 MutableStat 或 MutableStatList 前一个不是列表, 后一个可以放列表数据, 这样当这个数据改变的时候, UI才会跟着改变

2.3.3 代码举例: 

public class NewsListModel : ViewModel() {

    public var data = mutableStateListOf<News>(); //UI中的数据来源

    //获取远程数据,给 data 赋值
    public fun setData(ctx: Context) {
        val url = "https://xxx.com/json_data";
        val queue = Volley.newRequestQueue(ctx);
        val stringRequest = StringRequest(
            url,
            Response.Listener<String>{ response ->
                val obj = JSONObject(response)
                //Log.i("111-msg", obj.getString("msg"))
                //Log.i("111-msg", obj.getString("code"))
                val arr = obj.getJSONArray("data");
                for (i in 0 until arr.length()) {
                    val item = arr.getJSONObject(i);
                    data.add(News(item.getString("title"), item.getString("desc"))); //News类的定义在下边
                }
            },
            Response.ErrorListener { Log.i("1111", "error") }
        )
        queue.add(stringRequest); //通过volley获得服务端数据
    }

}

data class News(val title:String, val desc:String); //就这样写, 不用写花括号

2.3.4 在MainActivity中初始化ViewModel获取数据, 这样写: 

class MainActivity : xxxx () {
    override fun onCreate(xxx) {
        .....
        val vm:NewsListModel = viewModel(); //单例写法
        vm.setData(this) //这个方法用Volley去请求服务端数据, 然后给vm.data赋值
        .....
    }
}

2.4 最后, 在UI控件中与ViewModel绑定

@Composable
fun NewsList(vm:NewsListModel = viewModel()) {
    Column() {
        vm.data.forEach {
            Row() {
                Text(text = "${it.title} : ${it.desc}")
            }
        }
    }
}

2.4.1 此方法会在MainActivity中setContent()直接或间接调用, 调用时, 不用传入viewModel参数, 系统会自动实例化vm

2.4.2 调用了被@Composable注解的方法也必须有@Composable注解

2.4.3 其中的it, 是forEach这个lamda方法的默认参数, 代指循环中的每一个item


版权声明:本文为zhangzhibinshuai原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。