教你一步步开发手机商城应用开发(一) :准备工作

65 阅读4分钟

前言

本教程将带领大家一步步实现一个完整的Android手机商城应用。我们将使用Kotlin语言开发,采用MVVM架构模式

项目概览

我们的手机商城应用包含以下主要功能模块:

1.首页模块 - 展示轮播图、分类入口、推荐商品等

2.分类模块 - 商品分类浏览

3.购物车模块 - 商品选购、数量管理、结算功能

4.个人中心模块 - 用户信息、订单管理、设置等

5.商品详情模块 - 商品信息展示、规格选择、加入购物车

6.登录注册模块 - 用户身份认证

开发环境准备

1.Android Studio最新版(海獭)

2.JDK 17或更高版本

3.Gradle 9.0

4.Android SDK 36

接口文档: 点我查看,原作者指出是开源的

第一步:创建项目与基础配置

1. 创建新项目

打开Android Studio,创建一个新的Kotlin项目,选择Empty Activity模板。

2. 添加必要依赖

在项目级 build.gradle.kts 和模块级 build.gradle.kts 中添加必要的依赖:

implementation("io.coil-kt:coil:2.7.0") // Coil图片加载库
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
implementation("androidx.room:room-runtime:2.5.1")
ksp("androidx.room:room-compiler:2.5.1")
implementation("androidx.room:room-ktx:2.5.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1")
implementation("com.google.android.material:material:1.9.0")

第二步:实现统一的图片加载管理(Coil)

按照要求,我们将使用Coil进行统一的图片加载管理。首先创建工具类:

1. 创建图片加载工具类

import android.widget.ImageView
import coil.load
import coil.request.CachePolicy
import coil.transform.CircleCropTransformation
import coil.transform.RoundedCornersTransformation
import java.io.File

// 加载普通图片,开启缓存
fun setUrl(url: String?, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        // 添加内存优化配置
        scale(coil.size.Scale.FIT)
        allowHardware(false)
    }
}

// 设置圆角用户头像(本地文件)
fun setFileUrl(url: File?, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        size(80, 80)
        transformations(CircleCropTransformation())
    }
}

// 加载圆形图片
fun setUrlCircle(url: String?, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        transformations(CircleCropTransformation())
    }
}

// 加载圆角图片
fun setUrlRound(url: String?, circleNumber: Float, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        transformations(RoundedCornersTransformation(circleNumber))
    }
}

Coil最重要的是没有Context这种坑爹,因为这个Context处理不好就是轻则内存泄漏,重则闪退

手机商城应用开发详细教程

前言

本教程将带领大家一步步实现一个完整的Android手机商城应用。我们将使用Kotlin语言开发,采用MVVM架构模式,并特别注意使用Coil进行统一的图片加载管理。

项目概览

我们的手机商城应用包含以下主要功能模块:

  1. 首页模块 - 展示轮播图、分类入口、推荐商品等

2.分类模块 - 商品分类浏览

3.购物车模块 - 商品选购、数量管理、结算功能

4.个人中心模块 - 用户信息、订单管理、设置等

5.商品详情模块 - 商品信息展示、规格选择、加入购物车

6.登录注册模块* - 用户身份认证

开发环境准备

1.Android Studio最新版

2.JDK 11或更高版本

3.Gradle 9.0+

4.Android SDK 36

第一步:创建项目与基础配置

1. 创建新项目

打开Android Studio,创建一个新的Kotlin项目,选择Empty Activity模板。

2. 添加必要依赖

在项目级build.gradle.kts和模块级build.gradle.kts中添加必要的依赖:

Kotlin
// 模块级 build.gradle.kts 中添加以下依赖
implementation("io.coil-kt:coil:2.4.0") // Coil图片加载库
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1")
implementation("androidx.room:room-runtime:2.5.1")
ksp("androidx.room:room-compiler:2.5.1")
implementation("androidx.room:room-ktx:2.5.1")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.
1")
implementation("com.google.android.material:material:1.9.0")

