LiveData+Room

article/2025/11/11 5:51:14

文章目录

  • LiveData
    • 1.LiveData的作用
    • 2.LiveData的特点
    • 3.LiveData与ViewModel(无参数)的结合
    • 4.LiveData与ViewModel(有参数)的结合
    • 5.map()和switchMap()
      • 5.0 map()和switchMap()的作用
      • 5.1map()
        • 5.11没带ViewModel版
        • 5.12带ViewModel版
      • 5.2switchMap()
  • Room
    • 1.Room的定义
    • 2.Room的三个组件
    • 3.添加依赖
    • 4.Room数据库的使用
      • 4.1Entity的用法
        • 4.11定义主键
        • 4.12定义复合主键
        • 4.13忽略字段
      • 4.2DAO访问数据
        • 4.21DAO的一些基本用法
          • 4.211插入操作
          • 4.212更新操作
          • 4.213删除操作
          • 4.214查询操作
            • 4.2141简单的查询
            • 4.2142返回表格列的子集
            • 4.2143将参数传递给查询
      • 4.3Database
      • 4.4创建数据库

LiveData

1.LiveData的作用

LiveData是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 activityfragmentservice)的生命周期。这种感知能力可确保 LiveData 仅更新处于活跃生命周期状态的应用组件观察者。

《第一行代码安卓》第三版中提到

LiveData主要用来是和ViewModel结合起来用,因为ViewModel在单线程中不会出错,但是一旦ViewModel内部开启线程去执行,得到的数据还是原来的数据

2.LiveData的特点

如果观察者的生命周期处于STARTED或者RESUMED,则LiveData认为观察者处于活跃状态,LiveData会把更新通知给活跃观察者,

非活跃观察者不会收到通知

3.LiveData与ViewModel(无参数)的结合

public class TextViewModel extends ViewModel {public MutableLiveData<Integer> livedata = new MutableLiveData<Integer>();int a =0;public void init(){livedata.setValue(a);Log.d("1234",String.valueOf(livedata.getValue()));}public void plusOne(){a++;livedata.setValue(a);Log.d("1234",String.valueOf(livedata.getValue()));}public void clear(){a = 0;livedata.setValue(a);}
}

这个作用就是init()获得此时的a的值的大小

plusOne()a的值+1,然后显示a的值的大小

clear()a的值清零

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);TextViewModel viewModel = new ViewModelProvider(this).get(TextViewModel.class);TextView textView = findViewById(R.id.textview);Button button_0 = findViewById(R.id.button_0);Button button_1 = findViewById(R.id.button_1);Button button_2 = findViewById(R.id.button_2);button_0.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {viewModel.init();}});button_1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {viewModel.plusOne();}});button_2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {viewModel.clear();}});viewModel.livedata.observe(this, new Observer<Integer>() {@Overridepublic void onChanged(Integer integer) {textView.setText(String.valueOf(integer));}});}
}

先看TextViewModel的那块

 public MutableLiveData<Integer> livedata = new MutableLiveData<Integer>();

这里我们将livedata修改为MutableLiveData对象,并把它的泛型指定为Integer,表示为它包含整型数据,

为什么要用MutableLiveData呢,因为MutableLiveData为一种可变的LiveData

image-20221123220848735

这是MutableLiveData的源码,可以看出来MutableLiveData的主要功能是实现了LiveDatapostValuesetValue的功能

getValue()获取LiveData中的数据
setValue()在主线程中给LiveData设置数据
postValue()在非主线程中给LiveData设置数据

这样大部分代码都能看懂了,这下我们再来看看MainActivity里面的代码

viewModel.livedata.observe(this, new Observer<Integer>() {@Overridepublic void onChanged(Integer integer) {textView.setText(String.valueOf(integer));}});

任何一个LiveData对象都可以调用它的**observe()**方法来观察数据的变化

observe()方法接受两个参数:
第一个参数为一个
LifecycleOwner对象
,activity本身就有一个lifecycle对象,因此直接传入this。第二个是Observe()接口,当livedata中的数据发生变化便会回调到这里

4.LiveData与ViewModel(有参数)的结合

其实可以直接在刚才LiveDataViewModel **(无参数)**的版本下修改

但我还是重写了一个

