Kotlin+Jetpack Compose+Volley+ViewModel Android开发
2022-8-22 16:40:39 星期一
刚开始接触 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 代码举例
1 @Composable 2 fun Greeting(name: String) { 3 4 Column( 5 modifier = Modifier 6 .fillMaxHeight() 7 .fillMaxWidth() 8 .background(Color.LightGray) 9 .padding(5.dp) 10 , verticalArrangement = Arrangement.Top 11 , horizontalAlignment = Alignment.CenterHorizontally 12 ) { 13 Text(text = "Hello $name! 111", Modifier.padding(5.dp).background(Color.White).border(1.dp, Color.Green, RoundedCornerShape(4.dp))) 14 Text(text = name, Modifier.padding(5.dp), fontSize = 18.sp, maxLines = 2, overflow = TextOverflow.Ellipsis, fontWeight = FontWeight.Bold) 15 Divider(color = Color.Black) 16 17 Button(onClick = {}) { 18 Text(text = "点击") 19 } 20 } 21 }
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 代码举例:
1 public class NewsListModel : ViewModel() { 2 3 public var data = mutableStateListOf<News>(); //UI中的数据来源 4 5 public fun setData(ctx: Context) { 6 val url = "https://xxx.com/json_data"; 7 val queue = Volley.newRequestQueue(ctx); 8 val stringRequest = StringRequest( 9 url, 10 Response.Listener<String>{ response -> 11 val obj = JSONObject(response) 12 //Log.i("111-msg", obj.getString("msg")) 13 //Log.i("111-msg", obj.getString("code")) 14 val arr = obj.getJSONArray("data"); 15 for (i in 0 until arr.length()) { 16 val item = arr.getJSONObject(i); 17 data.add(News(item.getString("title"), item.getString("desc"))); //News类的定义在下边 18 } 19 }, 20 Response.ErrorListener { Log.i("1111", "error") } 21 ) 22 queue.add(stringRequest); //通过volley获得服务端数据 23 } 24 25 } 26 27 data class News(val title:String, val desc:String); //就这样写, 不用写花括号
2.3.4 在在MainActivity中使用ViewModel单例, 这样写:
1 class MainActivity : xxxx () { 2 override fun onCreate(xxx) { 3 ..... 4 val vm:MyxxxModel = viewModel(); //单例写法 5 vm.setData(this) //这个方法用Volley去请求服务端数据, 然后给vm.data赋值 6 ..... 7 } 8 }
2.4 UI控件中使用ViewModel
1 @Composable 2 fun NewsList(vm:NewsListModel = viewModel()) { 3 Column() { 4 vm.data.forEach { 5 Row() { 6 Text(text = "${it.title} : ${it.desc}") 7 } 8 } 9 } 10 }
2.4.1 此方法会在MainActivity中setContent()直接或间接调用, 调用时, 不用传入viewModel参数, 系统会自动实例化vm
2.4.2 调用了被@Composable注解的方法也必须有@Composable注解
2.4.3 其中的it, 是forEach这个lamda方法的默认参数, 代指循环中的每一个item