学习《第一行代码》(十一)

数据存储

1.文件存储

适用于存储简单的文本数据或者二进制数据,若想存复杂的文本数据需自行定义格式规范以便要用到数据时可将数据从文件中重新解析出来。
举例(与书中有所不同但大同小异):
①编写界面

<android.support.constraint.ConstraintLayout 
	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"
    tools:context=".FirstActivity">

    <Button
        android:id="@+id/read_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="60dp"
        android:layout_marginBottom="56dp"
        android:text="读取"
        app:layout_constraintBottom_toTopOf="@+id/read"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.95" />

    <TextView
        android:id="@+id/read"
        android:layout_width="180dp"
        android:layout_height="221dp"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="188dp"
        android:hint="读点啥"
        android:textSize="50sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.578"
        app:layout_constraintStart_toEndOf="@+id/write" />

    <EditText
        android:id="@+id/write"
        android:layout_width="180dp"
        android:layout_height="221dp"
        android:layout_marginStart="16dp"
        android:layout_marginBottom="188dp"
        android:hint="写点啥"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/write_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="60dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="60dp"
        android:text="写入"
        app:layout_constraintBottom_toTopOf="@+id/write"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="1.0" />
</android.support.constraint.ConstraintLayout>

②编写读写文件逻辑:

public class FirstActivity extends AppCompatActivity {

    private String write_data;
    private String read_data;

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

        final Button Write_button = (Button) findViewById(R.id.write_button);
        Button Read_button = (Button) findViewById(R.id.read_button);
        final EditText Write_text = (EditText) findViewById(R.id.write);
        final TextView Read_text = (TextView) findViewById(R.id.read);

        Write_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!Write_text.getText().toString().equals("")){
                    FileOutputStream out = null;
                    BufferedWriter writer = null;
                    try{
                        write_data = Write_text.getText().toString();
						/*
						 * "data"是保存的文件名,后面是模式
						 * MODE_PRIVATE(默认)--写入同名文件会覆盖原有数据
						 * MODE_APPEND--有文件则在末尾加数据,没有则创建文件再加数据
						 */
                        out = openFileOutput("data", Context.MODE_PRIVATE);
                        writer = new BufferedWriter(new OutputStreamWriter(out));
                        writer.write(write_data);
                        Toast.makeText(FirstActivity.this,"写入成功",Toast.LENGTH_SHORT).show();
                    }
                    catch (IOException e){
                        e.printStackTrace();
                    }
                    finally {
                        try{
                            if (writer != null) {
                                writer.close();
                            }
                        }
                        catch (IOException ex){
                            ex.printStackTrace();
                        }
                    }
                }
                else {
                    AlertDialog.Builder builder = new AlertDialog.Builder(FirstActivity.this);
                    builder.setTitle("警告");
                    builder.setMessage("写入数据为空");
                    builder.setCancelable(true);
                    builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    });
                    builder.show();
                }
            }
        });

        Read_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                FileInputStream in = null;
                BufferedReader reader = null;
                StringBuilder content = new StringBuilder();
                try {
	                //读取文件名为"data"中的内容
                    in = openFileInput("data");
                    reader = new BufferedReader(new InputStreamReader(in));
                    String line = "";
                    while((line = reader.readLine()) != null){
                        content.append(line);
                    }
                }
                catch (IOException e){
                    e.printStackTrace();
                }
                finally {
                    if(reader != null){
                        try{
                            reader.close();
                        }
                        catch (IOException ex){
                            ex.printStackTrace();
                        }
                    }
                }
                read_data = content.toString();
                Read_text.setText(read_data);
                Toast.makeText(FirstActivity.this,"读取成功",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

③效果:

为证明确实写入了虚拟机内存,我查看了虚拟机的内容(书中的查看方法在AS3.0+已经不行了)
(一)
View–>Tool Windows–>Device File Explorer
在这里插入图片描述
(二)
找到data文件夹,保存到电脑中
在这里插入图片描述
(三)
查看
在这里插入图片描述

2.SharedPreference存储

使用键值对的方式来存储数据。
有三种方法:

类名方法名参数备注
Context.getSharedPreferences
(String name,int mode)
指定文件名,指定操作模式(只有MODE_PRIVATE,与直接传入0效果相同)背后是用xml文件存放数据,文件存放在/data/data//shared_prefs目录下
Activity.getPreferences(int mode)指定操作模式文件名默认使用当前活动的类名,模式默认为0或MODE_PRIVATE,还可以使用MODE_APPEND、MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE
PreferenceManager.getDefaultSharedPreferences
(Context)
自动使用当前应用程序的包名作为前缀来命名SharedPreference文件

使用步骤:
①获得SharedPreferences对象
②获得SharedPreferences.Editor对象。
③通过SharedPreferences.Editor接口的putXxx()方法存放键-值对(其中Xxx表示不同的数据类型。如:字符串类型的value需要用putString()方法)。
④通过SharedPreferences.Editor接口的commit()方法保存键-值对(commit方法相当于数据库事务中的提交(commit)操作)。

举例(getSharedPreference()):

①编写按钮响应事件

Write_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                write_data = Write_text.getText().toString();
                SharedPreferences.Editor editor = getSharedPreferences
                												("data",MODE_PRIVATE).edit();
                editor.putString("input",write_data);
                editor.apply();
                Toast.makeText(FirstActivity.this,"写入成功",Toast.LENGTH_SHORT).show();
            }
        });

        Read_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SharedPreferences pref = getSharedPreferences("data",MODE_PRIVATE);
                read_data = pref.getString("input","");
                Read_text.setText(read_data);
                Toast.makeText(FirstActivity.this,"读取成功",Toast.LENGTH_SHORT).show();
            }
        });

