Android-数据存储

一、SharedPreferences

  • SharedPreferences是Android的一个轻量级存储工具,采用的存储结构是Key-value的键值对方式。
    共享参数的存储介质是符合XMK规范的配置文件。保存路径是:/data/data/应用包名/shared_prefs/文件名.xml。

使用场景:
简单且孤立的数据。若是复杂且相互间有关的数据,则要保存再数据库中。
文本形式的数据。若是二进制数据,则要保存在文件中。
需要持久化存储的数据。在App推出后再次启动时,之前保存的数据仍然有效。

实际开发中,共享参数经常存储的数据有App的个性化配置信息、用户使用App的行为信息、临时需要保存的片段信息等。
实战:
在这里插入图片描述
布局:
layout/activity_share_write.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ShareWriteActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="姓名:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入姓名" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="年龄:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入年龄" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="身高:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入身高" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="体重:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_weight"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入体重" />
    </LinearLayout>

    <CheckBox
        android:id="@+id/cb_married"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="已婚" />

    <Button
        android:id="@+id/btn_save"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存到共享参数"
        />

</LinearLayout>

相关选择器:
drawable-v24/editext_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:drawable="@drawable/shape_edit_focus"/>
    <item android:drawable="@drawable/shape_edit_normal"/>
</selector>

drawable-v24/shape_edit_focus.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<!--    指定形状内部的填充颜色-->
    <solid android:color="#ffffff" />
<!--    指定形状轮廓的粗细与颜色-->
    <stroke android:width="1dp"
        android:color="#0000ff" />
<!--    指定了形状四个圆角的半径-->
    <corners android:radius="5dp" />
<!--    指定形状四个方向的间距-->
    <padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp"/>
</shape>

drawable-v24/shape_edit_normal.xml

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

<!--    指定形状内部的填充颜色-->
    <solid android:color="#ffffff" />
<!--    指定形状轮廓的粗细与颜色-->
    <stroke android:width="1dp"
        android:color="#aaaaaa" />
<!--    指定了形状四个圆角的半径-->
    <corners android:radius="5dp" />
<!--    指定形状四个方向的间距-->
    <padding android:bottom="2dp" android:left="2dp" android:right="2dp" android:top="2dp"/>

</shape>

业务代码:

public class ShareWriteActivity extends AppCompatActivity implements View.OnClickListener {

    private EditText et_name;
    private EditText et_age;
    private EditText et_height;
    private EditText et_weight;
    private CheckBox cb_married;
    private Button btn_save;
    private SharedPreferences sharedPreferences;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_write);

        et_name = findViewById(R.id.et_name);
        et_age = findViewById(R.id.et_age);
        et_height = findViewById(R.id.et_height);
        et_weight = findViewById(R.id.et_weight);
        btn_save = findViewById(R.id.btn_save);
        cb_married = findViewById(R.id.cb_married);

        btn_save.setOnClickListener(this);
        // config 为文件名,MODE_PRIVATE 私有模式
        sharedPreferences = getSharedPreferences("config", Context.MODE_PRIVATE);

        // 推出程序后(结束),重新进入读取数据
       reload();
    }

    private void reload() {
        String name = sharedPreferences.getString("name", null);
        if (name != null) {
            et_name.setText(name);
        }

        int age = sharedPreferences.getInt("age", 0);
        if (age != 0) {
            et_age.setText(String.valueOf(age));
        }

        float height = sharedPreferences.getFloat("height", 0f);
        if(height != 0f) {
            et_height.setText(String.valueOf(height));
        }

        float weight = sharedPreferences.getFloat("weight", 0f);
        if (weight != 0f) {
            et_weight.setText(String.valueOf(weight));
        }

        boolean married = sharedPreferences.getBoolean("married", false);
        cb_married.setChecked(married);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_save:
                String name = et_name.getText().toString();
                String age = et_age.getText().toString();
                String height = et_height.getText().toString();
                String weight = et_weight.getText().toString();
                SharedPreferences.Editor edit = sharedPreferences.edit();
                edit.putString("name", name);
                edit.putInt("age", Integer.parseInt(age));
                edit.putFloat("height", Float.parseFloat(height));
                edit.putFloat("weight", Float.parseFloat(weight));
                edit.putBoolean("married", cb_married.isChecked());
                edit.commit();
                break;
        }
    }
}

