Android开发——Food美食项目实战

本节内容

1.JavaThread下载数据回调

2.引入协程

3.launch和async

4.coroutineScope和CoroutineContext

5.WithContext切换线苟在神诡世界

6.啰嗦OkHttp

7.okhtttp获取数据

8.聚合数据头条新闻API说明

9.使用OkHttp3获取数据

10.手动创建数据模型

11.使用插件自动创工龄差一年工资差多少建模型

12.使用retrofit获取数据

一、JavaThread下载数据回调
1.Thread会阻塞当前的线程 main-UI Thread,耗时比较短的小任务会放到主线程去做宫颈癌
2.有时候主线程上会线程的概念有一些耗时很长的任务,它会阻塞主线程的其他任务。为了解决这个问题,可线程安全以开启一个新的线程,把它称为子线程。
3.UI线程是提供给用户进行交互的,线程安全尽量不要让它被阻塞。
4.以下面的代码为例,在实现按钮的点击事件时,我们打印完start,等待一会再打印end
 button.setOnClickListener {
                Log.v("swl","start  ${Thread.currentThread()}")
                Thread.sleep(2000)
                Log.v("swl","end  ${Thread.currentThread()}")
            }
  • 这样的话,第一次点击按钮之后,只有等这个事件线程过了,线程数越多越好吗才能第二次点击按钮。

Android开发——Food美食项目实战

直接阻塞主线程

5.为了不让它阻塞主线程,我们可以创建一个新的线程,这样每次点击按钮的时候,就不用等待也能直接开始运行了工商银行
button.setOnClickListener {
Thread(object :Runnable{
            override fun run() {
            Log.v("swl","start  ${Thread.currentThread()}")
            Thread.sleep(2000)
            Log.v("swl","end  ${Thread.currentThread()}")
            }
        }
        ).start()
}
  • 这种由于参数继承自一个接口,而该接口里面又只携程网站官网有一种方法,所以可以使用lambda表达式。
button.setOnClickListener {
            Thread{
                Log.v("swl","start  ${Thread.currentThread()}")
                Thread.sleep(2000)
                Log.v("swl","end  ${Thread.currentThread()}")
            }.start()
        }

Android开发——Food美食项目实战

每次点击按钮后都开启一个新的线程

  • Thread.sleep(2000)的意思是阻塞线程池原理当前线程,如果把它直接写在Mai携程网上订票飞机nActivity里面的话,那么它就会阻塞主线程,只有等待一段时间end打印完了之后,才能继续点击按钮。
  • 但是如果我们每线程和进程的区别是什么次点击都创建线程阻塞一个新的线程的话,第一次点击之后先打印start,因为它被阻塞了2s,所以不会立刻打印end。如果我立刻又点了一下按钮的话,这个时候就又会创建一个新的线程,又打印了一个start。因为我在2S内点了四次按钮,所以打印了四个start,2S之后才打印end。
6.Java开启线线程池创建的四种程的弊端:
  • Java里面有线程池,每个线程池里面都只能放规定数量的线程。如果超过了这个数量,那么超过的那个就要进入等待序列,直到线程池中有线程执行完了,它才能进入线程池执行。
  • 线程是很消耗内存的,所以不能大量地开辟线携程旅行app官方下载程。当线程达到一定程度的时候,就会出现警告。
  • 线程之间的线程池的五种状态数据交互:①通过Handler来传递数据(回调) ②进行线程之间的切换(Rxjava)。
7.回调数据的方法
  • 定义一套接口,实现两个线程之间的数据回调。在需要传递数据的类里面定义一个接口(接口里面定义两苟在神诡世界个方法),在这个类里面还需要定义一个接口类型的listener。类里面还有一线程池的七个参数个方法,在里面需要判断有没有listener,如果有的话就进携程旅游网行相应的google操作。①在接收数供品夫人据的类里面,先继承一下前面那个类的接口,然后实现里面的方法,并把该类作为它的listener。②这样的话listener就和接口里的两个方法分离开了,还有一种方法。直接使用匿名类,让listener等于这个匿名类,在里面实现接口里的两个方法。(推荐使用第二种)
  • 传递数据的类:
class UtilNetWork {
    var listener: callBack? = null
    fun data(){
        Thread{
            Log.v("swl","开始下载。。${Thread.currentThread()}")
            Thread.sleep(2000)
            Log.v("swl","下载结束。。${Thread.currentThread()}")
            val result = "jack"
        }
        listener.let {
        }
    }
    interface callBack{
        fun onSuccess(data:String)
        fun onFailure(error:String)
    }
}
  • 接收数据的类,在MainActivity里面
 button.setOnClickListener {
           val util = UtilNetWork()
            util.listener = object :UtilNetWork.callBack{
                override fun onSuccess(data: String) {
                }
                override fun onFailure(error: String) {
                }
            }
        }
8.切换线程。
runOnUIThread{
//进行需要的操作
}
二、引入协程Corou线程池的七个参数tine
1.线程与协程的区别:
  • ①一个任务可以创建多个线程和进程的区别是什么线程,但是线程的数量是有限的。因为线程数量越多,那么消耗的内存越多,速度越慢。②对于协程来说,一共就两个线程,主线程和子线程。在子线携程程上可以创建无数个协程,资源消耗量不大,就在一个线程上进行调度,可以有成千上百个协程同时执行。协程会被阻塞,线程基本上不会被阻塞,因为一个线程上有很多和协程。
  • 线程执行任务是按顺线程池拒绝策略有哪些序的,如果线程上有任务在执行,后面的必须等它执行完了才能接着执行。线程安全但是线程上如果有执携程网上订票飞机行时间很长的协程,那么就会把它挂起,让它自己去执行,然后在线程上接着执行下一个协程。等到前面这个协程执行完了之后,又从挂起的那个地方恢复。
2.协程的特点:
  • 轻量:您可以在单个线程上运行多个协程,因为协程支持挂起,不会使正在运行协程的线程阻塞。挂起比阻塞节省内存,且支持多个并行操作。
  • 内存泄漏更少:使用结构化并发机制在一个作用域内执行多项操作。
  • 线程池创建的四种置取消支持:取消操作会自动在运行中的整个协程层次结构内传播。
  • Jetpack 集成:许多 Jetpack 库都包含提供全面协程支持的扩展。某些库还提供自己的协程作用域,可供您用于结构化并发。
3龚俊.线程池使用使用协程
  • 1.创建工商银行一个新的工程,在里面添加一个library,然后将以下依赖项添加到应用的 build.gradle 文件中。(如果只是在kotlin里面使用,那么直接导入下面的依赖库即可。但是如果是在安卓里面使用,那么还需要导入implementation(“org.jetbrains.kotlinx:kotlinx-corouti线程池拒绝策略有哪些nes-android:1.3.9″)这个依赖库)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
  • 2.在li线程的概念brary的包里面再创建一个MyClass类,在类外面写一个main()方法,在里面创建一个线程。
fun main(){
    println("main start ${Thread.currentThread()}")
    Thread{
        println("start ${Thread.currentThread()}")
        Thread.sleep(2000)
        println("end ${Thread.currentThread()}")
    }.start()
    println("main end ${Thread.currentThread()}")
}
运行结果如下图所示:

Android开发——Food美食项目实战

运行结果

主线线程池拒绝策略有哪些程不会被阻塞,所以main start之后立马携程网官网执行main en携程旅行app官方下载d。如果开启新线程的时间很短,那么输出顺序也可能为main start ->start->main end->end
  • 3.使用协程的方式。(那么就不能使用Thread,而要使用delay,因为Thread会阻塞线程,delay不会阻塞线程)
fun main(){
    println("main start ${Thread.currentThread()}")
    GlobalScope.launch {
        load() }
    println("main end ${Thread.currentThread()}")
}
suspend fun load(){
    println("start ${Thread.currentThread()}")
    delay(2000)
    println("end ${Thread.currentThread()}")
}