效果:

Alt text

举例(getDefaultSharedPreferences()):

尝试编写简单的记住用户和记住密码功能
①添加两个CheckBox

<CheckBox
        android:id="@+id/rmUser"
        android:layout_width="120dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="72dp"
        android:layout_marginTop="8dp"
        android:text="记住用户"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/Sign_in" />
        
<CheckBox
        android:id="@+id/rmPass"
        android:layout_width="120dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="44dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:text="记住密码"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.309"
        app:layout_constraintStart_toEndOf="@+id/rmUser"
        app:layout_constraintTop_toBottomOf="@+id/Sign_in" />

②编写逻辑
要记住了用户才可以记住密码:

public class LoginActivity extends BaseActivity {

    private SharedPreferences pref;
    private SharedPreferences.Editor editor;
    private CheckBox rmUser;
    private CheckBox rmPass;

    private EditText User;
    private EditText Password;
    private Button Sign_in;

    @Override
    protected void onCreate(Bundle saveInstanceState){
        super.onCreate(saveInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_login);
        pref = PreferenceManager.getDefaultSharedPreferences(this);

        rmUser = (CheckBox) findViewById(R.id.rmUser);
        rmPass = (CheckBox) findViewById(R.id.rmPass);


        User = (EditText) findViewById(R.id.User);
        Password = (EditText) findViewById(R.id.Password);
        boolean isRmUser = pref.getBoolean("remember_user",false);
        boolean isRmPass = pref.getBoolean("remember_password",false);
        rmUser.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (rmUser.isChecked()){
                    rmPass.setClickable(true);
                    rmPass.setChecked(false);
                }
                else {
                    rmPass.setClickable(false);
                    rmPass.setChecked(false);
                }
            }
        });
        if(isRmUser){
            String Users = pref.getString("User","");
            User.setText(Users);
            rmUser.setChecked(true);
            if (isRmPass){
                String Passwords = pref.getString("Password","");
                Password.setText(Passwords);
                rmPass.setChecked(true);
            }
        }

        Sign_in = (Button) findViewById(R.id.Sign_in);
        Sign_in.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String account = User.getText().toString();
                String password = Password.getText().toString();
                if(account.equals("test")&&password.equals("12345678")){
                    editor = pref.edit();
                    if (rmUser.isChecked()){
                        editor.putBoolean("remember_user",true);
                        editor.putString("User",account);
                        if (rmPass.isChecked()){
                            editor.putBoolean("remember_password",true);
                            editor.putString("Password",password);
                        }
                        else{
                            editor.putBoolean("remember_password",false);
                            editor.remove("Password");
                        }
                    }
                    else {
                        editor.clear();
                        editor.putBoolean("remember_user",false);
                        editor.remove("User");
                    }
                    editor.apply();
                    editor.clear();
                    Intent intent = new Intent(LoginActivity.this,MainActivity.class);
                    intent.putExtra("data",account);
                    startActivity(intent);
                    User.setText("");
                    Password.setText("");
                    finish();
                }
                else {
                    Toast.makeText(LoginActivity.this,"用户名密码有误",
                    											Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
}

我是修改了书中例子,可能有些地方逻辑会不顺畅甚至是冗余了请见谅
③效果:

保存的数据(完全没加密):
在这里插入图片描述

3.数据库存储
SQLite数据库存储
(1)创建数据库

主要是借助SQLiteOpenHelper这个帮助类
①编写MyDatabaseHelper.java

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

import android.widget.Toast;

public class MyDatebaseHelper extends SQLiteOpenHelper {

    public static final String CREATE_BOOK = "create table book ("
            + "id integer primary key autoincrement,"
            + "author text,"
            + "price real,"
            + "pages integer,"
            + "name text )";
    private Context mContext;

    public MyDatebaseHelper(Context context, String name, 
    									SQLiteDatabase.CursorFactory factory, int verson){
        super(context,name,factory,verson);
        mContext = context;
    }

    @Override
    //创建
    public void onCreate(SQLiteDatabase db){
        db.execSQL(CREATE_BOOK);
        Toast.makeText(mContext,"生成数据库成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    //更新
    public void onUpgrade(SQLiteDatabase database, int oldverson,int newverson){
        database.execSQL("drop table if exists Book");
        onCreate(database);
    }
}

②添加一个按钮用于测试创建数据库

<Button
        android:id="@+id/create_DB"
        android:layout_width="match_parent"
        android:layout_height="81dp"
        android:layout_alignBottom="@+id/textView"
        android:layout_marginBottom="-364dp"
        android:text="创建数据库"
        />

③编写按钮响应事件

public class MainActivity extends BaseActivity {

    private MyDatebaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		
		......
		
        dbHelper = new MyDatebaseHelper(MainActivity.this,"BookStore.db",null,1);
        Button create_DB = (Button) findViewById(R.id.create_DB);
        create_DB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dbHelper.getWritableDatabase();
                Toast.makeText(MainActivity.this,dbHelper.getDatabaseName(),
                												Toast.LENGTH_SHORT).show();
            }
        });

		......
}