效果展示:
在这里插入图片描述

二、数据库SQLite

数据库管理器SQLiteDatabase
SQLiteDatabase 是SQLite的数据库管理类,它提供了若干操作数据表的API,常用方法有3类:
1、管理类,用于数据库层面的操作
openDatabase:打开指定路径的数据库
isOpen:判断数据库是否已打开。
close:关闭数据库。
getVersion:获取数据库的版本号。
setVersion:设置数据库的版本号。

2、事务类
beginTransaction:开始事务
setTransactionSuccessful: 设置事务的成功标志
endTransaction: 结束事务

3、数据处理类,用于数据表层面的操作
execSQL:执行数据表层面的操作
delete: 删除符合条件的记录
update: 更新符合条件的记录
insert: 插入一条记录
query: 执行查询操作,返回结果集的游标
rawQuery: 执行拼接好的SQL查询语句,返回结果集的游标

数据库操作
布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".DatabaseActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:layout_marginTop="5dp"
        >

        <Button
            android:id="@+id/btn_create_database"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="创建数据库"
            />
        <Button
            android:id="@+id/btn_drop_database"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="删除数据库"
            />

    </LinearLayout>

    <TextView
        android:id="@+id/tv_show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

</LinearLayout>

业务代码:

public class DatabaseActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn_create_database;
    private Button btn_drop_database;
    private TextView tv_show;
    private String mDatabaseName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_database);

        btn_create_database = findViewById(R.id.btn_create_database);
        btn_drop_database = findViewById(R.id.btn_drop_database);
        tv_show = findViewById(R.id.tv_show);

        btn_create_database.setOnClickListener(this);
        btn_drop_database.setOnClickListener(this);

        // 生成一个测试数据库的完整路径
        mDatabaseName = getFilesDir() + "/test.db";
    }

    @Override
    public void onClick(View v) {
        String desc = null;
        switch (v.getId()) {
            case R.id.btn_create_database:
                // 创建或者打开数据库。数据库如果不存在就创建它,如果存在就打开它
                SQLiteDatabase sqLiteDatabase = openOrCreateDatabase(mDatabaseName, Context.MODE_PRIVATE, null);
                desc = String.format("数据库%s创建%s", sqLiteDatabase.getPath(), (sqLiteDatabase != null) ? "成功" : "失败");
                tv_show.setText(desc);
                break;
            case R.id.btn_drop_database:
                // 删除数据库
                boolean result = deleteDatabase(mDatabaseName);
                desc = String.format("数据库%s创建%s", mDatabaseName, result ? "成功" : "失败");
                tv_show.setText(desc);
                break;
        }
    }
}

效果展示:
在这里插入图片描述
数据库帮助器SQLiteOpenHelper
是Android提供的数据库辅助工具,用于指导开发者进行SQLite的合理使用
SQLiteOpenHelper的具体使用步骤:

  • 新建一个继承自SQLiteOpenHelper的数据库操作类,提示重写onCreate和onUpgrade两个方法。
    封装保证数据库安全的必要方法。
    提供对表记录进行增加、删除、修改、擦汗寻的操作方法。

1、增删改查

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ShareWriteActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="姓名:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入姓名" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="年龄:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入年龄" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="身高:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入身高" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="体重:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_weight"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入体重" />
    </LinearLayout>

    <CheckBox
        android:id="@+id/cb_married"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="已婚" />

    <Button
        android:id="@+id/btn_add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="添 加"
        />
    <Button
        android:id="@+id/btn_delete"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="删 除"
        />
    <Button
        android:id="@+id/btn_update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="修 改"
        />
    <Button
        android:id="@+id/btn_query"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="查 询"
        />