public class ViewModel extends androidx.lifecycle.ViewModel {public MutableLiveData<Integer>mIntegerMutableLiveData;int a = 0;public ViewModel(MutableLiveData<Integer> integerMutableLiveData) {mIntegerMutableLiveData = integerMutableLiveData;}public void init(){mIntegerMutableLiveData.setValue(a);}public void addOne(){a++;mIntegerMutableLiveData.setValue(a);}public void clear(){a = 0;mIntegerMutableLiveData.setValue(a);}
}

其实就是比无参版的多了一个

public ViewModel(MutableLiveData<Integer> integerMutableLiveData) {mIntegerMutableLiveData = integerMutableLiveData;}

也就是有参构造


ViewModelFactory中和向ViewModel传递参数的差不多

public class ViewModelFactory implements ViewModelProvider.Factory {public MutableLiveData<Integer>mIntegerMutableLiveData;public ViewModelFactory(MutableLiveData<Integer> integerMutableLiveData) {mIntegerMutableLiveData = integerMutableLiveData;}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {return (T) new com.example.livedataviewmodelwithparams.ViewModel(mIntegerMutableLiveData);}
}

MainActivity中的修改

public class MainActivity extends AppCompatActivity {SharedPreferences mPreferences;ViewModel mViewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mPreferences = PreferenceManager.getDefaultSharedPreferences(this);int a = mPreferences.getInt("sava_data",0);MutableLiveData<Integer> savedCounter = new MutableLiveData<>(a);mViewModel = new ViewModelProvider(this,new ViewModelFactory(savedCounter)).get(ViewModel.class);Button button = findViewById(R.id.button_0);Button button1 = findViewById(R.id.button_1);Button button2 = findViewById(R.id.button_2);TextView textView = findViewById(R.id.textview);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mViewModel.init();}});button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mViewModel.addOne();}});button2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {mViewModel.clear();}});mViewModel.mIntegerMutableLiveData.observe(this, new Observer<Integer>() {@Overridepublic void onChanged(Integer integer) {textView.setText(String.valueOf(integer));}});}@Overrideprotected void onPause() {super.onPause();SharedPreferences.Editor editor = mPreferences.edit();editor.putInt("sava_data",mViewModel.mIntegerMutableLiveData.getValue());editor.apply();}
}

真的代码差不多

我感觉唯一要注意的就是这儿

	int a = mPreferences.getInt("sava_data",0);MutableLiveData<Integer> savedCounter = new MutableLiveData<>(a);mViewModel = new ViewModelProvider(this,new ViewModelFactory(savedCounter)).get(ViewModel.class);

为什么说唯一要注意的就是这儿呢,因为哥们当时候傻逼了,

我当时候是这么写的

	MutableLiveData<Integer>savaedcounter = mPreferences.getInt("sava_data",0);

然后这块一直爆红,原因也很明显

mPreferences.getInt("sava_data",0);

这个是int类型,而MutableLiveDatasavaedcounter是一个**MutableLiveData**类型,卡了好久

最后发现,你不是要**MutableLiveData**这个类型嘛,我给你转化成这个不就好了,

所以就先

int a = mPreferences.getInt("sava_data",0);
MutableLiveData<Integer> savedCounter = new MutableLiveData<>(a);

就成功转化

其他就没啥了。

5.map()和switchMap()

5.0 map()和switchMap()的作用

比如一个user类,类里面包含了一个名字年龄,可是我只想要user里面的年龄,这时候怎么办呢,这时就得用

**map()或者switchMap()**了。

但我写着写着发现它的作用就是:

把一个类型变成另一个类型

5.1map()

如果希望在将 LiveData 对象分派给观察者之前对存储在其中的值进行更改,或者需要根据另一个实例的值返回不同的 LiveData 实例,可以使用LiveData中提供的Transformations类。

比如我想把一个 MutableLiveData类型转化为String类型

5.11没带ViewModel版

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//Integer类型的liveData1MutableLiveData<Integer> liveData1 = new MutableLiveData<>();TextView textView = findViewById(R.id.textview);//转换成String类型的liveDataMapLiveData<String> liveDataMap = Transformations.map(liveData1, new Function<Integer, String>() {@Overridepublic String apply(Integer input) {String s = input + "好好听课";Log.i("TAG", "apply: " + s);return s;}});liveDataMap.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {Log.i("TAG", "onChanged1: "+s);textView.setText(s);}});liveData1.setValue(100);}
}

最后的结果就是

其实主要有用的就是这几段代码

