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>
问题分析
- 未初始化变量访问崩溃:Adapter中
lateinit var todo: Data在App启动阶段未被赋值,但getItemCount()直接调用todo.count,会触发UninitializedPropertyAccessException,导致App启动即崩溃。 - 数据更新未通知RecyclerView:网络请求成功后给
adapt.todo赋值,但未调用notifyDataSetChanged(),RecyclerView无法感知数据变化,不会刷新列表。 - 缺少网络权限: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
相关产品推荐
相关产品推荐