</LinearLayout>

选择器:drawable-v24/editext_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:drawable="@drawable/shape_edit_focus"/>
    <item android:drawable="@drawable/shape_edit_normal"/>
</selector>

实体类:

public class User {

    private int id; // 序号
    private String name; // 姓名
    private int age; // 年龄
    private long height; // 身高
    private float weight; // 体重
    private boolean married; // 婚否

    public User() {
    }

    public User(String name, int age, long height, float weight, boolean married) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.weight = weight;
        this.married = married;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public long getHeight() {
        return height;
    }

    public void setHeight(long height) {
        this.height = height;
    }

    public float getWeight() {
        return weight;
    }

    public void setWeight(float weight) {
        this.weight = weight;
    }

    public boolean isMarried() {
        return married;
    }

    public void setMarried(boolean married) {
        this.married = married;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", height=" + height +
                ", weight=" + weight +
                ", married=" + married +
                '}';
    }
}

数据库帮助类:

package com.example.datesaved.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

import com.example.datesaved.bean.User;

import java.util.ArrayList;
import java.util.List;

/**
 * @author liuzhihao
 * @create 2023-03-11 0:09
 *
 *
 * 操作步骤:
 *      新建一个继承自SQLiteOpenHelper的数据库操作类,提示重写onCreate和onUpgrade两个方法。
 *      封装保证数据库安全的必要方法。
 *      提供对表记录进行增加、删除、修改、查询的操作方法。
 */