MutableLiveData<Integer> liveData1 = new MutableLiveData<>();
LiveData<String> liveDataMap = Transformations.map(liveData1, new Function<Integer, String>() {@Overridepublic String apply(Integer input) {String s = input + "好好听课";Log.i("TAG", "apply: " + s);return s;}});

第一行,确定了它的类型是**MutableLiveData**类型

第二行

LiveData<String> liveDataMap = Transformations.map(liveData1, new Function<Integer, String>() {@Overridepublic String apply(Integer input) {String s = input + "好好听课";Log.i("TAG", "apply: " + s);return s;}});

最后再让liveDataMap进行observe()

textview上显示

5.12带ViewModel版

其实那个不带ViewModel版写和不写没啥区别,LiveData不和ViewModel进行绑定就没啥意义

我写的还是带参数的那个版本

ViewModel

public class viewmodel extends ViewModel {public MutableLiveData<Integer>mIntegerMutableLiveData = new MutableLiveData<Integer>();public viewmodel(int value) {mIntegerMutableLiveData.postValue(value);Log.d("TAG","好"+String.valueOf( mIntegerMutableLiveData.getValue()));}public LiveData<String> liveDataMap = Transformations.map(mIntegerMutableLiveData, new Function<Integer, String>() {@Overridepublic String apply(Integer input) {Log.d("TAG","hahaha"+(input));String s = input+"hahaha";Log.d("TAG", "apply: " + s);return s;}});
}

ViewModelFactory

public class viewmodelfactory implements ViewModelProvider.Factory {private int value;public viewmodelfactory(int value) {this.value = value;}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {return (T) new viewmodel(value);}
}

MainActivity

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//Integer类型的liveData1TextView textView = findViewById(R.id.textview);//转换成String类型的liveDataMapviewmodel viewModel = new ViewModelProvider(this,new viewmodelfactory(1)).get(viewmodel.class);viewModel.liveDataMap.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {textView.setText(s);}});}
}

最后的效果

5.2switchMap()

如果想要根据某个值 切换观察不同LiveData数据,则可以使用Transformations.switchMap()方法

viewmodel

public class viewmodel extends ViewModel {public MutableLiveData<String>mMutableLiveData =  new MutableLiveData<>();public MutableLiveData<String>mMutableLiveData1 = new MutableLiveData<>();public MutableLiveData<Integer>mIntegerMutableLiveData = new MutableLiveData<>();public LiveData<String> mlivedata = Transformations.switchMap(mIntegerMutableLiveData, new Function<Integer, LiveData<String>>() {@Overridepublic LiveData<String> apply(Integer input) {if(input==123) {return mMutableLiveData;}else{return mMutableLiveData1;}}});public viewmodel(int a,String b,String c) {mIntegerMutableLiveData.setValue(a);mMutableLiveData.setValue(b);mMutableLiveData1.setValue(c);}
}

viewmodelfactory

public class viewmodelfactory implements ViewModelProvider.Factory {public int a;public String b;public String c;public viewmodelfactory(int a,String b,String c){this.a = a;this.b = b;this.c = c;}@NonNull@Overridepublic <T extends ViewModel> T create(@NonNull Class<T> modelClass) {return  (T) new viewmodel(a,b,c);}
}

MainActivity

public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);viewmodel viewModel  = new ViewModelProvider(this,new viewmodelfactory(1,"hao","good")).get(viewmodel.class);TextView textView = findViewById(R.id.text_1);viewModel.mlivedata.observe(this, new Observer<String>() {@Overridepublic void onChanged(String s) {textView.setText(s);}});}
}

最后效果

