区块链技术博客
www.b2bchain.cn

Android项目搭建教程(Viewmodel、DataBinding)求职学习资料

本文介绍了Android项目搭建教程(Viewmodel、DataBinding)求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

新项目准备工作

新建项目建议使用 kotlinandroix.* 组件进行开发,毕竟属于Google官方推荐方式。

初始化建议实现方式

配置使用 Startup 组件进行开发,配置依赖:

implementation “androidx.startup:startup-runtime:1.0.0-beta01”

新建类实现 Initializer<Unit> 接口:

class Init : Initializer<Unit> {
override fun create(context: Context) {
// 进行初始化逻辑
Utils.mContext = context
}

override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}

}

清单文件配置启动模式:

<provider
android:name=”androidx.startup.InitializationProvider”
android:authorities=”${applicationId}.androidx-startup”
android:exported=”false”
tools:node=”merge”>
<meta-data
android:name=”com.xxx.xxx.Init” // 修改为自己Init类的全路径
android:value=”androidx.startup” />
</provider>

更多关于 Startup 使用请参考 官方文档

工具类

建议实现方式:

object Utils {
// 已在Init类初始化
lateinit var mContext: Context

fun showToast(content: String) {
Toast.makeText(mContext, content, Toast.LENGTH_LONG).show()
}
}

键值对存取

这里推荐使用腾讯的 MMKV 开源库进行实现。当然也可以使用官方推荐的 SharedPreferences

新建 SPUtils 类,封装如下:

object SPUtils {
private val mk by lazy {
MMKV.defaultMMKV()
}

fun put(key: String, value: Any) {
when (value) {
is String -> {
mk.encode(key, value)
}
is Boolean -> {
mk.encode(key, value)
}
is Int -> {
mk.encode(key, value)
}
is Long -> {
mk.encode(key, value)
}
is Parcelable -> {
mk.encode(key, value)
}
is Float -> {
mk.encode(key, value)
}
is Double -> {
mk.encode(key, value)
}
}
}

fun removeFromKey(key: String) {
mk.removeValueForKey(key)
}

fun getInt(key: String): Int {
return mk.decodeInt(key, 0)
}

fun getBoolean(key: String): Boolean {
return mk.decodeBool(key, false)
}

fun getString(key: String): String {
return mk.decodeString(key, “”)
}

fun getFloat(key: String): Float {
return mk.decodeFloat(key, 0.0f)
}

fun getDouble(key: String): Double {
return mk.decodeDouble(key, 0.0)
}

fun <T : Parcelable> getParceable(key: String, tClass: Class<T>): T {
return mk.decodeParcelable(key, tClass)
}
}

可以扩展自己实现方式,也可以直接使用此处封装好的。

更多使用方式及原理请参考 MMKV官方文档

BaseViewModel

目前的趋势,推荐使用 ViewModel 进行开发,降低业务逻辑耦合关联。

新建 ViewModel 工厂类创建带参数的 ViewModel,如果不需要带参数的 ViewModel,可以不用创建这个类:

class ViewmodelFactory(private val frag: FragmentManager) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.getConstructor(FragmentManager::class.java).newInstance(frag)
}
}

创建 BaseViewModel ,实现简单的页面展示及常用异常捕获:

abstract class BaseViewmodel(val frag: FragmentManager) : ViewModel(), LifecycleObserver {

fun showLoading() {
}

fun hideLoading() {
}

fun getException(ex: Exception) {
when (ex) {
is NetworkErrorException, is ConnectException ->
Utils.showToast(“网络连接异常~”)
is SocketTimeoutException, is TimeoutException ->
Utils.showToast(“网络连接超时~”)
else ->
ex.message?.let {
Utils.showToast(“未知异常~”)
Logger.e(it)
}
}
}
}

此处创建参数 FragmentManger 参数,是考虑到在 ViewModel 需要进行等待对话框的展示,当然也可以不用传入参数,直接使用在 Utils 中创建的 context 来进行对话框创建。对话框逻辑在这里实现是因为 ViewModel 一般会处理耗时操作,包括请求网络以及数据库读取。

BaseActivity

创建基类:

abstract class BaseActivity<VM : ViewModel> : AppCompatActivity() {
}

使用泛型进行约束,确保子类实现Viewmodel。如果有需要可以在泛型内添加 databing 约束:

abstract class BaseActivity<T : ViewDataBinding, VM: ViewModel> : AppCompatActivity() {
}

首先创建抽象函数,确保子类都需要实现的功能:

