ViewModel的基本使用_viewmodel使用-程序员宅基地

技术标签: kotlin  ViewModel  Android  

ViewModel的职责就是保证View层中数据的稳定性

一、基本使用

在app目录下build.gradle导入ViewModel依赖

implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'

MyViewModel.kt

package com.example.myviewmodel

import androidx.lifecycle.ViewModel

class MyViewModel : ViewModel() {

    // 数据放这 进行横竖屏切换不会丢失
    var number : Int = 0
}

MainActivity.kt

package com.example.myviewmodel

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
// Kotlin的绑定机制
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    // 数据放这 进行横竖屏切换会丢失
    // var number : Int = 0

    private lateinit var myViewModel: MyViewModel
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // myViewModel = MyViewModel()  // 不能直接实例化,因为这样写系统就不可控了

        // 旧版本的写法(扩展性不强)
        // ViewModelProviders.of(this).get(MyViewModel::class.java)

        // this == ViewModelStoreOwner接口
        myViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
            .get(MyViewModel::class.java)  // 通过反射来加载Java的class

        // Kotlin的绑定机制
        tv_number.text = "${myViewModel.number}"

        bt.setOnClickListener {
            tv_number.text = "${++myViewModel.number}"
        }

    }
}

  数据存放在ViewModelStore类中,该类有一个Map存储<String, ViewModel>,value为ViewModel,该ViewModel存放相关的具体数据,横竖屏切换保证ViewModelStore是同一个对象。

二、ViewModel + DataBinding + LiveData结合使用

1. java版本

在app目录下的build.gradle导入相关的依赖包

apply plugin: 'com.android.application'

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.jetpack_java2"
        minSdkVersion 26
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    // dataBinding引入方式
    // 方式一
    dataBinding {
        enabled  true
    }
    // 方式二
    // dataBinding.enabled = true

}

dependencies {
    implementation fileTree(dir: "libs", include: ["*.jar"])
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

    // ViewModel依赖
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<!-- DataBinding区域 -->
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="vm"
            type="com.example.jetpack_kotlin.MainViewModel" />
    </data>

    <!-- UI绘制区域 -->
    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical"
        android:background="@drawable/phone2_bg">

        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="0dip"
            android:layout_weight="1" />

        <!-- 电话号码 -->
        <TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:textSize="@dimen/activity_phone_tv"
            android:gravity="center"
            android:text="@{vm.phoneInfo}"
            android:textStyle="bold" />

        <!-- 表格布局 -->
        <TableLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="16dip">

            <!-- 第一列 -->
            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone1"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(1))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone2"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(2))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone3"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(3))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />
            </TableRow>

            <!-- 第二列 -->
            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone4"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(4))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone5"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(5))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone6"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(6))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />
            </TableRow>

            <!-- 第3列 -->
            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone7"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(7))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone8"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(8))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone9"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(9))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />
            </TableRow>

            <!-- 第4列 -->
            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phonexin"
                    android:onClick="@{()->vm.appendNumber(@string/phonexin)}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phone0"
                    android:onClick="@{()->vm.appendNumber(String.valueOf(0))}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />

                <Button
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="@string/phonejin"
                    android:onClick="@{()->vm.appendNumber(@string/phonejin)}"
                    android:textSize="@dimen/activity_phone_bt"
                    android:background="@drawable/phone_selector_number" />
            </TableRow>

            <!-- 第5列 -->
            <TableRow
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="6dip">

                <LinearLayout
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!-- 清空 -->
                    <Button
                        android:layout_width="40dp"
                        android:layout_height="40dp"
                        android:textSize="@dimen/activity_phone_bt"
                        android:background="@drawable/phone_selector_min"
                        android:layout_gravity="center"
                        android:onClick="@{()->vm.clear()}"
                        android:layout_margin="6dip" />

                </LinearLayout>

                <LinearLayout
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!-- 拨打 -->
                    <ImageView
                        android:layout_width="46dip"
                        android:layout_height="46dip"
                        android:src="@drawable/phone_selector_call"
                        android:onClick="@{()->vm.callPhone()}"
                        android:layout_gravity="center" />

                </LinearLayout>

                <LinearLayout
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <!-- 删除一个字符 -->
                    <Button
                        android:layout_width="60dp"
                        android:layout_height="wrap_content"
                        android:textSize="@dimen/activity_phone_bt"
                        android:background="@drawable/phone_selector_backspace"
                        android:layout_gravity="center"
                        android:onClick="@{()->vm.backspaceNumber()}"
                        />

                </LinearLayout>

            </TableRow>

        </TableLayout>

    </LinearLayout>
</layout>

MainViewModel.java

package com.example.jetpack_java2;

import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;

import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.MutableLiveData;

/**
 * AndroidViewModel 与 ViewModel的区别是 AndroidViewModel自带application环境
 */
public class MainViewModel extends AndroidViewModel {