![](https://img-blog.csdnimg.cn/101fc84f7b8a4c6a9d2521af54037edd.png

Room

1.Room的定义

首先使用的数据库是一个面向关系数据库,将面向对象的语言面向关系的数据库结合在一起就是ORM,即对象关系映射

Room就是有这样的一个ORM框架

Room 是一个数据库对象映射库,可以轻松访问 Android 应用程序上的数据库。

Room 持久性库在 SQLite 上提供了一个抽象层,以便在充分利用 SQLite 的强大功能的同时,能够流畅地访问数据库。具体来说,Room 具有以下优势:

  • 针对 SQL 查询的编译时验证。
  • 可最大限度减少重复和容易出错的样板代码的方便注解。
  • 简化了数据库迁移路径。

2.Room的三个组件

  • (Database)[数据库类],用于保存数据库并作为应用持久性数据底层连接的主要访问点。

  • (Entity)[数据实体],用于表示应用的数据库中的表。

  • (DAO)[数据访问对象 (DAO)],提供您的应用可用于查询、更新、插入和删除数据库中的数据的方法。

3.添加依赖

implementation 'androidx.room:room-common:2.3.0'
implementation 'androidx.room:room-runtime:2.4.3'
annotationProcessor "androidx.room:room-compiler:2.4.3" 

4.Room数据库的使用

4.1Entity的用法

您可以将每个 Room 实体定义为带有 [@Entity] 注解的类。Room 实体包含数据库中相应表中的每一列的字段,包括构成[主键]的一个或多个列。

以下代码是一个简单实体的示例,定义了一个 User 表,其中包含 ID 列、名字列

@Entity
public class User {
@PrimaryKeypublic int uid;
@ColumnInfopublic String name;
}

注意:要保留某个字段,Room 必须拥有该字段的访问权限。您可以通过将某个字段设为公开或为其提供 getter 和 setter 方法,确保 Room 能够访问该字段。

默认情况下,Room 将类名称用作数据库表名称。如果您希望表具有不同的名称,请设置 @Entity 注解的 tableName属性。同样,Room 默认使用字段名称作为数据库中的列名称。如果您希望列具有不同的名称,请将 [@ColumnInfo] 注解添加到该字段并设置 [name] 属性。

@Entity(tableName = "users")
public class User {@PrimaryKeypublic int id;@ColumnInfo(name = "first_name")public String firstName;
}

原本没有写**(tableName = “users”)之前,这个数据库的名字是User**,用来之后,数据库的名字变成了users

4.11定义主键

 @PrimaryKey

来定义主键

主键外键
主键是能确定一条记录的唯一标识外键用于与另一张表的关联。是能确定另一张表记录的字段,用于保持数据的一致性

刚才的那段代码,主键就是id

4.12定义复合主键

如果您需要通过多个列的组合对实体实例进行唯一标识,则可以通过列出 @Entity 的 [primaryKeys]属性中的以下列定义一个复合主键:

@Entity(primaryKeys = {"firstName", "lastName"})
public class User {public String firstName;public String lastName;
}

4.13忽略字段

默认情况下,Room 会为实体中定义的每个字段创建一个列。 如果某个实体中有您不想保留的字段,则可以使用 **[@Ignore]**为这些字段添加注解,

@Entity
public class User {
@PrimaryKeypublic int uid;
@ColumnInfopublic String name;
@Ignorepublic String lastName;
}

这样你的数据库中就不会出现lastName这个数据了

如果实体继承了父实体的字段,则使用 属性的 [ignoredColumns]属性通常会更容易:@Entity

@Entity(ignoredColumns = "lastName")
public class newUser extends User{
@PrimaryKeypublic int id;
@ColumnInfopublic String name1;
}

我用newUser继承User这个类

在**@Entity()里面写ignoredColumns = “”**就会把原本那个类的一个东西忽略了

4.2DAO访问数据

当您使用 Room 持久性库存储应用的数据时,您可以通过定义数据访问对象 (DAO) 与存储的数据进行交互。每个 DAO 都包含一些方法,这些方法提供对应用数据库的抽象访问权限。在编译时,Room 会自动为您定义的 DAO 生成实现。

通过使用 DAO(而不是查询构建器或直接查询)来访问应用的数据库,您可以**[使关注点保持分离]**

我的理解就是,不要把所有功能都写到MainActivity和同一个Fragment,这样可以避免许多与组件生命周期相关的问题,并提高这些类的可测试性

,这是一项关键的架构原则。DAO 还可让您在**[测试应用]**时更轻松地模拟数据库访问。

4.21DAO的一些基本用法

4.211插入操作
@Dao
public interface UserDao {@Insertpublic void insertUsers(User... users);@Insertpublic void insertBothUsers(User user1, User user2);@Insertpublic void insertUsersAndFriends(User user, List<User> friends);
}

Insert这个注释表示的是插入,方法中的对象的类必须是在Entity中被注释过

,调用**@Insert就会执行插入的操作,方法中无需再写其他的东西**

如果 @Insert 方法接收单个参数,则会返回 long 值,这是插入项的新 rowId。如果参数是数组或集合,则该方法应改为返回由 long 值组成的数组或集合,并且每个值都作为其中一个插入项的 rowId

4.212更新操作

借助 @Update 注释,您可以定义更新数据库表中特定行的方法。与 @Insert 方法类似,@Update 方法接受数据实体实例作为参数。 以下代码展示了一个 @Update 方法示例,该方法尝试更新数据库中的一个或多个 User 对象:

@Dao
public interface UserDao{
@Update
public void updataUsers(User... users);
}

Room 使用主键将传递的实体实例与数据库中的行进行匹配。如果没有具有相同主键的行,Room 不会进行任何更改。

@Update 方法可以选择性地返回 int 值,该值指示成功更新的行数。

4.213删除操作

借助 @Delete 注释,您可以定义从数据库表中删除特定行的方法。与 @Insert 方法类似,@Delete 方法接受数据实体实例作为参数。 以下代码展示了一个 @Delete 方法示例,尝试从数据库中删除一个或多个 User 对象:

@Dao
public interface UserDao{
@Delete
public void deleteUsers(User... users);
}

它的操作方法和更新的操作步骤差不多

4.214查询操作

使用 **[@Query]**注解,您可以编写 SQL 语句并将其作为 DAO 方法公开。使用这些查询方法从应用的数据库查询数据,或者需要执行更复杂的插入、更新和删除操作。

Room 会在编译时验证 SQL 查询。这意味着,如果查询出现问题,则会出现编译错误,而不是运行时失败。

4.2141简单的查询

以下代码定义了一个方法,该方法使用简单的 SELECT 查询返回数据库中的所有 User 对象:

@Dao
public interface UserDao{
@Query("SELECT * FROM user")
public User[] loadAllUsers();
}
4.2142返回表格列的子集

在大多数情况下,您只需要返回要查询的表中的列的子集。例如,您的界面可能仅显示用户的名字和姓氏,而不是该用户的每一条详细信息。为节省资源并简化查询的执行,您应只查询所需的字段。

借助 Room,您可以从任何查询返回简单对象,前提是您可以将一组结果列映射到返回的对象。例如,您可以定义以下对象来保存用户的名字和姓氏:

public class NameTuple {@ColumnInfo(name = "first_name")public String firstName;@ColumnInfo(name = "last_name")@NonNullpublic String lastName;
}
@Query("SELECT first_name, last_name FROM user")
public List<NameTuple> loadFullName();
4.2143将参数传递给查询

大多数情况下,您的 DAO 方法需要接受参数,以便它们可以执行过滤操作。Room 支持在查询中将方法参数用作绑定参数。

返回特定年龄以上的所有用户的方法

@Query("SELECT * FROM user WHERE age > :minAge")
public User[] loadAllUsersOlderThan(int minAge);

还可以在查询中传递多个参数或多次引用同一参数,如以下代码所示:

@Query("SELECT * FROM user WHERE age BETWEEN :minAge AND :maxAge")
public User[] loadAllUsersBetweenAges(int minAge, int maxAge);@Query("SELECT * FROM user WHERE first_name LIKE :search " +"OR last_name LIKE :search")
public List<User> findUserWithName(String search);

某些 DAO 方法可能要求您传入数量不定的参数,参数的数量要到运行时才知道。Room 知道参数何时表示集合,并根据提供的参数数量在运行时自动将其展开。

例如,以下代码定义了一个方法,该方法返回了部分地区的所有用户的相关信息:

@Query("SELECT * FROM user WHERE region IN (:regions)")
public List<User> loadUsersFromRegions(List<String> regions);

4.3Database

创建数据库

AppDatabase 定义数据库配置,并作为应用对持久性数据的主要访问点。数据库类必须满足以下条件:
1.该类必须带有 @Database 注解,该注解包含列出所有与数据库关联的数据实体的 entities 数组。
2.该类必须是一个抽象类,用于扩展 RoomDatabase。
3.对于与数据库关联的每个 DAO 类,数据库类必须定义一个具有零参数的抽象方法,并返回 DAO 类的实例。

@Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {public abstract UserDao userDao();
}

version = 1表示只有1张User表

4.4创建数据库

MainActivity

AppDatabase db = Room.databaseBuilder(getApplicationContext(),AppDatabase.class, "database-name").build();

第一个参数为整个应用程序的顶层上下文,第二个参数为数据库类,第三个参数为数据库的名称,最后调用build方法完成创建。

有了具体的数据库后我们就可以使用DAO来对其进行具体的操作了,还记得我们在
数据库类中有一个返回相应的DAO的方法,我们可以用其来获取DAO:

UserDao userDao = db.userDao();
"SELECT * FROM user WHERE first_name LIKE :search " +"OR last_name LIKE :search")
public List<User> findUserWithName(String search);

