You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android名言展示App无法运行求助(含Retrofit等核心代码)

名言展示App启动失败问题排查与修复

我是Android开发新手,计划开发一款调用API的名言展示App,将名言内容与作者信息显示在TextView中,但App无法启动运行。以下是项目的全部核心代码:

1. MainActivity.kt

package com.example.latestnews

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.example.latestnews.databinding.ActivityMainBinding
import retrofit2.HttpException
import java.io.IOException


const val TAG = "Main Activity"

class MainActivity : AppCompatActivity() {
private lateinit var bind: ActivityMainBinding
private lateinit var adapt: Adapter

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    bind = ActivityMainBinding.inflate(layoutInflater)
    setContentView(bind.root)
    setuprecycleview()

    //coroutine
    lifecycleScope.launchWhenCreated {
        bind.progressBar.isVisible = true
        val response = try {
            RetrofitInstance.api.get()
        } catch (_: IOException) {
            Log.e(TAG, "IOException, you might not have internet connection")
            bind.progressBar.isVisible = false
            return@launchWhenCreated
        } catch (_: HttpException) {
            Log.e(TAG, "HttpException, unexpected response ")
            bind.progressBar.isVisible = false
            return@launchWhenCreated
        }
        if (response.isSuccessful && response.body() != null) {
            bind.progressBar.isVisible = false
            adapt.todo = response.body()!!
        } else {
            Log.e(TAG, "Response not successful")
            bind.progressBar.isVisible = false
        }
    }

}

private fun setuprecycleview() {
    bind.main.apply {
        adapt = Adapter()
        adapter = adapt
        layoutManager = LinearLayoutManager(this@MainActivity)
    }
}}

2. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/main"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.5" />

    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="visible"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

3. Adapter.kt

package com.example.latestnews

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.latestnews.databinding.NewsLayoutBinding

class Adapter:RecyclerView.Adapter<Adapter.QViewHolder>() {

    inner class QViewHolder(val binding: NewsLayoutBinding) :RecyclerView.ViewHolder(binding.root)
    lateinit var todo: Data


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QViewHolder {
        return QViewHolder(NewsLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
    }

    override fun onBindViewHolder(holder: QViewHolder, position: Int) {
        holder.binding.apply {
            val items = todo.results[position]
            textView.text=items.content
            textView2.text=items.author
        }
    }

    override fun getItemCount(): Int {
    return todo.count
    }
}

4. Quotesapi.kt

package com.example.latestnews

import retrofit2.Response
import retrofit2.http.GET

interface Quotesapi {
    @GET("/quotes")
    suspend fun get(): Response<Data>
}

5. RetrofitInstance.kt

package com.example.latestnews

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {

    val api:Quotesapi by lazy {
        Retrofit.Builder().
        baseUrl("https://quotable.io")
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(Quotesapi::class.java)//same name as interface
    }

}

6. Data.kt

package com.example.latestnews

data class Data(
    val count: Int,
    val lastItemIndex: Int,
    val page: Int,
    val results: List<Result>,
    val totalCount: Int,
    val totalPages: Int
)

7. Result.kt

package com.example.latestnews

data class Result(
    val _id: String,
    val author: String,
    val authorSlug: String,
    val content: String,
    val dateAdded: String,
    val dateModified: String,
    val length: Int,
    val tags: List<String>
)

8. news_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="80dp">

    <TextView
        android:id="@+id/textView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        tools:text="PlaceHolder1"
        android:layout_marginTop="10dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/textView2"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"/>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        tools:text="PlaceHolder2"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView"
        app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

问题分析

  1. 未初始化变量访问崩溃:Adapter中lateinit var todo: Data在App启动阶段未被赋值,但getItemCount()直接调用todo.count,会触发UninitializedPropertyAccessException,导致App启动即崩溃。
  2. 数据更新未通知RecyclerView:网络请求成功后给adapt.todo赋值,但未调用notifyDataSetChanged(),RecyclerView无法感知数据变化,不会刷新列表。
  3. 缺少网络权限:App调用外部API需要互联网权限,未添加的话会导致网络请求失败,后续逻辑无法执行。

修复方案

1. 修复Adapter.kt

将todo改为可空类型,避免未初始化访问,同时添加数据设置方法并通知RecyclerView刷新:

package com.example.latestnews

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.example.latestnews.databinding.NewsLayoutBinding

class Adapter:RecyclerView.Adapter<Adapter.QViewHolder>() {

    inner class QViewHolder(val binding: NewsLayoutBinding) :RecyclerView.ViewHolder(binding.root)
    var todo: Data? = null

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QViewHolder {
        return QViewHolder(NewsLayoutBinding.inflate(LayoutInflater.from(parent.context), parent, false))
    }

    override fun onBindViewHolder(holder: QViewHolder, position: Int) {
        val currentData = todo ?: return
        holder.binding.apply {
            val item = currentData.results[position]
            textView.text = item.content
            textView2.text = item.author
        }
    }

    override fun getItemCount(): Int {
        return todo?.count ?: 0
    }

    fun setData(newData: Data) {
        this.todo = newData
        notifyDataSetChanged()
    }
}

2. 修改MainActivity.kt的数据赋值逻辑

替换原有的直接赋值,调用Adapter的setData方法:

if (response.isSuccessful && response.body() != null) {
    bind.progressBar.isVisible = false
    adapt.setData(response.body()!!)
} else {
    Log.e(TAG, "Response not successful")
    bind.progressBar.isVisible = false
}

3. 添加网络权限

在AndroidManifest.xml的<manifest>标签内添加:

<uses-permission android:name="android.permission.INTERNET"/>

内容的提问来源于stack exchange,提问作者Alok Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 17:50:30