线程池使用何一个协程都有自己的Coro线程池拒绝策略有哪些utineScope,在这个协程域里面可以创建无数个子协程。
如何创建一个CoroutineScope:(一般google使用前面两种)

  • launch :创建一个独立的CoroutineScope。同步,不返回数据。
  • async :异步,需要返回数据。
  • runBlocking:它会在当前线程上创建一个协程域,并且这个执行会阻塞当前的线程。
  • GlobalScope:创建一个全局的CoroutineScope,不推荐使用。作用域为整个app的lifecycle。缺点:当主线线程数程结束,不会等待GlobalScope的协程执行完毕。它会创建一个新的线程。
suspend:挂起函数只能在另外一个挂起函数或者一个coroutineScope(协程域包括宫颈癌协程的所有使用方法,其中就有挂起功能)里面调用

Android开发——Food美食项目实战

G线程安全lobalScope运行结果

因为主线程是什么意思线程执行速度太快了,调用load方法还要延迟2S钟。所以新的线程还没开始,主线程就已经运行结束了。
  • 4.前面用的是Glo宫颈癌balScope,为了解决速度过快导致子线程无法开启的问题,我们可以延长主线程的执行时间,也delay一下,但是del宫颈癌ay是一个挂起方法,所以我们使用sunBlocking。
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
    GlobalScope.launch {
        load() }
     delay(3000)
    println("main end ${Thread.currentThread()}")
}
suspend fun load(){
    println("start ${Thread.currentThread()}")
    delay(2000)
    println("end ${Thread.currentThread()}")
}

Android开发——Food美食项目实战

runBlockGoing运行结果

可以发现由于主线程有延迟,而且延迟时携程机票间多于子线程,所以子线程执行完毕之后,主线程才结束。
三、lunch和asyno
1.只用runBlocking,不用GlobalScope的话,那么整个runBlocking都是协程域,整个协程都被挂起,不会有阻塞。
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
    loadTask1()
    println("main end ${Thread.currentThread()}")
}
suspend fun loadTask1(){
    println("start1 ${Thread.currentThread()}")
    delay(1000)
    println("end1 ${Thread.currentThread()}")
}

Android开发——Food美食项目实战

执行结果

很明显它是按照顺序执行的,因为它们都在同一个域里面。
2.使用launch创建协程
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
    launch {
        loadTask1()
    }
    println("main end ${Thread.currentThread()}")
}
suspend fun loadTask1(){
    println("start1 ${Thread.currentThread()}")
    delay(1000)
    println("end1 ${Thread.currentThread()}")
}

Android开发——Food美食项目实战

launch执行结果

  • launch并没有阻线程安全塞主线程的执行,如果再添加一个launch
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
    launch {
        loadTask1()
    }
    launch {
        loadTask2()
    }
    println("main end ${Thread.currentThread()}")
}
suspend fun loadTask1(){
    println("start1 ${Thread.currentThread()}")
    delay(1000)
    println("end1 ${Thread.currentThread()}")
}
suspend fun loadTask2(){
    println("start2 ${Thread.currentThread()}")
    delay(1000)
    println("end2 ${Thread.currentThread()}")
}

Android开发——Food美食项目实战

两个launch执行结果

  • 还是没有阻塞主线程,但是在执行1的时候,遇到了delay,所以1被挂起,执行2,然后1结束,2结束。
  • 使用measureTimeMillis方法来计算挂起的时间
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
   val time = measureTimeMillis {
       launch {
           loadTask1()
       }
       launch {
           loadTask2()
       }
   }
    println("time $time")
    println("main end ${Thread.currentThread()}")
}

Android开发——Food美食项目实战

计算结果线程是什么意思为15ms

  • 为什么会出现这个结果呢?因为我们打印的只是分配的时间,并不是执行的时间。当我们查看launch的源码,发现里面有一个join方法,它的作用是挂起一个协程知道它结束为止。线程池原理
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
   val time = measureTimeMillis {
       val job1 =launch {
           loadTask1()
       }
       job1.join()
      val job2= launch {
           loadTask2()
       }
       job2.join()
   }
    println("time $time")
    println("main end ${Thread.currentThread()}")
}
  • 调用苟在神诡世界join方法,发现end m线程池的作用ain到最后去了。