某些 DAO 方法可能要求您传入数量不定的参数,参数的数量要到运行时才知道。Room 知道参数何时表示集合,并根据提供的参数数量在运行时自动将其展开。

例如,以下代码定义了一个方法,该方法返回了部分地区的所有用户的相关信息:

@Query("SELECT * FROM user WHERE region IN (:regions)")
public List<User> loadUsersFromRegions(List<String> regions);

http://chatgpt.dhexx.cn/article/GUlkCJo8.shtml

相关文章

Android架构组件(二)——LiveData

Android架构组件&#xff08;二&#xff09;——LiveData 上一篇文章讲到了Android架构组件之一Lifecycle组件&#xff08;Android 架构组件&#xff08;一&#xff09;——Lifecycle-Aware Components&#xff0c;现在我们再来看看另一个成员LiveData。 定义 简单地说&#xf…

Android LiveData 使用详解

说在前面 本次推出 Android Architecture Components 系列文章&#xff0c;目前写好了四篇&#xff0c;主要是关于 lifecycle&#xff0c;livedata 的使用和源码分析&#xff0c;其余的 Navigation&#xff0c; Paging library&#xff0c;Room&#xff0c;WorkMannager 等春节…

由浅入深,详解 LiveData 的那些事

引言 关于LiveData,在2022尾声的今天&#xff0c;从事 Android 开发的小伙伴一定不会陌生。相应的&#xff0c;关于 LiveData 解析与使用的文章更是数不胜数&#xff0c;其中不乏优秀的创作者&#xff0c;在众多的文章以及前辈面前&#xff0c;本篇也不敢妄谈能写的多么深入,易…