④效果(查看创建的数据库):
书上的方法感觉比较麻烦,搜索了一下发现Android Studio本身就有查看数据库的插件,下载
(在File --> Settings --> Plugins --> 搜索Database Navigator下载)即可

  • 1.先把数据库导出(通过Device File Explorer)
    在这里插入图片描述
  • 2.点击打开下载好的Database Navigator(在左侧有DB Browser)
    在这里插入图片描述
  • 3.把导出的数据库添加到Database Navigator中
    Alt text
    Alt text
    Alt text
    (其中android_metadata是每个数据库都有的,Book是刚刚通过代码创建的)
(2)升级数据库

①修改MyDatabaseHelper

public class MyDatebaseHelper extends SQLiteOpenHelper {

	......
	
    public static final String CREATE_CATEGORY = "create table Category ("
            + "id integer primary key autoincrement,"
            + "category_name text,"
            + "category_code integer)";
    private Context mContext;

	......
	
    @Override
    public void onCreate(SQLiteDatabase db){
        db.execSQL(CREATE_BOOK);
        db.execSQL(CREATE_CATEGORY);
        Toast.makeText(mContext,"生成数据库成功",Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onUpgrade(SQLiteDatabase database, int oldverson,int newverson){

        database.execSQL("drop table if exists Book");
        database.execSQL("drop table if exists Category");
        onCreate(database);
    }
}

②在主活动中修改版本,升级
如果verson相同的话不会执行onUpgrade(),数据库已经存在的话也不会再次执行onCreate()

public class MainActivity extends BaseActivity {

    private MyDatebaseHelper dbHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        ......
		//这里的"2"即为版本号,比之前的版本号大即可,因为这里设置的时候是int,所以只能为整数
        dbHelper = new MyDatebaseHelper(MainActivity.this,"BookStore.db",null,2);
        
        ......
        
}

③查看导出的数据库
在这里插入图片描述

(3)添加数据

对表中数据有四种操作——CRUD
在这里插入图片描述

操作方法参数
Create(创建/添加).insert(String table, String nullColumnHack, ContentValues values)①表名
②在未指定数据时自动赋值null
③要添加的值
Retrieve(查询)query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)①表名
②想要显示的字段
③条件
④selection的值
⑤分组
⑥分组条件
⑦排序
⑧分页
Update(更新).update(String table, ContentValues values, String whereClause, String[] whereArgs)①表名
②ContentValues对象:该对象存储方式为Key-value,Key表示表中的字段名称,value表示该字段对应的值
③查询条件,例如:_ID = ?
④第三个参数的值(用来替换的值)
Delete(删除)delete(String table, String whereClause, String[] whereArgs)①表名er
②删除条件例如:_ID = ?
③whereClause的值!

做着做着发现如果用上面说的插件来查看数据库,那么每次操作都要导出一次数据库很麻烦,于是又找了另一种较为方便的查看方式

