安卓数据存储总结(永久存储和临时存储)
作者:互联网
0.目录
安卓开发数据存储主要分为两种形式,一种是永久存储,一种是临时存储。
永久存储
- 本地数据库Room
- 网络
- SharedPreferences
- 文件存储数据
- SQLite数据库
- ContentProvider
临时存储
- ViewModel
- Bundle
- Intent
- Application
1.永久存储
1.1本地数据库Room
应用场景:一般用来存储结构化数据;因为存储在本地,从本地读取速度会慢于从内存读取;好处是如果数据需要按照某个字段排序,则可以直接利用数据库语句而不用自己重写comparator。
用法:建立数据库(单例),建立实体类,编写接口(Dao),调用。
数据库建立:
//entities注解中填写本数据库的实体类,并在下面返回dao
@Database(entities = {Keyword.class}, version = 1, exportSchema = false)
public abstract class MyDatabase extends RoomDatabase {
private static final String DB_NAME = "my_database.db";//数据库名称
private static MyDatabase instance;
//单例
public static synchronized MyDatabase getInstance(Context context) {
if (instance == null) {
instance = Room.databaseBuilder(
context.getApplicationContext(),
MyDatabase.class,
DB_NAME
).build();
}
return instance;
}
public abstract KeywordDao getKeywordDao();
}
编写实体类
@Entity(tableName = "keyword")
public class Keyword {
@PrimaryKey
@NonNull
@ColumnInfo(name = "_id")
public String _id;
@ColumnInfo(name = "type")
public int type;
@ColumnInfo(name = "sortStr")
public String sortStr;
@ColumnInfo(name = "name")
public String name;
@NonNull
public String get_id() {
return _id;
}
//此处省略其他属性的getter和setter
编写Dao接口
@Dao
public interface KeywordDao {
//冲突处理
@Insert(onConflict = REPLACE)
void insertKeywords(List<Keyword> keywordList);
@Query("select * from keyword")
DataSource.Factory<Integer, Keyword> getKeywordList();
@Query("select * from keyword where type = 0 order by sortStr")
DataSource.Factory<Integer, Keyword> getDiseaseList();
@Query("select * from keyword where type = 1 order by sortStr")
DataSource.Factory<Integer, Keyword> getMedicineList();
}
调用
private void insertKeywords(List<Keyword> keywords) {
Log.d(TAG, "insertKeywords: ");
//异步操作
AsyncTask.execute(() -> MyDatabase.getInstance(this).getKeywordDao().insertKeywords(keywords));
}
1.2 网络
没做过,我不会,但我知道有。
学会了再补。
1.3 sharedpreferences
应用场景:不想保存在本地数据库,数据量比较少,数据结构比较简单(例如基本数据类型),可以保存在sharedpreferences,本质是在本地建立一个xml文件以map的形式存储键值对。
使用:建立自定义sharedpreferences类,获取shp的editor进行保存即可。
要注意获取到editor进行编辑之后一定要及时apply()或commit()对editor修改的内容进行保存,这两种方法的区别在于:
apply()异步进行,commit()同步进行,一般使用apply()比较好,可以参照之前的笔记
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
public class UserInfoShp {
private static final String USER_NAME = "USER_NAME";
private static final String USER_PASSWORD = "USER_PASSWORD";
private static final String USER_TOKEN = "USER_TOKEN";
private static final String PREFERENCES_FILE = "PREFERENCES_FILE_USER";
public static String getUserName(Context context) {
return getUserPreference(context).getString(USER_NAME, "");
}
@SuppressLint("CommitPrefEdits")
public static void setUserName(Context context, String userName) {
getUserPreference(context).edit().putString(USER_NAME, userName).apply();
}
public static String getUserPassword(Context context) {
return getUserPreference(context).getString(USER_PASSWORD, "");
}
@SuppressLint("CommitPrefEdits")
public static void setUserPassword(Context context, String userPassword) {
getUserPreference(context).edit().putString(USER_PASSWORD, userPassword).apply();
}
public static String getUserToken(Context context) {
return getUserPreference(context).getString(USER_TOKEN, "");
}
@SuppressLint("CommitPrefEdits")
public static void setUserToken(Context context, String userToken) {
getUserPreference(context).edit().putString(USER_TOKEN, userToken).apply();
}
/**
*重点在这里,调用context的getSharedPreferences方法即可获取shp,第一个参数是shp对应的xml文件名,第二个参数是模式。
*/
private static SharedPreferences getUserPreference(Context context) {
return context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
}
}
对于方法context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE);
getSharedPreferences()
适用于需要建立多个shp文件的情况,这时可以在第一个参数为xml文件自由命名;如果只需要一个shp文件,且文件生命周期只存在于该活动,则可以调用该活动(activity)的getPreferences()
方法。
关于shp所能保存的数据类型
- 安卓官方提供的可以保存的数据类型包括以下几种
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-piAQv0HG-1636447253392)(F:\Notes\Typora\Pictures\image-20211109162957512.png)]
但有些情况下我们需要保存其他数据类型,例如ArrayList、Map等,安卓并没有提供相应方法,但我们也可以借助putString来实现相同的效果
-
保存arraylist类型
原理:保存数据:利用Gson工具将arraylist转换为json字符串,利用putString保存在shp;
取出数据:利用Gson工具将保存在shp的json字符串解析为所需实体类。
/** * 保存List */ public static <T> void setDataList(String tag, List<T> datalist, Context context) { if (null == datalist || datalist.size() <= 0) return; Gson gson = new Gson(); //转换成json数据,再保存 String strJson = gson.toJson(datalist); SharedPreferences.Editor editor = getKeywordPreference(context).edit(); editor.putString(tag, strJson); editor.apply(); } /** * 获取List */ public static <T> List<T> getDataList(Class<T> clazz, String tag, Context context) { List<T> datalist = new ArrayList<>(); String strJson = getKeywordPreference(context).getString(tag, null); if (null == strJson) { return datalist; } Gson gson = new Gson(); Type listType = com.google.gson.internal.$Gson$Types.newParameterizedTypeWithOwner(null, ArrayList.class, clazz); // datalist = gson.fromJson(strJson, new TypeToken<List<T>>() {}.getType()); //上面这行获取type的方法不提倡,因为在使用返回数据时会报"LinkedTreeMap can't be cast into 你想要的数据类型"错误,因为它的本质还是强制类型转换,解析出来的不是我们想要的数据类型而是LinkedTreeMap datalist = gson.fromJson(strJson, listType); return datalist; }
1.4 文件存储
待补充
1.5 SQLite数据库
待补充
1.6 ContentProvider
待补充
2.临时存储
2.1 viewmodel
应用场景:一般和LiveData结合使用,监听数据状态,响应数据的动态变化;生命周期伴随activity或fragment(一般为activity,方便activity的各个fragment间数据传递)。
使用:创建viewmodel类,在activity中创建对应实例即可。
创建viewmodel类,需要继承AndroidViewModel
public class LoginViewModel extends AndroidViewModel {
protected MutableLiveData<String> userNameLD = new MutableLiveData<>();
protected MutableLiveData<String> userPasswordLD = new MutableLiveData<>();
public LoginViewModel(@NonNull Application application) {
super(application);
}
public void login() {
//此处省略登录具体实现代码,知道用到了viewmodel里的属性就可以了
}
//一般不写属性的set方法,因为可以直接使用get方法获取到对象之后调用setValue直接对其赋值
public MutableLiveData<String> getUserNameLD() {
return userNameLD;
}
public MutableLiveData<String> getUserPasswordLD() {
return userPasswordLD;
}
}
创建实例对象
//activity onCreate
loginViewModel= new ViewModelProvider(requireActivity()).get(LoginViewModel.class);
生命周期介绍如图,官网介绍如下
ViewModel
对象存在的时间范围是获取ViewModel
时传递给ViewModelProvider
的Lifecycle
。ViewModel
将一直留在内存中,直到限定其存在时间范围的Lifecycle
永久消失:对于 activity,是在 activity 完成时;而对于 fragment,是在 fragment 分离时。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZU5lcEaI-1636447253394)(F:\Notes\Typora\Pictures\viewmodel-lifecycle.png)]
2.2 bundle
应用场景:安卓开发者官网介绍
如果系统销毁或重新创建界面控制器,则存储在其中的任何瞬态界面相关数据都会丢失。例如,应用可能会在它的某个 Activity 中包含用户列表。为配置更改重新创建 Activity 后,新 Activity 必须重新提取用户列表。对于简单的数据,Activity 可以使用
onSaveInstanceState()
方法从onCreate()
中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。例如当某个activity隐藏,又被销毁,而我们重新返回到此activity时若不做任何操作数据就会丢失,此时可以通过onSavedInstanceState()回调
代码如下
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
String tempData = "Something you just typed!";
outState.putString("tempData", tempData);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dialog);
if (savedInstanceState != null) {
String tempData = savedInstanceState.getString("tempData");
Log.d("SavedData", tempData);
}
}
2.3 intent
Android-Developer Intent和Intent过滤器
Intent
是一个消息传递对象,您可以用来从其他应用组件请求操作。尽管 Intent 可以通过多种方式促进组件之间的通信,但其基本用例主要包括以下三个:
- 启动 Activity
Activity
表示应用中的一个屏幕。通过将Intent
传递给startActivity()
,您可以启动新的Activity
实例。Intent
用于描述要启动的 Activity,并携带任何必要的数据。如果您希望在 Activity 完成后收到结果,请调用
startActivityForResult()
。在 Activity 的onActivityResult()
回调中,您的 Activity 将结果作为单独的Intent
对象接收。如需了解详细信息,请参阅 Activity 指南。
- 启动服务
Service
是一个不使用用户界面而在后台执行操作的组件。使用 Android 5.0(API 级别 21)及更高版本,您可以启动包含JobScheduler
的服务。如需了解有关JobScheduler
的详细信息,请参阅其API-reference documentation
。对于 Android 5.0(API 级别 21)之前的版本,您可以使用
Service
类的方法来启动服务。通过将Intent
传递给startService()
,您可以启动服务执行一次性操作(例如,下载文件)。Intent
用于描述要启动的服务,并携带任何必要的数据。如果服务旨在使用客户端-服务器接口,则通过将
Intent
传递给bindService()
,您可以从其他组件绑定到此服务。如需了解详细信息,请参阅服务指南。
- 传递广播
广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将
Intent
传递给sendBroadcast()
或sendOrderedBroadcast()
,您可以将广播传递给其他应用。本页的其余部分将说明 Intent 的工作方式及如何使用 Intent。对于相关信息,请参阅与其他应用交互和共享内容。
Intent 类型
Intent 分为两种类型:
- 显式 Intent:通过提供目标应用的软件包名称或完全限定的组件类名来指定可处理 Intent 的应用。通常,您会在自己的应用中使用显式 Intent 来启动组件,这是因为您知道要启动的 Activity 或服务的类名。例如,您可能会启动您应用内的新 Activity 以响应用户操作,或者启动服务以在后台下载文件。
- 隐式 Intent :不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理。例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
可以为activity间传递数据,例如:当A活动想要启动B活动时,可以调用B活动的startActivity静态方法,并传入所需参数。
public static void BActivity(Context context, int type) {
Intent intent = new Intent(context, BActivity.class);
intent.putExtra("type", type);
context.startActivity(intent);
}
2.4 application
应用场景:Android系统在运行每一个程序应用的时候,都会创建一个Application对象,用于存储与整个应用相关的公共变量。 一个Android应用只会生成一个Application对象,在不同的Activity中获取的Application对象是一样的,所以Application对象是一个单例**(SingleTon)**。 Application对象非常适合用于存储一些与整个应用相关数据,例如应用版本,应用登录账户,数据缓存等。 利用Application对象存储公共数据或数据传递 ,免去activity的频繁切换所需的凌乱数据传递。
使用:待补充。
本文转自 https://blog.csdn.net/qq_45436365/article/details/121231454,如有侵权,请联系删除。
标签:存储,String,安卓,永久,Intent,context,Activity,static,public 来源: https://www.cnblogs.com/godshadow/p/16477686.html