LiveData的原理和使用

LiveData Livedata是什么&#xff1f;它的作用是什么&#xff1f;我们能用它来干什么&#xff1f; 首先&#xff0c;LiveData是一种可观察的数据存储类。这句话可以看成两个部分&#xff0c;一个是可观察的类&#xff0c;另一个是数据存储的类。 LiveData 是可以被观察的&am…

python电子书合集

Python电子书合集 小编最早接触的编程语言是C&#xff0c;决心走上编程之路的是JavaScript&#xff0c;后来入职靠的Java&#xff0c;后来发现还有一门短小精悍的语言叫——Python。 本来以为是一门新语言&#xff0c;结果才发现是自己out了&#xff0c;没想到这门语言比小编还…

《Python Cookbook》(中文第三版):电子书

《Python Cookbook&#xff08;第3版&#xff09;中文版》介绍了Python应用在各个领域中的一些使用技巧和方法&#xff0c;其主题涵盖了数据结构和算法&#xff0c;字符串和文本&#xff0c;数字、日期和时间&#xff0c;迭代器和生成器&#xff0c;文件和I/O&#xff0c;数据编…

python编程入门电子书-《Python编程 从入门到实践》高清电子书免费下载

今天给大家分享一本书 获取方式 公众号后台回复 Python基础 获取百度网盘下载链接 书籍简介 本书旨在让你成为优秀的程序员&#xff0c;具体地说&#xff0c;是优秀的Python程序员。通过阅读本书&#xff0c;你将迅速掌握编程概念&#xff0c;打下坚实的基础&#xff0c;并…