public class UserDBHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "user.db";
    private static final String TABLE_NAME = "user";
    private static final int DB_VERSION = 1;
    private static UserDBHelper mHelper = null;
    private SQLiteDatabase mRDB = null; // 读操作
    private SQLiteDatabase mWDB = null; // 写操作


    private UserDBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    // (懒汉式 线程不安全)利用单例模式获取数据库帮助器的唯一实例
    public static UserDBHelper getInstance(Context context) {
        if (mHelper == null) {
            mHelper = new UserDBHelper(context);
        }
        return mHelper;
    }

    // 打开数据库的读链接
    public SQLiteDatabase openReadLink() {
        if (mRDB == null || !mRDB.isOpen()) {
            mRDB = mHelper.getReadableDatabase();
        }
        return mRDB;
    }

    // 打开数据库的写链接
    public SQLiteDatabase openWriteLink() {
        if (mWDB == null || !mWDB.isOpen()) {
            mWDB = mHelper.getReadableDatabase();
        }
        return mWDB;
    }

    // 关闭数据库链接
    public void closeLink() {
        if (mRDB != null && mRDB.isOpen()) {
            mRDB.close();
            mRDB = null;
        }

        if (mWDB != null && mWDB.isOpen()) {
            mWDB.close();
            mWDB = null;
        }
    }

    public long insert(User user) {
        ContentValues values = new ContentValues(); // map
        values.put("name", user.getName());
        values.put("age", user.getAge());
        values.put("height", user.getHeight());
        values.put("weight", user.getWeight());
        values.put("married", user.isMarried());
        // 执行插入记录,该语句返回插入记录的行号
        // 第二个参数的作用:
        // 如果第三个参数values为null或者元素个数为0,由于insert()方法要求必须添加一条除了主键之外其他字段为null值的记录,
        // 为了满足SQL语法的需要,insert语句必须给定一个字段名,如:insert into person(name) values (NULL),
        // 如果不给顶字段名,insert语句就成了这样:insert into person() values(),显然这不满足标准SQL的语法,
        // 如果第三个参数values不为null并且元素的个数大于0,可以把第二个参数设置为null
        return mWDB.insert(TABLE_NAME, null, values);
    }

    public long deleteByName(String name) {
        // 删除所有
//        mWDB.delete(TABLE_NAME, "1 = 1", null);
        return mWDB.delete(TABLE_NAME, "name = ?", new String[]{name});
    }

    public long update(User user) {
        ContentValues values = new ContentValues();
        values.put("name", user.getName());
        values.put("age", user.getAge());
        values.put("height", user.getHeight());
        values.put("weight", user.getWeight());
        values.put("married", user.isMarried());
        return mWDB.update(TABLE_NAME, values, "name = ?", new String[]{user.getName()});
    }

    public List<User> queryAll() {
        List<User> list = new ArrayList<>();
        // 返回一个游标:一行一行读取每一行的记录
        Cursor cursor = mRDB.query(TABLE_NAME, null, null, null, null, null, null);
        while (cursor.moveToNext()) {
            User user = new User();
            user.setName(cursor.getString(1));
            user.setAge(cursor.getInt(2));
            user.setHeight(cursor.getLong(3));
            user.setWeight(cursor.getFloat(4));
            // SQL没有布尔型,用0表示false,用1表示true
            user.setMarried(cursor.getInt(5) != 0);
            list.add(user);
        }
        return list;
    }
    
    public List<User> queryByName(String name) {
        List<User> list = new ArrayList<>();
        Cursor cursor = mRDB.query(TABLE_NAME, null, "name = ?", new String[]{name}, null, null, null);
        while (cursor.moveToNext()) {
            User user = new User();
            user.setName(cursor.getString(1));
            user.setAge(cursor.getInt(2));
            user.setHeight(cursor.getLong(3));
            user.setWeight(cursor.getFloat(4));
            user.setMarried(cursor.getInt(5) != 0);
            list.add(user);
        }
        return list;
    }

    /**
     * 创建数据库,执行建表语句
     * @param db
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
                " _id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                " name VARCHAR NOT NULL," +
                " age INTEGER NOT NULL," +
                " height LONG NOT NULL," +
                " weight FLOAT NOT NULL," +
                " married INTEGER NOT NULL);";
        db.execSQL(sql);
    }

    // 数据库版本更新
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }


}

工具类:

package com.example.datesaved.utils;

import android.content.Context;
import android.widget.Toast;

/**
 * @author liuzhihao
 * @create 2023-03-12 0:16
 */
public class ToastUtil {
    public static void show(Context context, String desc) {
        Toast.makeText(context, desc, Toast.LENGTH_SHORT).show();
    }
}

业务代码:

package com.example.datesaved;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

import com.example.datesaved.bean.User;
import com.example.datesaved.database.UserDBHelper;
import com.example.datesaved.utils.ToastUtil;

import java.util.List;

public class SQLiteHelperActivity extends AppCompatActivity implements View.OnClickListener, View.OnFocusChangeListener {

    private static final String TAG = "liuzhihao";