  • 1.在app中的build.gradle中添加依赖
    implementation 'com.facebook.stetho:stetho:1.5.0'
  • 2.在活动启动后调用函数
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Stetho.initializeWithDefaults(this);
        setContentView(R.layout.activity_second);
        
        ......

}
  • 3.在浏览器地址栏中输入chrome://inspect/#devices(Chrome和猎豹浏览器都行)
  • 4.找到数据库查看即可

点inspect
Alt text
Alt text
即能查看

举例:
①Create
逻辑:插入两本书的书名、页数、价格,id自动递增

Button Insert = (Button) findViewById(R.id.Insert);
Insert.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase database = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("name","The Da Vinic Code");
        values.put("author","Dan Brown");
        values.put("pages",454);
        values.put("price",16.96);
        database.insert("Book",null,values);

        values.clear();
        values.put("name","The Lost Symbol");
        values.put("author","Dan Brown");
        values.put("pages",510);
        values.put("price",19.95);
        database.insert("Book",null,values);

        Toast.makeText(SecondActivity.this,"插入成功",Toast.LENGTH_SHORT).show();
            }
        });

效果(按两下插入):
Alt text

②更新
逻辑:把书名为"The Da Vinic Code"的价格更新为11.88

Button Updata = (Button) findViewById(R.id.Update);
Updata.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase database = dbHelper.getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put("price",11.88);
        database.update("Book",values,"name = ?",new String[]{"The Da Vinic Code"});
    }
});

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

③删除
逻辑:删除页数pages超过500的书的信息

Button Delete = (Button) findViewById(R.id.Delete);
Delete.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        SQLiteDatabase database = dbHelper.getWritableDatabase();
        database.delete("Book","pages > ?", new String[]{"500"});
    }
});

效果:
在这里插入图片描述
④查询
逻辑:查看Book库中的所有数据,在下面的TableLayout中显示
TableLayout:

<TableLayout
        android:layout_width="395dp"
        android:layout_height="253dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <TableRow
            android:layout_weight="4"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <TextView
                android:id="@+id/book_name"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="书名" />

            <TextView
                android:id="@+id/book_author"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:text="作者" />
            <TextView
                android:id="@+id/book_pages"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="页数" />
            <TextView
                android:id="@+id/book_price"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="价格" />
        </TableRow>
    </TableLayout>

活动:

public class SecondActivity extends AppCompatActivity {

    private MyDatebaseHelper dbHelper;
    String name = "书名";
    String author = "作者";
    String pages = "页数";
    String price = "价格";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Stetho.initializeWithDefaults(this);
        setContentView(R.layout.activity_second);

		......
		
        final TextView Bname = (TextView) findViewById(R.id.book_name);
        final TextView Bauthor = (TextView) findViewById(R.id.book_author);
        final TextView Bpages = (TextView) findViewById(R.id.book_pages);
        final TextView Bprice = (TextView) findViewById(R.id.book_price);

        Button Retrieve = (Button) findViewById(R.id.Retrieve);
        Retrieve.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                SQLiteDatabase database = dbHelper.getWritableDatabase();
                Cursor cursor = database.query("Book",null,null,null,null,null,null);
                for(cursor.moveToFirst();!cursor.isAfterLast();cursor.moveToNext()){
                    name = name + "\r\n" + cursor.getString(cursor.getColumnIndex("name"));
                    author = author + "\r\n" + cursor.getString(cursor.getColumnIndex("author"));
                    pages = pages + "\r\n" + cursor.getString(cursor.getColumnIndex("pages"));
                    price = price + "\r\n" + cursor.getString(cursor.getColumnIndex("price"));
                }
                Bname.setText(name);
                name = "书名";
                Bauthor.setText(author);
                author = "作者";
                Bpages.setText(pages);
                pages = "页数";
                Bprice.setText(price);
                price = "价格";
                cursor.close();
            }
        });
		
		......
}        

效果:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值