【小沐学Python】Python实现在线电子书制作(MkDocs + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建新项目4、添加页面5、编辑导航页6、设置主题7、更改图标图标8、构建网站9、部署9.1 准备github项目9.2 注册登录Read the Docs9.3 导入github项目到 Read the Docs 10、Markdown语法10.1 横线10.2 标题10.3 段落10.4 文字高亮10.5 换行10.6 斜体…

超全的Python完全版电子书——从基础到爬虫、分析等高级应用,限时下载

python3.11即将于下半年发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 1、爬虫。简单的…

【小沐学Python】Python实现在线电子书制作(Sphinx + readthedocs + github + Markdown)

文章目录 1、简介2、安装3、创建测试工程4、项目文件结构5、编译为本地文件6、编译为http服务7、更改样式主题8、支持markdown9、修改文档显示结构10、项目托管到github11、部署到ReadtheDocs结语 1、简介 Sphinx 是一个 文档生成器 &#xff0c;您也可以把它看成一种工具&…

python编程入门电子书-Python3零基础教材电子书合集

Python3零基础教材电子书合集&#xff0c;传送门&#xff1a;https://www.52pojie.cn/thread-676318-1-1.html 一、《Python编程从入门到实践》 链接&#xff1a;https://pan.baidu.com/s/1o9wJq0y 密码&#xff1a;12od 这书楼主现在也在看&#xff0c;讲的很细&#xff0c;…

学习Python必看的经典书籍(附电子书)

哈喽&#xff0c;我是牙儿 今天给大家推荐几本经典的Python书籍 一起来看看都有哪些吧~ 1 《Python学习手册&#xff08;第4版&#xff09;》 这本书全面、深入地介绍了 Python 语言&#xff0c;不管你是编程新手还是 Python 初学者&#xff0c;它将帮助你快速实现使用 Pyt…

超全的Python完全版电子书.pdf !从基础到爬虫、分析等高级应用,限时下载

python3.11即将于下半年发布&#xff0c;新的版本速度提升2倍&#xff0c;以弥补与其他编程语言在速度上的缺陷。可以预见Python语言在未来的应用范围会越来越广。 python学习方向建议&#xff1a; 如果你是本科及以下学历&#xff0c;建议你学习以下两个方向 1、爬虫。简单…

python入门经典电子书-推荐6本学习Python的免费电子书

便宜并不是没好货&#xff0c;这里的一些书籍已经被很多大学作为课本来使用&#xff0c;比如麻省理工的计算机科学与编程入门课程&#xff0c;加利福尼亚大学的编程思想课程都用到了下面的某(几)本书籍。 简明 简明 Python 教程是Swaroop C.H. 教授为Python初学者写的一本书。…

Python 开源电子书资源

转载自公众号&#xff1a;Mocun6 昨天给大伙儿送了书&#xff0c;留言区的篇幅占了整篇文章的一半&#xff0c;看来大家都想好&#xff08;把&#xff09;好&#xff08;我&#xff09;学&#xff08;掏&#xff09;习&#xff08;空&#xff09;。今天不送纸质书了&#xff0c…

100多本python书,免费电子版下载

推荐&#xff1a; 1、Coffee Break Python Slicing: 24 Workouts to Master Slicing in Python, Once and for All 切片&#xff08;Slicing&#xff09;是 Python 里非常有用的一个功能&#xff0c;属于 Python 开发人员最基本的技能之一。 如果你是初学者而且想了解 Slicin…

学习 Python 必看的书单(附电子书链接)

本文为你分享入门Python的必读书单。 学 Python 看什么书&#xff1f; 这是刚接触 Python 的朋友最疑惑的问题。 今天就结合自己入门时的学习历程和大家来聊一聊如何入门 Python&#xff0c;为了更有说服性一些&#xff0c;这里我把入门时看过的一些大佬推荐的书单进行了汇总…

python入门电子版-Python3零基础教材电子书合集

Python3零基础教材电子书合集,传送门:https://www.52pojie.cn/thread-676318-1-1.html 一、《Python编程从入门到实践》 链接:https://pan.baidu.com/s/1o9wJq0y 密码:12od 这书楼主现在也在看,讲的很细,建议大家零基础的从这书开始最好。个人觉得比《简明python教程》…

Python爬虫获取电子书资源实战

最近在学习Python&#xff0c;相对java来说python简单易学、语法简单&#xff0c;工具丰富&#xff0c;开箱即用&#xff0c;适用面广做全栈开发那是极好的&#xff0c;对于小型应用的开发&#xff0c;虽然运行效率慢点&#xff0c;但开发效率极高。大大提高了咱们的生产力。为…

全套Python零基础学习资料,电子书整理好了,想要进行技术提升,转行的自取!

今天分享Python入门级宝典 所有资料都是专业大佬总结整理出来的 Python的知识体系&#xff0c;从0开始学习Python看这一篇就够了! 《Python入门思维导图》 《看漫画学Python电子版》 《Python学习路线图》 《100道Python练习题》 《70个Python项目》 今天把这些分享给真…