    private Button btn_add;
    private Button btn_delete;
    private Button btn_update;
    private Button btn_query;
    private EditText et_name;
    private EditText et_age;
    private EditText et_height;
    private EditText et_weight;
    private CheckBox cb_married;
    private UserDBHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite_helper);

        btn_add = findViewById(R.id.btn_add);
        btn_delete = findViewById(R.id.btn_delete);
        btn_update = findViewById(R.id.btn_update);
        btn_query = findViewById(R.id.btn_query);
        et_name = findViewById(R.id.et_name);
        et_age = findViewById(R.id.et_age);
        et_height = findViewById(R.id.et_height);
        et_weight = findViewById(R.id.et_weight);
        cb_married = findViewById(R.id.cb_married);

        btn_add.setOnClickListener(this);
        btn_delete.setOnClickListener(this);
        btn_update.setOnClickListener(this);
        btn_query.setOnClickListener(this);

        // 焦点变更
        et_name.setOnFocusChangeListener(this);
        et_age.setOnFocusChangeListener(this);
        et_height.setOnFocusChangeListener(this);
        et_weight.setOnFocusChangeListener(this);

        // 文本内容变更
        et_name.addTextChangedListener(new SelfWatcher());
        et_age.addTextChangedListener(new SelfWatcher());
        et_height.addTextChangedListener(new SelfWatcher());
        et_weight.addTextChangedListener(new SelfWatcher());

    }

    @Override
    protected void onStart() {
        super.onStart();
        // 获得数据库帮助器的实例
        dbHelper = UserDBHelper.getInstance(this);
        // 打开数据库帮助器的读写连接
        dbHelper.openWriteLink();
        dbHelper.openReadLink();
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 关闭数据库连接
        dbHelper.closeLink();
    }

    @Override
    public void onClick(View v) {
        String name = et_name.getText().toString();
        String age = et_age.getText().toString();
        String height = et_height.getText().toString();
        String weight = et_weight.getText().toString();
        User user = null;
        switch (v.getId()) {
            case R.id.btn_add:
                if(TextUtils.isEmpty(age) || TextUtils.isEmpty(height) || TextUtils.isEmpty(weight)) {
                    ToastUtil.show(this, "年龄/身高/体重不能为空");
                    return;
                }
                user = new User(name, Integer.parseInt(age), Long.parseLong(height), Float.parseFloat(weight), cb_married.isChecked());
                if (dbHelper.insert(user) > 0) {
                    ToastUtil.show(this, "添加成功");
                }
                break;
            case R.id.btn_delete:
                if (dbHelper.deleteByName(name) > 0) {
                    ToastUtil.show(this, "删除成功");
                }
                break;
            case R.id.btn_update:
                user = new User(name, Integer.parseInt(age), Long.parseLong(height), Float.parseFloat(weight), cb_married.isChecked());
                if (dbHelper.update(user) > 0) {
                    ToastUtil.show(this, "修改成功");
                }
                break;
            case R.id.btn_query:
//                List<User> users = dbHelper.queryAll();
                List<User> users = dbHelper.queryByName(name);
                for (User u : users) {
                    Log.d(TAG, "name : " + u.getName());
                    Log.d(TAG, "age : " + u.getAge());
                    Log.d(TAG, "height : " + u.getHeight());
                    Log.d(TAG, "weight : " + u.getWeight());
                    Log.d(TAG, "isMarried : " + (u.isMarried() ? "已婚" : "未婚"));
                }
                break;
        }
    }

    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            String name = et_name.getText().toString();
            if (TextUtils.isEmpty(name)) {
                et_name.requestFocus();
                ToastUtil.show(this, "请输入正确的姓名");
            }
        }
    }

    private class SelfWatcher implements TextWatcher {
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        @Override
        public void afterTextChanged(Editable s) {

        }
    }
   }

2、事务管理

  public long insert(User user) {
        ContentValues values = new ContentValues(); // map
        values.put("name", user.getName());
        values.put("age", user.getAge());
        values.put("height", user.getHeight());
        values.put("weight", user.getWeight());
        values.put("married", user.isMarried());
        // 执行插入记录,该语句返回插入记录的行号
        // 第二个参数的作用:
        // 如果第三个参数values为null或者元素个数为0,由于insert()方法要求必须添加一条除了主键之外其他字段为null值的记录,
        // 为了满足SQL语法的需要,insert语句必须给定一个字段名,如:insert into person(name) values (NULL),
        // 如果不给顶字段名,insert语句就成了这样:insert into person() values(),显然这不满足标准SQL的语法,
        // 如果第三个参数values不为null并且元素的个数大于0,可以把第二个参数设置为null

        // 事务操作
//        beginTransaction:开始事务
//        setTransactionSuccessful: 设置事务的成功标志
//        endTransaction: 结束事务
        try {
            mWDB.beginTransaction();
            mWDB.insert(TABLE_NAME, null, values);
            // 异常
            int i = 10 / 0;
            mWDB.insert(TABLE_NAME, null, values);
            mWDB.setTransactionSuccessful();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            mWDB.endTransaction();
        }

        return 1;

//        return mWDB.insert(TABLE_NAME, null, values);
    }

