技术标签: 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是同一个对象。
在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>
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
}
}
文章浏览阅读219次。算法标签:肝法_luogu倍增
文章浏览阅读3.1k次。为了验证接口能否被正常访问,我们常常需要使用测试工具,来对数据接口进行检测。好处:接口测试工具能让我们在不写任何代码的情况下,对接口进行调用和调试。_postman工具
文章浏览阅读733次。0.准备 换了一个32G的u盘,不过没关系按照之前的博客30天自制操作系统-Hello OS填写fat32文件格式。对于每一个u盘,要注意逻辑扇区和具体物理扇区的关系:选定59904扇区作为写入磁盘数据的起始,对应的柱面和磁头和扇区写入ipl10.nas然后要更改asmhead.nas。该文件的作用将从保护模式跳至实模式,具体的可以看该博客《30天自制操作系统》学习..._c语言自制系统
文章浏览阅读2.2w次,点赞30次,收藏169次。前言 allegro的原理图设计和PCB设计用的是两款软件。而连接两款软件的桥梁是一种叫网表(netlist)的东西。网表记录了原理图中所以的元器件,元器件封装以及网络连接。原理图规则检查(DRC) 在生成网表之前肯定需要一个完全正确无误的原理图,因此先对原理图进行规则检查。 回到原理图根目录界面,选中原理图文件 点击Tools ->Design rule check,弹..._如何生成drc
文章浏览阅读582次。操作系统学习_操作系统学习
文章浏览阅读2.7k次。摘要:随着科技的发展与进步,计算机技术越来越成熟,计算机技术在图像处理领域的应用也越来越广泛。本文对计算机技术在各领域的应用进行了简单介绍,并对其发展前景进行了展望。关键词:计算机;技术;图像处理中图分类号:TP391 文献标识码:A 文章编号:1007-9599 (2012) 16-0000-02计算机技术的出现为人类的生产和生活提供了极大的方便。计算机技术广泛的应用在各行各业当中。计算机技术在..._1.结合个人经历,举例说明一种图像处理技术及其在日常生活中的应用。
文章浏览阅读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
文章浏览阅读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
文章浏览阅读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
文章浏览阅读7.3k次,点赞4次,收藏13次。win10电脑使用时间久了,会出现各种各样的故障问题,最常见属于网络问题。近期一位用户说电脑莫名其妙无法识别网络,桌面右下角提示“连接不可用”,无法上网是一个比较烦人...下面本站小编介绍下使用方法,希望大家喜欢!1.我们点击右下角的无线网络,打开网络和共享中心。2.点击“更改适配器设置”。3.在“网络连接”窗口,如果网络连接里面有无线网络连接是灰色情况,我们就右键点击“启用”。4.当网络连接里面..._未连接连接不可用
文章浏览阅读4.3k次,点赞2次,收藏11次。Mysql join查询的相关原理,实现,由此推出的优化策略;join大表后进行groupby操作慢sql通过临时表+join进行优化_mysql left join 大表
文章浏览阅读3.1w次,点赞7次,收藏24次。在百度云安装redis服务之后,一直给我发送系统安全警告,推荐我redis设置访问密码,于是出于安全考虑我就设置一下redis的密码1.修改redis.conf配置文件:找到requirepass这一行,解注这一行代码,requirepass后面就是跟的自己的密码。2.关闭redis服务,发现报错:可以使用下面两个方法关闭服务:方式一:通过ps aux|grep red..._new jedispool 加入密码