欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 实现一个简单的拉取网络todo app

实现一个简单的拉取网络todo app

2025/2/22 21:13:34 来源:https://blog.csdn.net/m0_69086552/article/details/145782481  浏览:    关键词:实现一个简单的拉取网络todo app

思考怎么去做一个网络api的调取, 然后展示到android前端

需求分析

  1. 考虑几个页面,页面展示什么内容
  2. 我需不需要更改后端内容, 如果只是单纯的获取数据,那就只需考虑GET data
  3. 如果我需要更改后端数据库的内容, 那么什么参数和什么事件将会导致我这样做
  4. 考虑怎么配置网络请求, 网络请求返回的数据要不要存入到数据库
  5. 如果要存入到数据库,那么数据项目的配置是怎么样的
  6. 没有网络的情况下还能不能直接去拿到已经存在数据库的内容
  7. 考虑适配的android平台, 这里以android 13 api 33 为例

实现一个从网络请求获取todo数据,展示在app上面

先任务简单化(注意使用到viewbinding,可能部分代码需要配合xml文件名具体分析)

// 依赖
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'implementation 'com.drakeet.multitype:multitype:4.3.0'
def activity_version = "1.9.2"
// Kotlin
implementation "androidx.activity:activity-ktx:$activity_version"def room_version = "2.4.2"
//room
implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-runtime:$room_version"
//    kapt "androidx.room:room-compiler:$room_version"
ksp "androidx.room:room-compiler:$room_version"// 奔溃阻止
implementation 'com.github.alhazmy13:Catcho:v1.1.0'// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1"implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
implementation 'com.google.code.gson:gson:2.8.9'// ksp插件配置, app模块
plugins {alias(libs.plugins.android.application)alias(libs.plugins.kotlin.android)//    id 'kotlin-kapt'id 'com.google.devtools.ksp'
}// 项目根
plugins {alias(libs.plugins.android.application) apply falsealias(libs.plugins.kotlin.android) apply false// https://mvnrepository.com/artifact/com.google.devtools.ksp/symbol-processing//runtimeOnly 'com.google.devtools.ksp:symbol-processing:1.9.24-1.0.20'id 'com.google.devtools.ksp' version '1.9.24-1.0.20' apply false
}

1.配置BASE_URL

  • private const val BASE_URL = “https://7ce074a2.r7.cpolar.top”

2. 配置好mongodb connect string后, 启动后端

  • go run main.go

3. 找到需要的接口

  • GET api/todos 是我需要的
  • 接口返回示例
HTTP/1.1 200 OK
Date: Fri, 21 Feb 2025 07: 58: 10 GMT
Content-Type: application/json
Content-Length: 418
Vary: Origin
Connection: close[
{
"_id": "67b8244a6d9be942d1ba3a8a",
"completed": true,
"body": "hello world"
},
{
"_id": "67b825616d9be942d1ba3a8b",
"completed": true,
"body": "Damn"
},
{
"_id": "67b828926d9be942d1ba3a8c",
"completed": true,
"body": "哈哈"
},
{
"_id": "67b829796d9be942d1ba3a8d",
"completed": true,
"body": "AAA"
},
{
"_id": "67b829896d9be942d1ba3a8e",
"completed": true,
"body": "你好呀"
},
{
"_id": "67b82da36d9be942d1ba3a8f",
"completed": true,
"body": "及你太美"
}
]

4. 编写接口

interface TodoApi {@GET("api/todos")suspend fun getAllTodos(): Response<List<Todo>>
}

5. 编写retrofit客户端

object ApiService {// todo: 如果是retrofit 的话,这个连接不生效就马上闪退// 后端链接:  https://gitee.com/EEPPEE_admin/probe-examples/tree/master/fiber-and-react-example/backend// 配合内网穿透工具cpolar使用// cmd: cpolar 6969private const val BASE_URL = "https://7ce074a2.r7.cpolar.top"val todoApi: TodoApi by lazy {Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build().create(TodoApi::class.java)}
}

6. 数据库内容项保存

// 本机要存的信息
@Entity(tableName = "todos",
)
data class Todo(@PrimaryKey(autoGenerate = true)val id: Int = 0,
//    @PrimaryKey(autoGenerate/ = false)val _id: String = "",val completed: Boolean,val body: String,
)

7.dao查询接口

@Dao
interface TodoDao {@Query("SELECT * FROM todos")suspend fun getAllTodos(): List<Todo>
}

8. 数据库需要

@Database(entities = [Todo::class],version = 1,exportSchema = false
)
abstract class TodoDB : RoomDatabase() {abstract fun todoDao(): TodoDaocompanion object {@Volatileprivate var instance: TodoDB? = nullfun getDatabase(context: Context): TodoDB {return instance ?: Room.databaseBuilder(context.applicationContext,TodoDB::class.java,"todo_database").build()instance = instanceinstance}}
}

9. viewmodel层怎么搞,我也不会