3、数据库版本升级

// 数据库版本更新时执行(下次会比较版本号,不相等则执行此方法)
// 比如:新增字段,修改表结构
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    String sql = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN phone VARCHAR;";
    db.execSQL(sql);
    sql = "ALTER TABLE " + TABLE_NAME + " ADD COLUMN password VARCHAR;";
    db.execSQL(sql);
}

三、存储卡文件操作

3.1 私有存储空间与公共存储空间 和 在存储卡上读写文本文件
Android把外部存储分成了两块区域,一块时所有应用均可访问的公共空间,另一块时只有应用自己才可访问的私有空间。
在这里插入图片描述
布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ShareWriteActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="姓名:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入姓名" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="年龄:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_age"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入年龄" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="身高:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入身高" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginStart="5dp"
            android:text="体重:"
            android:textSize="15sp" />

        <EditText
            android:id="@+id/et_weight"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="5dp"
            android:background="@drawable/editext_selector"
            android:hint="请输入体重" />
    </LinearLayout>

    <CheckBox
        android:id="@+id/cb_married"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="已婚" />

    <Button
        android:id="@+id/btn_save"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保 存"
        />

    <Button
        android:id="@+id/btn_read"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="读 取"
        />
    <TextView
        android:id="@+id/tv_txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

</LinearLayout>

选择器:
drawable-v24/editext_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:drawable="@drawable/shape_edit_focus"/>
    <item android:drawable="@drawable/shape_edit_normal"/>
</selector>

业务代码:

public class FileWriteActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "liuzhihao";
    private EditText et_name;
    private EditText et_age;
    private EditText et_height;
    private EditText et_weight;
    private CheckBox cb_married;
    private Button btn_save;
    private Button btn_read;
    private TextView tv_txt;
    private String path;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file_write);

        et_name = findViewById(R.id.et_name);
        et_age = findViewById(R.id.et_age);
        et_height = findViewById(R.id.et_height);
        et_weight = findViewById(R.id.et_weight);
        cb_married = findViewById(R.id.cb_married);
        btn_save = findViewById(R.id.btn_save);
        btn_read = findViewById(R.id.btn_read);
        tv_txt = findViewById(R.id.tv_txt);

        btn_save.setOnClickListener(this);
        btn_read.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_save:
                String name = et_name.getText().toString();
                String age = et_age.getText().toString();
                String height = et_height.getText().toString();
                String weight = et_weight.getText().toString();

                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.append("姓名:").append(name);
                stringBuilder.append("\n年龄:").append(age);
                stringBuilder.append("\n身高:").append(height);
                stringBuilder.append("\n体重:").append(weight);
                stringBuilder.append("\n婚否:").append(cb_married.isChecked() ? "是" : "否");

                String fileName = System.currentTimeMillis() + ".txt"; // 文件名称
                String directory = null;
                // 外部存储的私有空间
                directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString();///storage/emulated/0/Android/data/com.example.datesaved/files/Download/
                // 外部存储的公共空间
                directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).toString(); // 需要在manifests中加权限 /storage/emulated/0/Download
                // 内部存储私有空间
                directory = getFilesDir().toString();// /data/user/0/com.example.datesaved/files/

                path = directory + File.separatorChar + fileName; // File.separatorChar = "/";斜杠
                Log.d(TAG, "onClick_save: path = " + path);
                FileUtil.saveText(path, stringBuilder.toString());
                ToastUtil.show(this, "保存成功");
                break;
            case R.id.btn_read:
                tv_txt.setText(FileUtil.openText(path));
                break;
        }
    }
}