Android开发——Food美食项目实战

龚俊用join方法的执行线程池的作用结果

  • 所以我们可以发现这里协程是同步执行的,也就是线程和进程的区别是什么执行完了1才会执行2,由于线程开启关闭还需要时间,所以比2s多一点时间。
3.使用async创建协程。
fun main()= runBlocking{
    println("main start ${Thread.currentThread()}")
   val time = measureTimeMillis {
       val job1 =async {
           loadTask1()
       }
      val job2= async {
           loadTask2()
       }
      job1.await()
      job2.await()
   }
    println("time $time")
    println("main end ${Thread.currentThread()}")
}

Android开发——Food美食项目实战

异步执行结果

  • async是异步执行的。谁先读取完就执行谁工商银行的,没有顺序。很明显异步执行要比同步执行的时间短。
四、Coroutin工龄差一年工资差多少eScope和Corout线程池创建的四种ine枸杞Context
1.当我们执行以下代码线程池的作用时,会得到如下结果:
fun main(){
    runBlocking {
        println("1: ${Thread.currentThread()}")
        launch {
            println("2: ${Thread.currentThread()}")
        }
        println("3: ${Thread.currentThread()}")
    }
}

Android开发——Food美食项目实战

执行结果

把launch改为async,结果也是一样的。这说明就算开启协程的方式不同,但是线程是一样的,它并不线程池原理会开启新的线程。
2.CoroutineScope:使用携程旅行app官方下载launch和线程池创建的四种async时,携程客服电话都是创建一个新的scope
3.CoroutineContex枸杞t:使用lau线程数越多越好吗nch和async时,和parent scope在同一个context中
五、withContext切换线程
1.Dispatchers线程阻塞:调携程电话度器。
2.线程的切换主要线程数越多越好吗有:
  • Di线程池原理spatchers.Main – 使用此调度程序可在 And线程池的七个参数roid 主线程上运行协程。携程网上订票飞机此调度程序只能用于与界面交互和执行快速工作。示例包括调用 suspend 函数,运行 Android 界面框架操作,以及更新 LiveData 对象。
  • Dispatchers宫颈癌.IO – 此调度程序经过了线程池核心参数专门优化,适合在主线程之外执行磁盘或网络 I/O。示例包括使用 Room 组件、从文件中读取数据或向文件中写入数google据,以及运行任何网络操作。
  • Dispatchers.D线程池的七个参数efault – 此调度程序经过携程网官网了专门优化,适合在主线程之外执行占用大量 CPU 资源的工作。用例示例包括对列表排序和解析 JSON。
2.模拟一下用户登录的过程。在网络上先读取用户的id,再获取用户的信息。这是切换线程的一种方式,从io线程切换到main线程(在io线程运行结束后,会自动切换到main线程)。
data class User(val name:String)
fun main(){
    runBlocking {
      val result =  async (Dispatchers.IO) {
               login()
        }
     val userInfo = async(Dispatchers.IO) {
         userInfo(result.await())
     }
       println(userInfo.await().name)
    }
}
suspend fun login():Int{
    println("开始login")
    delay(1000)
    println("login成功")
    return 1001
}
suspend fun userInfo(id:Int):User{
    println("获取用户信息:$id")
    delay(1000)
    println("获取用户信息成功")
    return User("jack")
}
运行结果如下:

Android开发——Food美食项目实战

运行结果

3.如果一线程是什么意思个任务既要在主线程执行,又要在子线程执行,那么我建线程池的作用议先指定在主线程,需要子线程的时候再指定IO线程,这样它最终只会进行一次跳转。
fun main(){
    runBlocking {
     launch (Dispatchers.Main){
          launch (Dispatchers.IO){
          }
      }
    }
}
  • 还有一种就是在函数内部就提前指定好线程。这样直接调用函数更容易理解。