第二步:实现统一的图片加载管理(Coil)

按照要求,我们将使用Coil进行统一的图片加载管理。首先创建工具类:

1. 创建图片加载工具类

Kotlin
// GlideUtil.kt
package org.lzy.shop.util
import android.widget.ImageView
import coil.load
import coil.request.CachePolicy
import coil.transform.CircleCropTransformation
import coil.transform.RoundedCornersTransformation
import org.lzy.shop.R
import java.io.File
// 加载普通图片,开启缓存
fun setUrl(url: String?, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        // 添加内存优化配置
        scale(coil.size.Scale.FIT)
        allowHardware(false)
    }
}
// 设置圆角用户头像(本地文件)
fun setFileUrl(url: File?, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        size(8080)
        transformations(CircleCropTransformation())
    }
}
// 加载圆形图片
fun setUrlCircle(url: String?, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        transformations(CircleCropTransformation())
    }
}
// 加载圆角图片
fun setUrlRound(url: String?, circleNumber: Float, img: ImageView) {
    img.load(url) {
        memoryCachePolicy(CachePolicy.ENABLED)
        diskCachePolicy(CachePolicy.ENABLED)
        crossfade(true)
        placeholder(R.mipmap.ic_launcher)
        error(R.mipmap.ic_launcher)
        transformations(RoundedCornersTransformation(circleNumber))
    }
}

2. 在应用中使用Coil加载图片

在任何需要加载图片的地方,我们都可以使用上面定义的扩展函数:

Kotlin
// 示例:在商品详情页加载轮播图
private val bannerManager by lazy {
    BannerManager(
        viewPager2 = binding.bannerViewpager,
        indicatorsContainer = binding.bannerIndicator,
        lifecycleOwner = this,
        dataList = bannerData ?: emptyList(),
        autoScrollDelay = 3000,
        isInfiniteLoop = true
    ).apply {
        // 设置图片加载器,使用我们的Coil扩展函数
        setImageLoader {
                imageView, url ->
            // 使用Coil加载圆角图片
            setUrlRound(url, 8f, imageView)
        }
    }
}

第三步:实现基础

1. 新建BaseActivity基类


import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.Window
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.viewbinding.ViewBinding
import kotlinx.coroutines.launch
import org.lzy.shop.util.ToastUtil

/**
 * 封装了通用的 init 方法,初始化布局,加载弹框等方法
 */
abstract class BaseActivity<VB : ViewBinding>(private val inflate: (LayoutInflater) -> VB) : AppCompatActivity() {
    protected lateinit var binding: VB
    protected var isDestroyed = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = inflate(layoutInflater)
        setContentView(binding.root)
        initView()
        initData()
        allClick()
    }

    // 初始化布局
    abstract fun initView()

    // 初始化数据
    abstract fun initData()

    // 处理所有点击事件
    abstract fun allClick()

    // 显示Toast
    fun showToast(message: String) {
        ToastUtil.show(message)
    }
}
  1. 创建应用类BaseApplication
import android.app.Application
import coil.ImageLoader
import coil.ImageLoaderFactory
import coil.memory.MemoryCache
import coil.request.CachePolicy
import coil.util.DebugLogger
import com.kongzue.dialogx.DialogX

class BaseApplication : Application(), ImageLoaderFactory {
    override fun onCreate() {
        super.onCreate()
        // 初始化DialogX
        DialogX.init(this)
        // 其他初始化操作
    }

    // 自定义Coil ImageLoader配置
    override fun newImageLoader(): ImageLoader {
        return ImageLoader.Builder(this)
            .memoryCache {
                MemoryCache.Builder(this)
                    .maxSizePercent(0.25)
                    .build()
            }
            .crossfade(true)
            .diskCachePolicy(CachePolicy.ENABLED)
            .memoryCachePolicy(CachePolicy.ENABLED)
            .respectCacheHeaders(false)
            .apply {
                if (BuildConfig.DEBUG) {
                    logger(DebugLogger())
                }
            }
            .build()
    }
}