abstract fun initView()
abstract fun initData()
abstract fun setBarTitle(): String // 赋值标题栏
abstract fun getModel(): Class<VM> // 赋值子类的viewmodel类
abstract fun getLayoutId(): Int // 赋值布局文件

一般布局都会隐藏 Toolbar 并且把通知栏透明处理:

fun initConetnt() {
val option: Int = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
window.decorView.systemUiVisibility = option
window.statusBarColor = Color.TRANSPARENT
supportActionBar?.hide()
}

声明布局容器:

private val contentLayout by lazy { // 创建布局根容器为LinearLayout
LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
}
}

有统一的标题栏:

fun initToolbar() {
findViewById<ViewGroup>(android.R.id.content).apply { // 找到Layout文件的根布局
removeAllViews() // 移除所有布局
addView(contentLayout) // 添加声明的根布局
}
toolBar = layoutInflater.inflate(R.layout.layout_toolbar, null) // 引入自定义的标题栏
contentLayout.addView(toolBar) // 根布局添加标题栏

toolbar_back.setOnClickListener { // 标题栏左边功能为返回
finish()
}
toolbar_title.text = setBarTitle() // 根据子类实现的函数设置标题栏题目
}

重写添加布局函数

override fun setContentView(layoutResID: Int) {
layoutInflater.inflate(layoutResID, contentLayout) // 重写添加函数,把对应的布局文件添加到声明的根布局内
}

最后还需要根据泛型约束创建带参数的 ViewModel 实例:

protected val viewModel: VM by lazy {
ViewModelProvider(this, ViewmodelFactory(supportFragmentManager))[getModel()]
}

如果实际逻辑中用不到带参数的 ViewModel,可以使用官方的实例方式:

protected val viewModel: VM by lazy {
ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[getModel()]
}

整合以上逻辑,onCreate 函数最终内容:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initContent()
initToolbar()

setContentView(getLayoutId()) // 根据子类实现填充布局

initView()
initData()
}

还需要提供隐藏 toolbar 的函数:

fun hideToolbar() {
contentLayout.removeViewAt(0)
}

使用方式:

class SplashActivity : BaseActivity<SplashViewmodel>() {

override fun initView() {
hideToolbar() // 隐藏标题栏
}

override fun initData() {
viewModel.spLD.observe(this, {
// 数据观察
})

viewModel.getData(2) // 因为BaseActivity已经声明了viewModel,所以可以直接使用
}

override fun getModel(): Class<SplashViewmodel> = SplashViewmodel::class.java
override fun getLayoutId(): Int = R.layout.activity_splash
override fun setBarTitle(): String = “我是标题”
}

如此操作,一个基本的Android项目框架便是搭建完成。

如果有更好的建议,欢迎大家提出来一起讨论进步。

小建议

在viewmodel中使用协程可以使用viewmodel域内的协程,自动绑定viewmodel的生命周期。

添加依赖:

//viewmodel 协程
implementation ‘androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha07’

使用方式(在viewmodel中):

viewModelScope.launch {
// dosomething
}

不用再单独声明协程作用域。

新项目准备工作

新建项目建议使用 kotlinandroix.* 组件进行开发,毕竟属于Google官方推荐方式。

初始化建议实现方式

配置使用 Startup 组件进行开发,配置依赖:

implementation “androidx.startup:startup-runtime:1.0.0-beta01”

新建类实现 Initializer<Unit> 接口:

class Init : Initializer<Unit> {
override fun create(context: Context) {
// 进行初始化逻辑
Utils.mContext = context
}

override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}

}

清单文件配置启动模式:

<provider
android:name=”androidx.startup.InitializationProvider”
android:authorities=”${applicationId}.androidx-startup”
android:exported=”false”
tools:node=”merge”>
<meta-data
android:name=”com.xxx.xxx.Init” // 修改为自己Init类的全路径
android:value=”androidx.startup” />
</provider>

更多关于 Startup 使用请参考 官方文档

工具类

建议实现方式:

object Utils {
// 已在Init类初始化
lateinit var mContext: Context

fun showToast(content: String) {
Toast.makeText(mContext, content, Toast.LENGTH_LONG).show()
}
}

键值对存取

这里推荐使用腾讯的 MMKV 开源库进行实现。当然也可以使用官方推荐的 SharedPreferences

新建 SPUtils 类,封装如下:

object SPUtils {
private val mk by lazy {
MMKV.defaultMMKV()
}

fun put(key: String, value: Any) {
when (value) {
is String -> {
mk.encode(key, value)
}
is Boolean -> {
mk.encode(key, value)
}
is Int -> {
mk.encode(key, value)
}
is Long -> {
mk.encode(key, value)
}
is Parcelable -> {
mk.encode(key, value)
}
is Float -> {
mk.encode(key, value)
}
is Double -> {
mk.encode(key, value)
}
}
}

fun removeFromKey(key: String) {
mk.removeValueForKey(key)
}

fun getInt(key: String): Int {
return mk.decodeInt(key, 0)
}

fun getBoolean(key: String): Boolean {
return mk.decodeBool(key, false)
}

fun getString(key: String): String {
return mk.decodeString(key, “”)
}

fun getFloat(key: String): Float {
return mk.decodeFloat(key, 0.0f)
}

fun getDouble(key: String): Double {
return mk.decodeDouble(key, 0.0)
}

fun <T : Parcelable> getParceable(key: String, tClass: Class<T>): T {
return mk.decodeParcelable(key, tClass)
}
}

可以扩展自己实现方式,也可以直接使用此处封装好的。

更多使用方式及原理请参考 MMKV官方文档

BaseViewModel

目前的趋势,推荐使用 ViewModel 进行开发,降低业务逻辑耦合关联。

新建 ViewModel 工厂类创建带参数的 ViewModel,如果不需要带参数的 ViewModel,可以不用创建这个类:

class ViewmodelFactory(private val frag: FragmentManager) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.getConstructor(FragmentManager::class.java).newInstance(frag)
}
}

创建 BaseViewModel ,实现简单的页面展示及常用异常捕获:

abstract class BaseViewmodel(val frag: FragmentManager) : ViewModel(), LifecycleObserver {

fun showLoading() {
}

fun hideLoading() {
}

fun getException(ex: Exception) {
when (ex) {
is NetworkErrorException, is ConnectException ->
Utils.showToast(“网络连接异常~”)
is SocketTimeoutException, is TimeoutException ->
Utils.showToast(“网络连接超时~”)
else ->
ex.message?.let {
Utils.showToast(“未知异常~”)
Logger.e(it)
}
}
}
}

此处创建参数 FragmentManger 参数,是考虑到在 ViewModel 需要进行等待对话框的展示,当然也可以不用传入参数,直接使用在 Utils 中创建的 context 来进行对话框创建。对话框逻辑在这里实现是因为 ViewModel 一般会处理耗时操作,包括请求网络以及数据库读取。

BaseActivity

创建基类:

abstract class BaseActivity<VM : ViewModel> : AppCompatActivity() {
}

使用泛型进行约束,确保子类实现Viewmodel。如果有需要可以在泛型内添加 databing 约束:

abstract class BaseActivity<T : ViewDataBinding, VM: ViewModel> : AppCompatActivity() {
}

首先创建抽象函数,确保子类都需要实现的功能:

abstract fun initView()
abstract fun initData()
abstract fun setBarTitle(): String // 赋值标题栏
abstract fun getModel(): Class<VM> // 赋值子类的viewmodel类
abstract fun getLayoutId(): Int // 赋值布局文件

一般布局都会隐藏 Toolbar 并且把通知栏透明处理:

fun initConetnt() {
val option: Int = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
window.decorView.systemUiVisibility = option
window.statusBarColor = Color.TRANSPARENT
supportActionBar?.hide()
}

声明布局容器:

private val contentLayout by lazy { // 创建布局根容器为LinearLayout
LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
}
}

有统一的标题栏:

fun initToolbar() {
findViewById<ViewGroup>(android.R.id.content).apply { // 找到Layout文件的根布局
removeAllViews() // 移除所有布局
addView(contentLayout) // 添加声明的根布局
}
toolBar = layoutInflater.inflate(R.layout.layout_toolbar, null) // 引入自定义的标题栏
contentLayout.addView(toolBar) // 根布局添加标题栏

toolbar_back.setOnClickListener { // 标题栏左边功能为返回
finish()
}
toolbar_title.text = setBarTitle() // 根据子类实现的函数设置标题栏题目
}

重写添加布局函数

override fun setContentView(layoutResID: Int) {
layoutInflater.inflate(layoutResID, contentLayout) // 重写添加函数,把对应的布局文件添加到声明的根布局内
}

最后还需要根据泛型约束创建带参数的 ViewModel 实例:

protected val viewModel: VM by lazy {
ViewModelProvider(this, ViewmodelFactory(supportFragmentManager))[getModel()]
}