class TodoViewModel(// 1. 需要注入网络apiprivate val api: TodoApi,// 2. 需要注入本机数据库private val db: TodoDB
) : ViewModel() {fun getAllTodos() {viewModelScope.launch {val response = api.getAllTodos()Log.d("GET返回", response.body().toString())if (response.isSuccessful && response.body() != null) {// 拿到api的返回,然后存入数据库Log.d("GET响应", response.body().toString())response.body()!!.forEach { it ->// 实际交付到dao做实际插入db.todoDao().insertTodo(it)}}}}
}// 还需要一个工厂?

10. 造一个activity和xml文件

  • TodoActivity.kt
  • activity_todo.xml: 需要刷新layout,和recyclerview
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/swiperefreshlayout"android:layout_width="match_parent" android:layout_height="match_parent"android:orientation="vertical"><androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView"android:layout_width="match_parent" android:layout_height="match_parent" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
  • item_todo.xml: recyclerview里面的数据项
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent" android:layout_height="wrap_content"android:orientation="vertical" android:padding="16dp"><TextView android:id="@+id/tvTitle" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="Todo Title" android:textSize="18sp" /><TextView android:id="@+id/tvCompleted" android:layout_width="wrap_content"android:layout_height="wrap_content" android:text="Completed" android:textSize="14sp" />
</LinearLayout>

11. 为recyclerview编写一个adapter,这里使用MultiType库

class TodoItemViewBinder : ItemViewBinder<Todo, TodoItemViewBinder.ViewHolder>() {// 内部类inner class ViewHolder(private val binding: ItemTodoBinding // 绑定到item_todo.xml) : RecyclerView.ViewHolder(binding.root) {fun bind(todo: Todo) {// 绑定效果binding.tvTitle.text = todo.bodybinding.tvCompleted.text = if (todo.completed) "已完成" else "暂时没搞定"}}override fun onBindViewHolder(holder: ViewHolder, item: Todo) {holder.bind(item)}override fun onCreateViewHolder(inflater: LayoutInflater, parent: ViewGroup): ViewHolder {val binding = ItemTodoBinding.inflate(inflater, parent, false)return ViewHolder(binding)}
}

12. 来实操TodoActivity.kt, 始终应该继承app compat activity,主要看onCreate内容就行

class TodoActivity : AppCompatActivity() {// 需要一个MultiTypeAdapter 对象private var multitypeAdapter = MultiTypeAdapter()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 这里使用到viewbinding内容, 绑定到activity_todo.xmlbinding = ActivityTodoBinding.inflate(layoutInflater)// 配置奔溃阻止,使用到BuildConfig,需要配置build.gradleif (!com.example.myapplication.BuildConfig.IS_DEBUG) {setUpCatcho(this)}setContentView(binding.root)// 默认就加载网络数据loadTodos()// 实现下拉刷新,加载网络数据binding.swiperefreshlayout.setOnRefreshListener {loadTodos()
//            binding.swiperefreshlayout.isRefreshing = false}binding.recyclerView.layoutManager = LinearLayoutManager(this)binding.recyclerView.adapter = multitypeAdapter// 注册 Todo 类型及其 ItemViewBindermultitypeAdapter.register(Todo::class.java, TodoItemViewBinder())}
}

13.抽离出loadTodos,设置一个私有函数(没调试成功)

  private fun loadTodos() {MainScope().launch {try {if (NetworkCheckConnUtil.isNetworkAvailable(this@TodoActivity)) {// 网络可用val response = ApiService.todoApi.getAllTodos()if (response.isSuccessful && response.body() != null) {val todos = response.body()!!// 插入到数据库todos.forEach { it ->todoDB?.todoDao()?.insertTodo(it)}multitypeAdapter.items = todosmultitypeAdapter.notifyDataSetChanged()binding.recyclerView.adapter = multitypeAdapter}} else {Toast.makeText(this@TodoActivity, "网络不可用", Toast.LENGTH_SHORT).show()loadTodosFromDatabase()}} catch (e: Exception) {e.printStackTrace()Toast.makeText(this@TodoActivity, "网络不可用", Toast.LENGTH_SHORT).show()loadTodosFromDatabase()} finally {binding.swiperefreshlayout.isRefreshing = false}}
}

遇到的问题(以上内容有修改了,看源码为主)

1. retrofit无网络,或者base url配置错时, 程序会闪退,这个东西要额外在viewmodel层处理

  • ok,解决bug的逻辑是这样,一开始就加载本地数据库内容(然后土司网络不可用),知道下滑刷新才加载网络内容,how
    about that
  • 程序一开始就没网的时候就闪退,我解决不了

总结

  • 实现刷新加载网络数据成功
  • 但是没有实现从数据库中获取内容,调试不通,无网络时,会报错误
java.net.UnknownHostException: Unable to resolve host "7ce074a2.r7.cpolar.top": No address associated with hostname
at 
  • 写shitcode啊,写安卓没有思路

效果截图

在这里插入图片描述

ref link:

  • https://gitee.com/EEPPEE_admin/android-mono-repo/tree/aaa/app/src/main/java/com/example/myapplication/todoapp
  • 后端: https://gitee.com/EEPPEE_admin/probe-examples/tree/master/fiber-and-react-example/backend

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词