工具类:

public class ToastUtil {
    public static void show(Context context, String desc) {
        Toast.makeText(context, desc, Toast.LENGTH_SHORT).show();
    }
}
public class FileUtil {


    // 把字符串保存到指定路径的文本文件
    public static void saveText(String path, String txt) {
        BufferedWriter os = null;
        try {
            os = new BufferedWriter(new FileWriter(path));
            os.write(txt);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
  }

3.2 在存储卡上读写图片文件
Android的位图工具是Bitmap,App读写Bitmap可以使用性能更好的BufferedOutputStream和BufferedInputStream。
Android还提供了BitmapFactory工具用于读取各种来源的图片,相关方法如下:

  • decodeResource: 该方法可以从资源文件中读取图片信息。
  • decodeFile:该方法可将指定路径的图片读取到Bitmap对象。
  • decodeStream: 该方法从输入流中读取位图数据。

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ImageWriteActivity">

    <Button
        android:id="@+id/btn_saveimg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="保存图片"
        />
    <Button
        android:id="@+id/btn_readimg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取图片"
        />

    <ImageView
        android:id="@+id/iv_content"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:scaleType="fitCenter"
        />

</LinearLayout>

业务代码:

public class ImageWriteActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = "liuzhihao";
    private Button btn_saveimg;
    private Button btn_readimg;
    private ImageView iv_content;
    private String directory;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_image_write);

        btn_saveimg = findViewById(R.id.btn_saveimg);
        btn_readimg = findViewById(R.id.btn_readimg);
        iv_content = findViewById(R.id.iv_content);

        btn_saveimg.setOnClickListener(this);
        btn_readimg.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_saveimg:
                String filename = System.currentTimeMillis() + ".jpeg";
                // 获取当前app的私有下载目录
                directory = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString() + File.separatorChar + filename;
                Log.d(TAG, "directory : " + directory);
                // 从指定资源文件中获取位图对象
                Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.libai);
                // 把位图对象保存为图片文件
                FileUtil.saveImage(directory, bitmap);
                ToastUtil.show(this, "保存图片成功");
                break;
            case R.id.btn_readimg:
                // 第一种方式
                if (directory != null) {
                    Bitmap image = FileUtil.openImage(directory);
                    iv_content.setImageBitmap(image);
                }
                // 第二种方式
//                Bitmap image = BitmapFactory.decodeFile(directory);
//                iv_content.setImageBitmap(image);

                // 第三种方式:直接调用setImageURI方法,设置图像视图的路径对象
//                iv_content.setImageURI(Uri.parse(directory));
                break;
        }
    }
}

工具类:

public class FileUtil {


    // 把字符串保存到指定路径的文本文件
    public static void saveText(String path, String txt) {
        BufferedWriter os = null;
        try {
            os = new BufferedWriter(new FileWriter(path));
            os.write(txt);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // 从指定路径的文本文件中读取内容字符串
    public static String openText(String path) {
        BufferedReader is = null;
        StringBuilder stringBuilder = new StringBuilder();
        try {
            is = new BufferedReader(new FileReader(path));
            String line = null;
            while ((line = is.readLine()) != null) {
                stringBuilder.append(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return stringBuilder.toString();
    }

    // 把位图数据保存到指定路径
    public static void saveImage(String directory, Bitmap bitmap) {
        FileOutputStream fileOutputStream = null;
        try {
            fileOutputStream = new FileOutputStream(directory);
            // 把位图数据压缩到文件输出流中
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    // 从指定路径的图片我呢见中读取位图数据
    public static Bitmap openImage(String directory) {
        Bitmap bitmap = null;
        FileInputStream fileInputStream = null;
        Log.d("liuzhihao", "openImage: directory = " + directory);
        try {
            fileInputStream = new FileInputStream(directory);
            bitmap = BitmapFactory.decodeStream(fileInputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return bitmap;
    }
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值