如果实际逻辑中用不到带参数的 ViewModel,可以使用官方的实例方式:

protected val viewModel: VM by lazy {
ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[getModel()]
}

整合以上逻辑,onCreate 函数最终内容:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initContent()
initToolbar()

setContentView(getLayoutId()) // 根据子类实现填充布局

initView()
initData()
}

还需要提供隐藏 toolbar 的函数:

fun hideToolbar() {
contentLayout.removeViewAt(0)
}

使用方式:

class SplashActivity : BaseActivity<SplashViewmodel>() {

override fun initView() {
hideToolbar() // 隐藏标题栏
}

override fun initData() {
viewModel.spLD.observe(this, {
// 数据观察
})

viewModel.getData(2) // 因为BaseActivity已经声明了viewModel,所以可以直接使用
}

override fun getModel(): Class<SplashViewmodel> = SplashViewmodel::class.java
override fun getLayoutId(): Int = R.layout.activity_splash
override fun setBarTitle(): String = “我是标题”
}

如此操作,一个基本的Android项目框架便是搭建完成。

如果有更好的建议,欢迎大家提出来一起讨论进步。

小建议

在viewmodel中使用协程可以使用viewmodel域内的协程,自动绑定viewmodel的生命周期。

添加依赖:

//viewmodel 协程
implementation ‘androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha07’

使用方式(在viewmodel中):

viewModelScope.launch {
// dosomething
}

不用再单独声明协程作用域。

新项目准备工作

新建项目建议使用 kotlinandroix.* 组件进行开发,毕竟属于Google官方推荐方式。

初始化建议实现方式

配置使用 Startup 组件进行开发,配置依赖:

implementation “androidx.startup:startup-runtime:1.0.0-beta01”

新建类实现 Initializer<Unit> 接口:

class Init : Initializer<Unit> {
override fun create(context: Context) {
// 进行初始化逻辑
Utils.mContext = context
}

override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}

}

清单文件配置启动模式:

<provider
android:name=”androidx.startup.InitializationProvider”
android:authorities=”${applicationId}.androidx-startup”
android:exported=”false”
tools:node=”merge”>
<meta-data
android:name=”com.xxx.xxx.Init” // 修改为自己Init类的全路径
android:value=”androidx.startup” />
</provider>

更多关于 Startup 使用请参考 官方文档

工具类

建议实现方式:

object Utils {
// 已在Init类初始化
lateinit var mContext: Context

fun showToast(content: String) {
Toast.makeText(mContext, content, Toast.LENGTH_LONG).show()
}
}

键值对存取

这里推荐使用腾讯的 MMKV 开源库进行实现。当然也可以使用官方推荐的 SharedPreferences

新建 SPUtils 类,封装如下:

object SPUtils {
private val mk by lazy {
MMKV.defaultMMKV()
}

fun put(key: String, value: Any) {
when (value) {
is String -> {
mk.encode(key, value)
}
is Boolean -> {
mk.encode(key, value)
}
is Int -> {
mk.encode(key, value)
}
is Long -> {
mk.encode(key, value)
}
is Parcelable -> {
mk.encode(key, value)
}
is Float -> {
mk.encode(key, value)
}
is Double -> {
mk.encode(key, value)
}
}
}

fun removeFromKey(key: String) {
mk.removeValueForKey(key)
}

fun getInt(key: String): Int {
return mk.decodeInt(key, 0)
}

fun getBoolean(key: String): Boolean {
return mk.decodeBool(key, false)
}

fun getString(key: String): String {
return mk.decodeString(key, “”)
}

fun getFloat(key: String): Float {
return mk.decodeFloat(key, 0.0f)
}

fun getDouble(key: String): Double {
return mk.decodeDouble(key, 0.0)
}

fun <T : Parcelable> getParceable(key: String, tClass: Class<T>): T {
return mk.decodeParcelable(key, tClass)
}
}

可以扩展自己实现方式,也可以直接使用此处封装好的。

更多使用方式及原理请参考 MMKV官方文档

BaseViewModel

目前的趋势,推荐使用 ViewModel 进行开发,降低业务逻辑耦合关联。

新建 ViewModel 工厂类创建带参数的 ViewModel,如果不需要带参数的 ViewModel,可以不用创建这个类:

class ViewmodelFactory(private val frag: FragmentManager) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.getConstructor(FragmentManager::class.java).newInstance(frag)
}
}