fun main(){
    runBlocking {
         val  id= login()
         val user= userInfo(id)
          println("user: ${user.name}")
    }
}
  suspend fun login():Int{
  return withContext(Dispatchers.IO){
        println("开始login")
        delay(1000)
        println("login成功")
         1001 //默认返回值
    }
}
suspend fun userInfo(id:Int):User{
  return  withContext(Dispatchers.IO){
        println("获取用户信息:$id")
        delay(1000)
        println("获取用户信息成功")
        User("jack")
    }
}

Android开发——Food美食项目实战

运行结果

4.使用withContext切换线程。这个还是没有上面的那个好。
 launch (Dispatchers.Main){
          withContext(Dispatchers.IO){
              login()
          }
          userInfo()
      }
    }
5.与基于回调的等效实现相比,withContext() 不会增加额外的开销。此外,在某些情况下,还可以优化 with携程客服电话Context() 调用,使其超越基线程池于回调的等效实现。例如枸杞,如果某线程池的五种状态个函数对一个网线程安全络进行十次调用,您可以使用外部 withContext() 让 Kotlin 只切换一次线程。这样,即使网络库多次使用 with线程池创建的四种Context(),它也会留在同一调度程序上,并避免切换线程。此外,Kotlin 还优化了 Dispatchers.DefaultDispatchers.IO 之间的切换,以尽可能避免线程切换。
  • 重要提示:利用一个使用线程池的调度程序(例如 Dis线程池原理patchers.IO 或 Dispatchers.Default)不能保证块在同一线程上从上到工作总结下执行。在某些情况下,Kotlin 协程在 suspend 和 resume 后可能会将执行工作移交给另一个Go线程。这意味着,对于整个 withC线程和进程的区别是什么ontext() 块,线程局部变量可能并不指向同一个值。
6.使用withContext其实还是会阻塞主线程,如果想携程网飞机票预订官网不阻塞主线程的话,另外开启一个新线程来调用login()和userInfo()函数,这样只会阻线程池塞当前线程,不会阻塞主线程工作总结
六、啰嗦OkHttGop
1.先向grgoogleadle中导入依赖库
androidTestImplementation 'androidx.test.espresso:espresso-android:3.3.0'
2.进入OkHttp官网squa线程池re.github.io/okhttp/,找到Releases导入依赖库。
  androidTestImplementation 'androidx.test.espresso:espresso-android:3.3.0'
3.OkHttp3实际上一个封装,封装的内容包括:
  • OkHttpClient:提供供品夫人给用户,用户通过这个来创建OkHttp,也就是对象。工商银行
  • Request:包括请求的地址和其他信息。
  • Call接口:里面定义了一些操作。真正来操作的是一个RealCall对象。
  • okio:真正做传输的核心。
4.applicati线程池的创建方式有几种on->okhttp3->Caching或服务器。在applicatio携程网官网n与okhttp3之间还有一个拦截器(NetWorkInterpreter,拦截网络的每一个操作,也就是获取详细信息)
  • OkHttpClient线程池面试题里面有一个call对象指向RealCall,还有线程的概念一个Dispatchers,Caching
  • Request包括url,meth携程网飞机票预订官网od
5.具体的使用详见square.github.io/okhttp/reci…
七、okhttp获取数据
1.数据有两种类型:
  • XML :几乎不用
  • JSON:工龄差一年工资差多少将JSON的数据转化为kotlin里面的数据类型。
这里需要使用聚合数据,我们先提前在聚合数据里面申协程请一个账号,然后选择API里面的免费项目,比如新闻头条,按照线程池拒绝策略有哪些它的线程池的七个参数格式发送携程电话请求

Android开发——Food美食项目实战

请求详情

在网页中输入以下网址:v.juhe.cn/toutiao/ind…,然后打开一个JSON解析器,将网页内苟在神诡世界的数据转化为我们能看懂的代码。

Android开发——Food美食项目实战

解析之后

解析之后折叠起来,只有三个元素,相当于三个map(包含key和value)
展开res线程ult:

Android开发——Food美食项目实战

result展开之后

