实战项目 - 新闻阅读器

99 阅读2分钟

第九章:实战项目 - 新闻阅读器

项目概述

我们将开发一个新闻阅读应用,包含以下功能:

  • 新闻列表展示
  • 新闻详情页
  • 收藏功能
  • 夜间模式
  • 缓存支持

项目结构

app/
├── data/
│   ├── api/            # 网络请求接口
│   ├── db/             # 本地数据库
│   ├── model/          # 数据模型
│   └── repository/     # 数据仓库
├── di/                 # 依赖注入
├── ui/
│   ├── news/          # 新闻列表
│   ├── detail/        # 新闻详情
│   └── favorite/      # 收藏列表
└── utils/             # 工具类

数据模型定义

// 新闻数据模型
@Entity(tableName = "news")
data class News(
    @PrimaryKey
    val id: String,
    val title: String,
    val content: String,
    val imageUrl: String,
    val publishTime: Long,
    var isFavorite: Boolean = false
)

// API 接口定义
interface NewsApi {
    @GET("news/list")
    suspend fun getNewsList(): List<News>

    @GET("news/{id}")
    suspend fun getNewsDetail(@Path("id") newsId: String): News
}

数据仓库实现

class NewsRepository @Inject constructor(
    private val newsApi: NewsApi,
    private val newsDao: NewsDao,
    private val context: Context
) {
    // 获取新闻列表,支持缓存
    fun getNewsList() = flow {
        // 先加载缓存
        emit(Resource.Loading(newsDao.getAllNews()))

        try {
            // 请求网络数据
            val remoteNews = newsApi.getNewsList()
            // 更新缓存
            newsDao.insertAll(remoteNews)
            // 发送最新数据
            emit(Resource.Success(newsDao.getAllNews()))
        } catch (e: Exception) {
            emit(Resource.Error("Failed to fetch news", newsDao.getAllNews()))
        }
    }
}

UI 实现

新闻列表页面

@AndroidEntryPoint
class NewsListFragment : Fragment() {
    private val viewModel: NewsViewModel by viewModels()
    private lateinit var binding: FragmentNewsListBinding

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val adapter = NewsAdapter { news ->
            // 导航到详情页
            findNavController().navigate(
                NewsListFragmentDirections.actionListToDetail(news.id)
            )
        }

        binding.recyclerView.adapter = adapter

        // 观察数据变化
        viewModel.newsList.observe(viewLifecycleOwner) { state ->
            when (state) {
                is Resource.Success -> {
                    binding.progressBar.isVisible = false
                    adapter.submitList(state.data)
                }
                is Resource.Loading -> {
                    binding.progressBar.isVisible = true
                }
                is Resource.Error -> {
                    binding.progressBar.isVisible = false
                    // 显示错误提示
                }
            }
        }
    }
}

新闻列表项布局

<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp">

    <ImageView
        android:id="@+id/newsImage"
        android:layout_width="100dp"
        android:layout_height="70dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/newsTitle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:textSize="16sp"
        android:textStyle="bold"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/newsImage"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/newsTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="12sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

通过这个实战项目,我们可以学习到:

  1. 如何合理组织项目结构
  2. 数据层、业务层、展示层的分离
  3. 各种 Android 组件的实际应用
  4. 界面布局的实现
  5. 网络请求与本地存储的结合

学习结语

从 Web 前端到 Android 开发的转型之路虽然充满挑战,但也充满机遇。通过这本教程,我们了解了从开发环境搭建、布局设计,到网络请求、数据存储等 Android 开发的核心概念。你会发现很多 Web 开发中的经验都能在 Android 开发中得到运用,比如组件化思维、状态管理、网络通信等。

作为开发者,保持学习的心态很重要。Android 技术生态在不断发展,建议你:

  • 持续关注 Android 开发的最新动态
  • 多阅读优秀的开源项目源码
  • 在实践中不断总结和提升

记住,每个优秀的 Android 开发者都是从第一行代码开始的。希望这本教程能够帮助你在 Android 开发的道路上走得更远。