创建 BaseViewModel ,实现简单的页面展示及常用异常捕获:

abstract class BaseViewmodel(val frag: FragmentManager) : ViewModel(), LifecycleObserver {

fun showLoading() {
}

fun hideLoading() {
}

fun getException(ex: Exception) {
when (ex) {
is NetworkErrorException, is ConnectException ->
Utils.showToast(“网络连接异常~”)
is SocketTimeoutException, is TimeoutException ->
Utils.showToast(“网络连接超时~”)
else ->
ex.message?.let {
Utils.showToast(“未知异常~”)
Logger.e(it)
}
}
}
}

此处创建参数 FragmentManger 参数,是考虑到在 ViewModel 需要进行等待对话框的展示,当然也可以不用传入参数,直接使用在 Utils 中创建的 context 来进行对话框创建。对话框逻辑在这里实现是因为 ViewModel 一般会处理耗时操作,包括请求网络以及数据库读取。

BaseActivity

创建基类:

abstract class BaseActivity<VM : ViewModel> : AppCompatActivity() {
}

使用泛型进行约束,确保子类实现Viewmodel。如果有需要可以在泛型内添加 databing 约束:

abstract class BaseActivity<T : ViewDataBinding, VM: ViewModel> : AppCompatActivity() {
}

首先创建抽象函数,确保子类都需要实现的功能:

abstract fun initView()
abstract fun initData()
abstract fun setBarTitle(): String // 赋值标题栏
abstract fun getModel(): Class<VM> // 赋值子类的viewmodel类
abstract fun getLayoutId(): Int // 赋值布局文件

一般布局都会隐藏 Toolbar 并且把通知栏透明处理:

fun initConetnt() {
val option: Int = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
window.decorView.systemUiVisibility = option
window.statusBarColor = Color.TRANSPARENT
supportActionBar?.hide()
}

声明布局容器:

private val contentLayout by lazy { // 创建布局根容器为LinearLayout
LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
}
}

有统一的标题栏:

fun initToolbar() {
findViewById<ViewGroup>(android.R.id.content).apply { // 找到Layout文件的根布局
removeAllViews() // 移除所有布局
addView(contentLayout) // 添加声明的根布局
}
toolBar = layoutInflater.inflate(R.layout.layout_toolbar, null) // 引入自定义的标题栏
contentLayout.addView(toolBar) // 根布局添加标题栏

toolbar_back.setOnClickListener { // 标题栏左边功能为返回
finish()
}
toolbar_title.text = setBarTitle() // 根据子类实现的函数设置标题栏题目
}

重写添加布局函数

override fun setContentView(layoutResID: Int) {
layoutInflater.inflate(layoutResID, contentLayout) // 重写添加函数,把对应的布局文件添加到声明的根布局内
}

最后还需要根据泛型约束创建带参数的 ViewModel 实例:

protected val viewModel: VM by lazy {
ViewModelProvider(this, ViewmodelFactory(supportFragmentManager))[getModel()]
}

如果实际逻辑中用不到带参数的 ViewModel,可以使用官方的实例方式:

protected val viewModel: VM by lazy {
ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())[getModel()]
}

整合以上逻辑,onCreate 函数最终内容:

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

initContent()
initToolbar()

setContentView(getLayoutId()) // 根据子类实现填充布局

initView()
initData()
}

还需要提供隐藏 toolbar 的函数:

fun hideToolbar() {
contentLayout.removeViewAt(0)
}

使用方式:

class SplashActivity : BaseActivity<SplashViewmodel>() {

override fun initView() {
hideToolbar() // 隐藏标题栏
}

override fun initData() {
viewModel.spLD.observe(this, {
// 数据观察
})

viewModel.getData(2) // 因为BaseActivity已经声明了viewModel,所以可以直接使用
}

override fun getModel(): Class<SplashViewmodel> = SplashViewmodel::class.java
override fun getLayoutId(): Int = R.layout.activity_splash
override fun setBarTitle(): String = “我是标题”
}

如此操作,一个基本的Android项目框架便是搭建完成。

如果有更好的建议,欢迎大家提出来一起讨论进步。

小建议

在viewmodel中使用协程可以使用viewmodel域内的协程,自动绑定viewmodel的生命周期。

添加依赖:

//viewmodel 协程
implementation ‘androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.0-alpha07’

使用方式(在viewmodel中):

viewModelScope.launch {
// dosomething
}

不用再单独声明协程作用域。

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » Android项目搭建教程(Viewmodel、DataBinding)求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们