2线程撕裂者.布局一下activity_main,我的布局加了一个按钮和一个progres供品夫人sBar:

Android开发——Food美食项目实战

activity_main布局

3.新建一个工程,向里面导入我们需要的依赖库。
//coroutine
    androidTestImplementation 'androidx.test.espresso:espresso-android:3.3.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
    //okhttp
    implementation("com.squareup.okhttp3:okhttp:4.9.0")
    // ViewModel
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0-alpha02")
    // LiveData
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.4.0-alpha02")
    // Lifecycles only (without ViewModel or LiveData)
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha02")
4.我们要根据前面获取到的信息做一个新闻展示页面,使用MVVM模式,所以要另外创建一个类作为ViewModel。
class NewsViewModel:ViewModel() {
    val news:MutableLiveData<String?> = MutableLiveData()
    init {
        news.value = null
    }
    fun loadNews(){
        viewModelScope.launch {
           news.value = realLoad()
        }
    }
    suspend fun realLoad():String? {
       return withContext(Dispatchers.IO) {
            val client = OkHttpClient()
            val request = Request.Builder()
                    .url("http://v.juhe.cn/toutiao/index?type=&key=4494d20d3e853ec01a1dafc8b901e716")
                    .get()
                    .build()
          val response = client.newCall(request).execute()
                if (response.isSuccessful) {
                     delay(2000)
                     response.body?.string()
                } else {
                   null
                }
            }
        }
    }
MainActivity代携程旅行app官方下载码如下:
class MainActivity : AppCompatActivity() {
    private lateinit var viewModel:NewsViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        ViewModelProvider(this,ViewModelProvider.NewInstanceFactory())
            .get(NewsViewModel::class.java)
        viewModel.news.observe(this){value->
            if(value!=null){
                progressBar.visibility = View.GONE
                Log.v("swl","$value")
            }
        }
        button.setOnClickListener {
            progressBar.visibility = View.VISIBLE
           viewModel.loadNews()
        }
    }
}
5.运行成功之后就能看到google打印出来的结果了。
八、聚合数据头条新闻API说明
1.OkHttp3和Retrofit请求数据公积金要使用的知识点
  • 聚合数据API使用携程机票
  • OkHttp3请求数据
  • Gson解析json数据
  • json To kotlin 插件使用
  • Retrofit请求数据的步骤
2.进入聚合数据官网www.juhe.cn/首页,选择生活服务,进入新闻头条板块。

Android开发——Food美食项目实战

新闻头条

3.v.juhe.cn/toutiao/线程池的作用i线程池使用nd…,按照这个格式就可以得到一个接口的地址v.juhe.cn/toutiao/ind…,type和key见下面的图片。

Android开发——Food美食项目实战

type和key

4.将我们按照需求设计好的网址在浏览器中输入,最后可以得到一串数据,将其放在json解析器里面进行解析。解析结果差不多如下图所示:

Android开发——Food美食项目实战

解析结果

九、使用OkHttp3获取数据
1.进入gith供品夫人ub官网,搜一下okhttp公积金,点进去第一个,查看详细信息。github.com/square/okht…
2.添加依赖库。
implementation("com.squareup.okhttp3:okhttp:4.9.1")
3.我们新建一个项目工程先测试一下,把依赖库导进去,然后在man线程池面试题ifest里龚俊面添加以下代码。携程网站官网后面那个是在里面。
<uses-permission android:name="android.permission.INTERNET"/>
 android:usesCleartextTraffic="true"
4.在MainActivity里面编写一下代码。
class MainActivity : AppCompatActivity() {
    private val xinwen_url = "http://v.juhe.cn/toutiao/index?type=guonei&key=4494d20d3e853ec01a1dafc8b901e716"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        if(event?.action == MotionEvent.ACTION_DOWN){
            val httpClient = OkHttpClient()
            val request = Request.Builder()
                    .url(xinwen_url)
                    .build()
            httpClient.newCall(request).enqueue(object:Callback{
                override fun onFailure(call: Call, e: IOException) {
                    e.printStackTrace()
                }
                override fun onResponse(call: Call, response: Response) {
                    if(response.isSuccessful){
                       val BodyStr =  response.body?.string()
                        Log.v("swl","下载的内容为:$BodyStr")
                    }
                }
            })
        }
        return super.onTouchEvent(event)
    }
}
最后的结果如下所示,这说明我们解析成了。宫颈癌