    // 传统方式的数据
    // private String phoneInfo = "";  // 目前无法实现感应功能

    // 实现感应功能 LiveData + DataBinding
    private MutableLiveData<String> phoneInfo;

    // 环境
    private Context mContext;


    public MainViewModel(@NonNull Application application) {
        super(application);
        mContext = application;
    }

    // 把数据暴露出去 给布局用
    public MutableLiveData<String> getPhoneInfo() {
        if (phoneInfo == null) {
            phoneInfo = new MutableLiveData<>();

            // 设置默认值
            phoneInfo.setValue("");
        }
       return phoneInfo;
    }

    /**
     * 输入
     * @param number
     */
    public void appendNumber(String number) {
        phoneInfo.setValue(phoneInfo.getValue() + number);
    }

    /**
     * 删除
     */
    public void backspaceNumber() {
       int length = phoneInfo.getValue().length();
       if (length > 0) {
           phoneInfo.setValue(phoneInfo.getValue().substring(0, length - 1));
       }
    }

    /**
     * 清空
     */
    public void clear() {
        phoneInfo.setValue("");
    }

    /**
     * 拨打
     */
    public void callPhone() {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:" + phoneInfo.getValue()));
        // 非Activity启动拨号 或者是 非Activity启动任何的  startActivity都会崩溃
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        mContext.startActivity(intent);
    }
}

MainActivity.java

package com.example.jetpack_java2;

import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;

import android.os.Bundle;
import android.view.View;

import com.example.jetpack_java2.databinding.ActivityMainBinding;

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding dataBinding;   // DataBinding初始化
    private MainViewModel mainViewModel;       // MainViewModel初始化

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // setContentView(R.layout.activity_main);
        dataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);

        // 旧版本的写法
        // mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);

        // 下面是新版本的写法
        // 如果MainViewModel extends ViewModel
        // mainViewModel = new ViewModelProvider(this,
        //      new ViewModelProvider.NewInstanceFactory()).get(MainViewModel.class);

        // 如果MainViewModel extends AndroidViewModel
        mainViewModel = new ViewModelProvider(getViewModelStore(),
                new ViewModelProvider.AndroidViewModelFactory(getApplication())).get(MainViewModel.class);

        dataBinding.setVm(mainViewModel);

        dataBinding.setLifecycleOwner(this);  // DataBinding与LiveData建立感应
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.jetpack_java2">

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

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2. kotlin版本

MainViewModel.kt

package com.example.jetpack_kotlin

import android.app.Application
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData

class MainViewModel(application : Application) : AndroidViewModel(application) {

    // LiveData数据(有感应)
    val phoneInfo by lazy { MutableLiveData<String>() }

    init {
        phoneInfo.value = "" // 设置默认值
    }

    // 定义一个环境
    var mContext : Context = application

    /**
     * 输入
     */
    fun appendNumber(number : String) {
        phoneInfo.value = phoneInfo.value + number
    }

    /**
     * 删除
     */
    fun backspaceNumberr() {
        var length = phoneInfo.value?.length ?: 0
        if (length > 0) {
            phoneInfo.value = phoneInfo.value?.substring(0, length - 1)
        }
    }

    /**
     * 清空
     */
    fun clear() {
        phoneInfo.value = ""
    }

    /**
     * 拨号
     */
    fun callPhone() {
        var intent = Intent()
        intent.action = Intent.ACTION_CALL
        intent.data = Uri.parse("tel:" + phoneInfo.value)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        mContext.startActivity(intent)
    }
}

MainActivity.kt

package com.example.jetpack_kotlin

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.jetpack_kotlin.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    var binding : ActivityMainBinding ?= null
    var viewModel : MainViewModel ?= null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // setContentView(R.layout.activity_main)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        viewModel = ViewModelProvider(this, ViewModelProvider.AndroidViewModelFactory(application))
            .get(MainViewModel::class.java)

        binding?.vm = viewModel

        // DataBinding 与 LiveData 建立感应
        binding?.lifecycleOwner = this

    }
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xuyin1204/article/details/132569934

智能推荐

luoguP2838 瓶子国的故事——倍增_luogu倍增-程序员宅基地

文章浏览阅读219次。算法标签:肝法_luogu倍增

PostMan安装使用教程(非常详细)从零基础入门到精通,看完这一篇就够了_postman工具-程序员宅基地

文章浏览阅读3.1k次。为了验证接口能否被正常访问,我们常常需要使用测试工具,来对数据接口进行检测。好处:接口测试工具能让我们在不写任何代码的情况下,对接口进行调用和调试。_postman工具

30天自制操作系统-导入c语言_c语言自制系统-程序员宅基地

文章浏览阅读733次。0.准备 换了一个32G的u盘,不过没关系按照之前的博客30天自制操作系统-Hello OS填写fat32文件格式。对于每一个u盘,要注意逻辑扇区和具体物理扇区的关系:选定59904扇区作为写入磁盘数据的起始,对应的柱面和磁头和扇区写入ipl10.nas然后要更改asmhead.nas。该文件的作用将从保护模式跳至实模式,具体的可以看该博客《30天自制操作系统》学习..._c语言自制系统