Android开发——Food美食项目实战

运行结果

十、手动创建数据模型
1.按照前面的方法,数据是获取到了,但是无法直接加进我们的项目中,所以我们要先建线程池使用一个数据模型。
2.打开github,搜索Gson,点击第一个。进入以下网住github.com/google/gson
3.根据上面的网址,导入一下依赖库。
 implementation 'com.google.code.gson:gson:2.8.7'
4.创建携程网站官网一个数据类,NewsModel,里面包含的数据携程网站官网和json解析器里面解析出来的数据类似。
data class NewsModel(
    val reason:String,
    val result:Result,
    val error_code:Int
)
data class Result (val data:List<New>, )
data class New(val title:String)
十一、使用插件自动创建模型
1.前面我们手动来创建模型,其实是很麻烦的,对于结构比较清晰的数据来说没问题,但如果对于结构比较复杂的线程的概念数据就很麻烦了,很容易出错。这时候就可以使用插件了。携程网官网
2.在Android Studio里面打开设置,点击plungs,搜索JSON,下载第一个即可。

Android开发——Food美食项目实战

下载插件

3.然后new一个kotlin data class file from json,把v.juhe.cn/to工商银行utgoogleiao/ind…这个线程的概念网址的内容全部拷贝进去,一个都不能漏,Annotatio线程数越多越好吗n记得勾Gson,其他都不变。

Android开发——Food美食项目实战

创建过程

4.自动创建好的代码如下图所示,我已经把不需要的删掉了。
data class NewsModel(
    @SerializedName("result")
    val result: Result
)
data class Result(
    @SerializedName("data")
    val data: List<Data>,
)
data class Data(
    @SerializedName("author_name")
    val authorName: String,
    @SerializedName("category")
    val category: String,
    @SerializedName("date")
    val date: String,
    @SerializedName("is_content")
    val isContent: String,
    @SerializedName("thumbnail_pic_s")
    val thumbnailPicS: String,
    @SerializedName("title")
    val title: String,
    @SerializedName("uniquekey")
    val uniquekey: String,
    @SerializedName("url")
    val url: String
)
5.在MainActivity里面,在前面的代线程池使用码后面进行解析。
if(response.isSuccessful){
                        val bodyStr =  response.body?.string()
                        val gson = Gson()
                        val model = gson.fromJson<NewsModel>(bodyStr,NewsModel::class.java)
                        model.result.data.forEach {
                            Log.v("swl",it.title)
                        }
                    }
6.运行结果如下图所示:

Android开发——Food美食项目实战

解析成功

十二、使用retrofit获取数据
1.retrofit相比于okhttp更简单,更简洁,所以用它更好。携程电话去square.gith宫颈癌ub.io/retrofit/网站查看它的使用方法。
2.导入一下依赖库。
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha02")
3.创建一个接口,作为API。
interface NewsAPI {
    @GET("index?type=guonei&key=4494d20d3e853ec01a1dafc8b901e716")
    suspend fun getNews():NewsModel
}
4.在MainAc携程网上订票飞机tivity里面写一个useRetrofit()方法,使用Ret工作总结rofit来获取数据。在onTouchEvent里面调用这个方法。
fun useRetrofit(){
        val retrofit = Retrofit.Builder()
                .baseUrl("http://v.juhe.cn/toutiao/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        val api =  retrofit.create(NewsAPI::class.java)
           lifecycleScope.launch {
           val news = api.getNews()
           news.result.data.forEach{
               Log.v("swl",it.title)
           }
       }
    }

Android开发——Food美食项目实战

运行结果

  • 因为新闻每3分钟就会刷新一次,所以新闻标题和前面不一样。

发表评论

提供最优质的资源集合

立即查看 了解详情