cadence allegro原理图DRC,生成网表与导入PCB_如何生成drc-程序员宅基地

文章浏览阅读2.2w次,点赞30次,收藏169次。前言  allegro的原理图设计和PCB设计用的是两款软件。而连接两款软件的桥梁是一种叫网表(netlist)的东西。网表记录了原理图中所以的元器件,元器件封装以及网络连接。原理图规则检查(DRC)  在生成网表之前肯定需要一个完全正确无误的原理图,因此先对原理图进行规则检查。  回到原理图根目录界面,选中原理图文件  点击Tools ->Design rule check,弹..._如何生成drc

操作系统学习01-程序员宅基地

文章浏览阅读582次。操作系统学习_操作系统学习

用计算机处理图像属于啥技术,计算机技术在图像处理中的应用-程序员宅基地

文章浏览阅读2.7k次。摘要:随着科技的发展与进步,计算机技术越来越成熟,计算机技术在图像处理领域的应用也越来越广泛。本文对计算机技术在各领域的应用进行了简单介绍,并对其发展前景进行了展望。关键词:计算机;技术;图像处理中图分类号:TP391 文献标识码:A 文章编号:1007-9599 (2012) 16-0000-02计算机技术的出现为人类的生产和生活提供了极大的方便。计算机技术广泛的应用在各行各业当中。计算机技术在..._1.结合个人经历,举例说明一种图像处理技术及其在日常生活中的应用。

随便推点

【ART-Pi与RT-Thread入门】⑤ART-Pi配置PWM设备(避坑指南,已验证)-程序员宅基地

文章浏览阅读1.8k次,点赞6次,收藏12次。文章目录开发环境创建项目步骤1:RT-Thread Studio项目设置步骤2:打开board.h宏定义步骤3:STM32CubeMX(或者STM32CubeIDE)配置3.0 新建基于STM32H750XBHx的项目。3.1 在Pinout view中配置PI5为TIM8_CH13.2 配置时钟3.3 RCC中配置使用外部高速晶振HSE3.4 TIM8配置CH13.5 设置代码输出选项3.6 点击Generate Code4. 修改board.c和board.h5. 修改main.c6. 避坑指南开发环_art-pi

在CentOS服务器上安装Tesseract完整版,附带解决错误的办法,Java程序进行图像识别_could not initialize class net.sourceforge.tess4j.-程序员宅基地

文章浏览阅读2k次。安装安装gcc、gcc-c++、make,如果有就不需要安装:yum install gcc gcc-c++ make 安装编译相关工具,没有的话编译时候可能报错:yum install autoconf automake libtool 安装对图片识别相关支持工具,没有这些在后续执行Tesseract命令时会报错,可以尝试一下:yum install libjpeg-devel l..._could not initialize class net.sourceforge.tess4j.tessapi at net.sourceforge

#MySQL各种bug汇总#_mysql bug 53352-程序员宅基地

文章浏览阅读2.6k次。目录1.MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server2.The MySQL server is running with the--skip-grant-tables option3.MySQL——修改root密码的4种方法(以windows为例)4."Host 'localhost' ..._mysql bug 53352

win10电脑显示网络未连接到服务器,教你win10电脑网络连接显示未连接不可用的方法...-程序员宅基地

文章浏览阅读7.3k次,点赞4次,收藏13次。win10电脑使用时间久了,会出现各种各样的故障问题,最常见属于网络问题。近期一位用户说电脑莫名其妙无法识别网络,桌面右下角提示“连接不可用”,无法上网是一个比较烦人...下面本站小编介绍下使用方法,希望大家喜欢!1.我们点击右下角的无线网络,打开网络和共享中心。2.点击“更改适配器设置”。3.在“网络连接”窗口,如果网络连接里面有无线网络连接是灰色情况,我们就右键点击“启用”。4.当网络连接里面..._未连接连接不可用

Mysql join大表优化案例_mysql left join 大表-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏11次。Mysql join查询的相关原理,实现,由此推出的优化策略;join大表后进行groupby操作慢sql通过临时表+join进行优化_mysql left join 大表

redis设置密码以及jedisPool设置密码_new jedispool 加入密码-程序员宅基地

文章浏览阅读3.1w次,点赞7次,收藏24次。在百度云安装redis服务之后,一直给我发送系统安全警告,推荐我redis设置访问密码,于是出于安全考虑我就设置一下redis的密码1.修改redis.conf配置文件:找到requirepass这一行,解注这一行代码,requirepass后面就是跟的自己的密码。2.关闭redis服务,发现报错:可以使用下面两个方法关闭服务:方式一:通过ps aux|grep red..._new jedispool 加入密码

推荐文章

热门文章

相关标签