Android之数据存储

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fu_17791654327/article/details/79999640

使用SharedPreferences

SharedPreferences与Editor

  • SharedPreferences保存的数据主要是类似于配置信息格式的数据,即简单类型的key-value对。
  • SharedPreferences接口主要负责读取应用程序的Preferences数据,它提供了如下常用方法来访问SharedPreferences中的key-value对:
    • boolean contains(String key):判断SharedPreferences是否包含特定key的数据
    • abstract Map getAll():获取SharedPreferences数据里全部的key-value对
    • boolean getXxx(String key, Xxx defValue):获取SharedPreferences里指定的key对应的value,如果key不存在,则返回默认值的defValue,其中Xxx是boolean、float、int、long、String等各种基本类型的值。
  • SharedPreferences接口本身并没有提供写入数据的能力,而是通过SharedPreferences的内部接口,SharedPreferences调用edit()方法即可获取他所对应的Editor对象。Editor对象提供了如下方法来向SharedPreferences写入数据:
    • SharedPreferences.Editor clear():清空SharedPreferences中的数据。
    • SharedPreferences.Editor putXxx(String key , Xxx value):向SharedPreferences存入指定key对应的数据,其中Xxx是boolean、float、int、long、String等各种基本类型数据。
    • SharedPreferences.Editor remove(String key):删除SharedPreferences里指定的key对应的数据项。
    • boolean commit():当Editor编辑完成后,调用该方法提交修改。
  • SharedPreferences本身是一个接口,程序无法直接创建SharedPreferences实例,只能通过下述三种方法来获取SharedPreferences对象:
    • Context类的getSharedPreferences(String name , int mode)方法:name—-指定SharedPreferences文件名,mode—-文件操作模式(Context.MODE_PRIVATE:只能被本应用程序读写;Context.MODE_WORLD_READABLE:能被其它应用读,但不能写;Context.MODE_WORLD_WRITEABLE:能被其它应用读写)。
    • Activity类的getPreferences(int mode)方法:参数与Context的mode值相同,SharedPreferences文件名默认为当前活动。
    • PreferencesManager类中的getDefaultSharedPreferences(Context context)静态方法获取,SharedPreferences文件名为当前应用程序的报名前缀作为SharedPreferences文件名。

SharedPreferences的存储位置和格式

  • 示例1:
    private void initView() {
        // 获取只能被本应用读写的SharedPreferences对象
        sharedPreferences = getSharedPreferences("default_sp",MODE_PRIVATE);
        editor = sharedPreferences.edit();
    }
    public void write(View resource){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日" + " hh:mm:ss " );
        // 存入当前时间
        editor.putString("time",sdf.format(new Date()));
        // 存入一个随机数
        editor.putInt("random", (int) (Math.random() * 100));
        // 提交所有存入的数据
        editor.commit();
    }
    public void read(View resource){
        // 读取字符串数据
        String time = sharedPreferences.getString("time",null );
        // 读取int型数据
        int randNum = sharedPreferences.getInt("random",0);
        String result = time == null ? "你暂时还未写入数据" : "写入时间为:" + time + "  \n 上次生成的随机数为 : " + randNum ;
        ToastUtils.showLong(this,result);
        LogUtils.e(result);

    }
  • 示例2:
    // 记录app被使用次数
    private void initViewCount() {
        sharedPreferences = getSharedPreferences("count",MODE_PRIVATE);
        editor = sharedPreferences.edit();
        int count = sharedPreferences.getInt("count",0);
        ToastUtils.showLong(this,"程序以前被使用了 " + count + " 次!");
        LogUtils.e("程序以前被使用了 " + count + " 次!");
        editor.putInt("count",++count);
        editor.commit();
    }

File存储

openFileOutput和openFileInput

  • Context提供了如下两种方法来打开应用程序的数据文件夹里的文件IO流:
    • FileInputStream openFileInput(String name):打开应用程序的数据文件夹下的name文件对应的输入流。
    • FileOutputStream openFileOutput(String name, int mode):打开应用程序的数据文件夹下的name文件对应的输出流(mode参数值—-MODE_PRIVATE:只能被本应用程序读写;MODE_APPEND:以追加方式打开该文件,应用程序可以向该文件追加内容;MODE_WORLD_READABLE:该文件内容能被其它应用读取,但不能写;MODE_WORLD_WRITEABLE:能被其它应用读写)。
  • Context还提供了如下几个方法访问应用程序的数据文件夹:
    • getDir(String name, int mode):在应用程序文件夹下获取或创建name对应的子目录
    • File getFilesDir():获取应用程序的数据文件夹的绝对路径
    • String[] fileList():返回应用程序的数据文件夹下的全部文件
    • deleteFile(String name):删除应用程序的数据文件夹下的指定文件
  • 示例:
            case R.id.btn_atvt_share_preferences_one:
                // 将输入的文字内容写入文件中
                try {
                    // 以追加方式打开文件输出流
                    FileOutputStream fos = openFileOutput("default_sp.bin", MODE_APPEND);
                    // 将FileOutputStream包装成PrintStream
                    PrintStream ps = new PrintStream(fos);
                    // 输出文件内容
                    ps.println(etAtvtSharePreferencesOne.getText().toString());
                    // 关闭文件输出流
                    ps.close();
                    etAtvtSharePreferencesOne.setText("");

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
                break;
            case R.id.btn_atvt_share_preferences_two:
                try {
                    // 打开文件输入流
                    FileInputStream fis = openFileInput("default_sp.bin");
                    byte[] buff = new byte[1024];
                    int hasRead = 0;
                    StringBuilder sb = new StringBuilder("");

                    // 读取文件内容
                    while ((hasRead = fis.read(buff)) > 0) {
                        sb.append(new String(buff, 0, hasRead));
                    }
                    // 关闭文件输入流
                    fis.close();
                    etAtvtSharePreferencesTwo.setText(sb.toString());

                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;

读写SD卡上面的文件

  • 示例1:
            case R.id.btn_atvt_share_preferences_three:
                try {
                    // 如果手机插入了SD卡,且应用具有SD卡访问权限
                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                        // 获取SD卡对应的存储目录
                        File sdCardDir = Environment.getExternalStorageDirectory();
                        File targetFile = new File(sdCardDir.getCanonicalPath() + "/default_sp.bin");
                        // 以指定文件创建 RandomAccessFile对象
                        RandomAccessFile raf = new RandomAccessFile(targetFile,"rw");
                        // 将文件记录指针移动到最后
                        raf.seek(targetFile.length());
                        // 输出文件内容
                        raf.write(etAtvtSharePreferencesThree.getText().toString().getBytes());
                        // 关闭RandomAccessFile
                        raf.close();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
            case R.id.btn_atvt_share_preferences_four:

                try {
                    // 如果手机插入了SD卡,且应用具有SD卡访问权限
                    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                        // 获取SD卡对应的存储目录
                        File sdCardDir = Environment.getExternalStorageDirectory();
                        // 获取指定文件对应的输入流
                        FileInputStream fis = new FileInputStream(sdCardDir.getCanonicalPath() + "/default_sp.bin");
                        // 将指定的输入流包装成BufferedReader
                        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
                        StringBuilder sb = new StringBuilder("");
                        String line = null;

                        // 读取文件内容
                        while ((line = br.readLine()) != null) {
                            sb.append(line);
                        }
                        // 关闭文件输入流
                        br.close();
                        etAtvtSharePreferencesFour.setText(sb.toString());
                        etAtvtSharePreferencesThree.setText("");
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
                break;
  • 示例2:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <View
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_25" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/path"
            android:layout_width="match_parent"
            android:layout_height="45dp"
            android:layout_alignParentTop="true"
            android:gravity="center"
            android:text="显示当前路径的文本框" />

        <ListView
            android:id="@+id/list"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/path"
            android:divider="#000"
            android:dividerHeight="1px" />

        <Button
            android:id="@+id/parent"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dp_45"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:text="返回上一级" />

    </RelativeLayout>
</LinearLayout>
package com.fpp.status.activity.eight.four;

import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;

import com.fpp.status.R;
import com.fpp.status.utils.LogUtils;
import com.fpp.status.utils.ToastUtils;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author fupengpeng
 * @description 描述
 * @data 2018/4/19 0019 9:33
 */

public class SharePreferencesExampleActivity extends AppCompatActivity {


    @BindView(R.id.path)
    TextView path;
    @BindView(R.id.list)
    ListView list;
    @BindView(R.id.parent)
    Button parent;
    private SharedPreferences sharedPreferences;
    private SharedPreferences.Editor editor;

    // 记录当前的父文件夹
    File currentParent;
    // 记录当前路径下的所有文件的文件数组
    File[] currentFiles;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_preferences_example);
        ButterKnife.bind(this);

        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        initView();
        initViewCount();

    }


    private void initViewCount() {
        sharedPreferences = getSharedPreferences("count", MODE_PRIVATE);
        editor = sharedPreferences.edit();
        int count = sharedPreferences.getInt("count", 0);
        ToastUtils.showLong(this, "程序以前被使用了 " + count + " 次!");
        LogUtils.e("程序以前被使用了 " + count + " 次!");
        editor.putInt("count", ++count);
        editor.commit();
    }

    private void initView() {
        // 获取系统的sd卡目录
        File root = new File("/mnt/sdcard");
        // 如果sd卡存在
        if (root.exists()){
            currentParent = root;
            currentFiles = root.listFiles();
            // 使用当前目录下的全部文件、文件夹来填充ListView
            inflateListView(currentFiles);
        }
        // 为listview列表项单击事件添加监听器
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                // 用户单击了文件,直接返回,不作任何处理
                if (currentFiles[position].isFile()){
                    return;
                }
                // 获取用户单击的文件夹下所有文件
                File[] tmp = currentFiles[position].listFiles();
                if (tmp == null || tmp.length == 0){
                    ToastUtils.showLong(SharePreferencesExampleActivity.this,"当前路径不可访问或该路径下没有文件");
                    LogUtils.e("当前路径不可访问或该路径下没有文件");
                }else {
                    // 获取用户单击的列表项对应的文件夹,设为当前的父文件夹
                    currentParent = currentFiles[position];
                    // 保存当前父文件夹内的全部文件和文件夹
                    currentFiles = tmp;
                    // 再次刷新listview
                    inflateListView(currentFiles);
                }

            }
        });

    }

    private void inflateListView(File[] files) {
        // 创建一个List 集合 ,List 集合的元素是Map
        List<Map<String,Object>> listItems = new ArrayList<Map<String, Object>>();
        for (int i = 0; i < files.length; i++) {
            Map<String,Object> listItem = new HashMap<String, Object>();
            // 如果当前File是文件夹,使用folder图标,否则使用file图标
            if (files[i].isDirectory()){
                listItem.put("icon",R.drawable.shilipic);
            }else {
                listItem.put("icon",R.drawable.meinv02);
            }
            listItem.put("fileName",files[i].getName());
            // 添加List项
            listItems.add(listItem);
        }

        // 创建一个SimpleAdapter对象
        SimpleAdapter simpleAdapter = new SimpleAdapter(this,listItems,R.layout.line,new String[]{"icon","fileName"},
                new int[]{R.id.icon,R.id.file_name});

        // 为listview设置Adapter
        list.setAdapter(simpleAdapter);


        try {
            path.setText("当前路径为:" + currentParent.getCanonicalPath());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    @OnClick({R.id.path, R.id.parent})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.path:

                try {
                    if (!currentParent.getCanonicalPath().equals("/mnt/sdcard")){
                        // 获取上一级目录
                        currentParent = currentParent.getParentFile();
                        // 列出当前目录下的所有文件
                        currentFiles = currentParent.listFiles();
                        // 再次更新listview
                        inflateListView(currentFiles);

                    }
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            case R.id.parent:
                break;
        }
    }
}

SQLite数据库

SQLiteDatabase简介

  • SQLite是一个嵌入式数据库引擎,专门适用于资源有限的设备(手机、平板等)上的适量数据存储。支持SQL绝大部分语法,但是却不需要像Oracle、MySql一样安装、启动服务器进程。SQLite数据库只是一个文件。
  • Android提供了SQLiteDatabase代表一个数据库(底层就是一个数据库文件),一旦应用程序获得了代表指定数据库的SQLiteDatabase对象,接下来就可以通过SQLiteDatabase对象来管理和操作数据库了。
  • SQLiteDatabase提供了如下静态方法来打开一个文件对应的数据库:
    • static SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags):打开path文件所代表的SQLite数据库。
    • static SQLiteDatabase openOrCreateDatabase(File file,SQLiteDatabase.CursorFactory factory):打开或创建(如果不存在)file文件所代表的SQLite数据库。
    • static SQLiteDatabase openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory):打开或创建(如果不存在)path文件所代表的SQLite数据库。
  • 在程序中获取到SQLiteDatabase对象后,可以调用SQLiteDatabase的如下方法来进行操作数据库:
    • execSQL(String sql, Object[] bindArgs):执行带占位符的SQL语句
    • execSQL(String sql):执行SQL语句
    • insert(String table, String nullcolumnHack, ContentValues values):向指定表中插入数据
    • updata(String table,ContentValues values, String whereClause, String[] whereArgs):更新指定表中特定数据
    • delete(String table, String whereClause, String[] whereArgs):删除指定表中特定数据
    • Cursor query(String table, String[] columns, String whereClause, String[] whereArgs, String groupBy, String having, String orderBy):对指定数据表执行查询
    • Cursor query(String table, String[] columns, String whereClause, String[] whereArgs, String groupBy, String having, String orderBy, String limit):对指定数据表执行查询,limit参数控制最多查询几条记录(用于控制分页的参数)
    • Cursor query(boolean distinct, String table, String[] columns, String whereClause, String[] whereArgs, String groupBy, String having, String orderBy, String limit):对指定表执行数据查询,其中第一个参数控制是否去除重复值
    • rawQuery(String sql, String[] selectionArgs):执行带占位符的SQL查询
    • beginTransaction():开启事务
    • endTransaction():结束事务
  • SQLiteDatabase的作用类似于JDBC的Connection接口。上述查询方法都返回了一个Cursor对象,Android中的Cursor对象类似于JDBC的ResultSet对象。Cursor提供了如下方法来移动查询结果的记录指针:
    • move(int offset):将记录指针向上或向下移动指定的行数,正数向上,负数向下
    • boolean moveToFirst():将记录指针移动到第一行,成功返回true
    • boolean moveToLast():将记录指针移动到最后一行,成功返回true
    • boolean moveToNext():将记录指针移动到下一行,成功返回true
    • boolean moveToPosition(int position):将记录指针移动到position行,成功返回true
    • boolean moveToPrevious():将记录指针移动到上一行,成功返回true
  • 将记录指针移动到指定行后,通过掉用Curson对象的getXxx()方法获取该行的指定列数据。

创建数据库和表

  • 创建数据库:如果目标路径下有temp.db3文件(数据库文件),则打开,如果没有,则创建。
        SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase("/mnt/db/temp.dp3",null);
        // 当未指定SQLiteDatabase.CursorFactory参数时,则使用默认工厂
  • 创建SQLiteDatabase对象之后,可以使用execSQL()方法执行任意SQL语句。
        // 定义建表语句
        String sql = "create table user_inf(user_id integer primary key , user_name varchar(255) , user_pass varchar(255))";
        // 执行SQL语句
        db.execSQL(sql);

使用SQL语句操作SQLite

  • 使用SQLiteDatabase进行数据库操作的步骤如下:
    1. 获取SQLiteDatabase对象,它代表了与数据库的连接。
    2. 调用SQLiteDatabase的方法来执行SQL语句。
    3. 操作SQL语句的执行结果,例如使用SimpleCursorAdapter封装Cursor。
    4. 关闭SQLiteDatabase,回收资源。
package com.fpp.status.activity.eight.four;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

import com.fpp.status.R;
import com.fpp.status.utils.LogUtils;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author fupengpeng
 * @description 描述
 * @data 2018/4/19 0019 9:33
 */

public class SQLiteActivity extends AppCompatActivity {

    SQLiteDatabase db;
    @BindView(R.id.et_atvt_sqlite_one)
    EditText etAtvtSqliteOne;
    @BindView(R.id.et_atvt_sqlite_two)
    EditText etAtvtSqliteTwo;
    @BindView(R.id.btn_atvt_sqlite_one)
    Button btnAtvtSqliteOne;
    @BindView(R.id.lv_atvt_sqlite)
    ListView lvAtvtSqlite;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);
        ButterKnife.bind(this);

        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        initView();

    }

    private void initView() {
        // 创建或者打开数据库
        db = SQLiteDatabase.openOrCreateDatabase(this.getFilesDir().toString() + "/my.dp3", null);
        LogUtils.e("数据库路径 = " + this.getFilesDir().toString());
        // 当未指定SQLiteDatabase.CursorFactory参数时,则使用默认工厂

    }

    /**/
    @OnClick({R.id.et_atvt_sqlite_two, R.id.btn_atvt_sqlite_one})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.et_atvt_sqlite_two:
                break;
            case R.id.btn_atvt_sqlite_one:
                // 获取用户输入数据
                String title = etAtvtSqliteOne.getText().toString();
                String content = etAtvtSqliteTwo.getText().toString();

                try {
                    insertData(db, title, content);
                    String selectSql = "select * from news_inf";
                    Cursor cursor = db.rawQuery(selectSql, null);
                    inflateList(cursor);
                } catch (SQLiteException e) {
                    // 执行DDL创建数据库表
                    String createSql = "create table news_inf(_id integer primary key autoincrement," +
                            "news_title varchar(255)," +
                            "news_content varchar(255))";
                    db.execSQL(createSql);
                    // 执行insert语句插入数据
                    insertData(db, title, content);
                    // 执行查询
                    String selectSql = "select * from news_inf";
                    Cursor cursor = db.rawQuery(selectSql, null);
                    inflateList(cursor);
                }
                break;
        }
    }

    private void inflateList(Cursor cursor) {
        // 填充SimpleCursorAdapter
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(SQLiteActivity.this,
                R.layout.line, cursor,
                new String[]{"news_title", "news_content"},
                new int[]{R.id.tv_lvi_title, R.id.file_name},
                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
        // 显示数据
        lvAtvtSqlite.setAdapter(adapter);
    }

    private void insertData(SQLiteDatabase db, String title, String content) {
        // 执行插入语句
        String insertSql = "insert into news_inf values(null,?,?)";
        db.execSQL(insertSql, new String[]{title, content});
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 退出程序时,关闭SQLiteDatabase
        if (db != null && db.isOpen()) {
            db.close();
        }
    }
}

使用sqlite3工具

使用特定方法操作SQLite数据库

  • 使用insert方法插入记录
    • SQLiteDatabase的insert方法的签名为 long insert(String table, String nullColumnHack, ContentValues values)(table:想插入数据的表名;nullColumnHack:强行插入null值的数据列的列名,当values参数为null或不包含任何key-value对时该参数有效;value:一行记录的数据)。
    • insert方法插入的一行记录使用ContentValues存放,ContentValues类似于Map,它提供了put(String key, Xxx value)(其中key为数据列的列名)方法用于存入数据,getAsXxx(String key)方法用于取出数据。
    • 使用insert方法插入数据时,不管第三个参数是否包含数据,执行insert()方法都会添加一条记录,如果第三个参数为空,则会添加一个除主键之外其它字段值都为空的记录。
    • SQLite的insert()方法底层实际上依然是通过构造insert SQL语句来进行插入的,因此它也会生成类似SQL的插入语句。当第三个参数为空时,此时插入语句的列名就由第二个参数来指定了。
  • 插入示例:
        ContentValues values = new ContentValues();
        values.put("name","张三");
        values.put("age",500);
        // 返回新添记录的行号,该行号是一个内部值,与主键id无关,发生错误返回-1
        long rowid = db.insert("person_inf",null,values);
  • 使用update方法更新记录
    • SQLiteDatabase的update方法的签名为updata(String table,ContentValues values, String whereClause, String[] whereArgs)( table:想更新数据的表名;values:想更新的数据;whereClause:满足该whereClause子句的记录将会被更新; whereArgs:用于为whereClause子句传入参数。)
    • update方法返回值是受此update语句影响的记录条数。
  • 更新示例:
        values = new ContentValues();
        // 存放更新后的人名
        values.put("name","李四");
        int updateResult = db.update("person_inf",values,"_id > ?", new String[]{"20"});
  • 使用delete方法删除记录
    • SQLiteDatabase的delete方法的签名为delete(String table, String whereClause, String[] whereArgs)(table:想删除数据的表名;whereClause:满足该whereClause子句传入参数; whereArgs:用于为whereClause子句传入参数;)
    • delete方法返回值是受此delete语句影响的记录条数。
  • 删除示例:
        int deleteResult = db.delete("person_inf","person_name like ? ",new String[]{"张"});
  • 使用query方法查询记录
    • SQLiteDatabase的query方法的签名为Cursor query(boolean distinct, String table, String[] columns, String whereClause, String[] whereArgs, String groupBy, String having, String orderBy, String limit)(distinct:是否去除重复记录;table:执行查询数据的表名;columns:要查询出来的列名,相当于select语句的select关键字后面的部分; whereClause:查询条件子句,相当于select语句的where关键字后面的部分,在条件子句中允许使用”?”; whereArgs:用于为whereClause子句中的占位符传入参数值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常; groupBy:用于控制分组,相当于select语句的group by关键字后面的部分; having:用于对分组进行过滤,相当于select语句的having关键字后面的部分; orderBy:用于对记录进行排序,相当于select语句的order by关键字后面的部分; limit:用于进行分页,相当于select语句的limit关键字后面的部分。)
  • 查询示例:
        Cursor cursor = db.query("person_inf ",new String[]{" _id,name,age "}," name like ? ",
                new String[]{" 张% "},null,null, " personid desc ", " 5,10 ");
        // 处理结果集
        cursor.close();

事务

  • SQLiteDatabase中包含两种方法来控制事务:
    • beginTransaction():开启事务
    • endTransaction():结束事务
  • SQLiteDatabase还提供了下述方法来判断当前上下文是否处于事务环境中。
    • inTransaction():如果当前上下文处于事务中,返回true,否则返回false。
  • 当程序执行endTransaction()方法时将会结束事务—-那到底是提交事物还是回滚事务呢?这取决于SQLiteDatabase是否调用了setTransactionSuccessful()方法来设置事务标志,如果程序事务执行中调用了该方法设置了事务成功,则提交事务,否则程序将会回滚事务。
  • 示例:
        // 开始事务
        db.beginTransaction();
        try{
            // 执行 DML 语句

            // 调用该方法设置事务成功,否则endTransaction()方法回滚事务
            db.endTransaction();
        }finally {
            // 由事务的标志决定是提交事务还是回滚事务
            db.endTransaction();
        }

SQLiteOpenHelper类

  • SQLiteOpenHelper是Android提供的一个管理数据库的工具类,可用于管理数据库的创建和更新。一般用法是创建SQLiteOpenHelper的子类,并扩展它的onCreate(SQLiteDatabase db) 和 onUpgrade(SQLiteDatabase db , int oldVersion , int newVersion)方法。
  • SQLiteOpenHelper包含下述常用方法:
    • synchronized SQLiteDatabase getReadableDatabase():以读写的方式打开数据库对应的SQLiteDatabase对象。
    • synchronized SQLiteDatabase getWritableDatabase():以写的方式打开数据库对应的SQLiteDatabase对象。
    • abstract void onCreate(SQLiteDatabase db):当第一次创建数0据库时回调该方法。
    • abstract void onUpgrade(SQLiteDatabase db , int oldVersion , int newVersion ):当数据库版本更新时回调该方法。
    • synchronized void close():关闭所有打开的SQLiteDatabase对象。
  • 上述五个方法中提供了打开数据库和关闭数据库的方法,使用时只需要重写它的两个抽象方法:
    • abstract void onCreate(SQLiteDatabase db):用于初次使用软件时生成数据库表。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于操作数据库的SQLiteDatabase实例时,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用。重写onCreate()方法时,可以生成数据库表结构,以添加应用使用到的一些初始化数据。
    • abstract void onUpgrade(SQLiteDatabase db , int oldVersion , int newVersion ):用于升级软件时更新数据库表结构,此方法在数据库的版本发生变化时会被调用。参数二、三分别是之前数据库版本号和当前数据库版本号。在程序创建SQLiteOpenHelper对象时,必须指定一个version参数,该参数就决定了所使用的数据库版本。只要某次创建SQLiteOpenHelper对象时指定的数据库版本号高于之前指定的版本号,系统就会自动触发onUpgrade(SQLiteDatabase db , int oldVersion , int newVersion )方法,程序就可以在该方法里面根据原版本号和目标版本号进行判断,再根据相应的版本号进行必须的表结构更新。
  • 注意事项:当以getWritableDatabase()方法打开数据库时,一旦数据库的磁盘空间满了,数据库就只能读不能写,倘若使用getWritableDatabase()打开数据库就会出错。而使用getReadableDatabase()方法打开数据库时,如果数据库的磁盘空间满了,就会打开失败,打开失败后会继续尝试以只读的方式打开数据库。
  • 示例:
package com.fpp.status.activity.eight.four;

import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.fpp.status.R;
import com.fpp.status.utils.ToastUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author fupengpeng
 * @description 描述
 * @data 2018/4/19 0019 9:33
 */

public class SQLiteExampleActivity extends AppCompatActivity {

    DatabaseHelper dbHelper;
    @BindView(R.id.et_atvt_sqlite_example_one)
    EditText etAtvtSqliteExampleOne;
    @BindView(R.id.et_atvt_sqlite_example_two)
    EditText etAtvtSqliteExampleTwo;
    @BindView(R.id.btn_atvt_sqlite_example_one)
    Button btnAtvtSqliteExampleOne;
    @BindView(R.id.et_atvt_sqlite_example_three)
    EditText etAtvtSqliteExampleThree;
    @BindView(R.id.btn_atvt_sqlite_example_two)
    Button btnAtvtSqliteExampleTwo;

    private ContentValues values;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite_example);
        ButterKnife.bind(this);

        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        initView();

    }

    private void initView() {
        // 创建DatabaseHelper对象,指定数据库版本为1,此处使用相对路径即可
        // 数据库文件会自动保存在程序的数据文件夹的database目录下。
        dbHelper = new DatabaseHelper(this, "muDict.db3", null, 1);

    }

    private void insertData(SQLiteDatabase db, String word, String detail) {
        // 执行插入语句
        String insertSql = "insert into dict values(null,?,?)";
        db.execSQL(insertSql, new String[]{word, detail});
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 退出程序时,关闭DatabaseHelper里面的SQLiteDatabase
        if (dbHelper != null) {
            dbHelper.close();
        }
    }

    @OnClick({R.id.btn_atvt_sqlite_example_one, R.id.btn_atvt_sqlite_example_two})
    public void onViewClicked(View view) {
        switch (view.getId()) {
            case R.id.btn_atvt_sqlite_example_one:
                // 获取用户输入数据
                String title = etAtvtSqliteExampleOne.getText().toString();
                String content = etAtvtSqliteExampleTwo.getText().toString();


                // 获取用户输入
                String word = etAtvtSqliteExampleOne.getText().toString();
                String detail = etAtvtSqliteExampleTwo.getText().toString();
                // 插入生词记录
                insertData(dbHelper.getReadableDatabase(), word, detail);
                // 显示提示信息
                ToastUtils.showLong(this, "添加生词成功!");

                break;
            case R.id.btn_atvt_sqlite_example_two:
                // 获取用户输入
                String key = etAtvtSqliteExampleThree.getText().toString();
                // 执行查询
                Cursor cursor = dbHelper.getReadableDatabase().rawQuery("select * from dict where word like ? or detail like ? ",
                        new String[]{"%" + key + "%", "%" + key + "%"});
                // 创建一个Bundle对象
                Bundle data = new Bundle();
                data.putSerializable("data", converCursorToList(cursor));
                // 创建一个Intent
                Intent intent = new Intent(SQLiteExampleActivity.this, ResultActivity.class);
                intent.putExtras(data);
                startActivity(intent);

                break;
        }
    }

    private ArrayList<Map<String, String>> converCursorToList(Cursor cursor) {
        ArrayList<Map<String, String>> result = new ArrayList<Map<String, String>>();
        // 遍历 Cursor 结果集
        while (cursor.moveToNext()) {
            // 将结果集中的数据存入
            Map<String, String> map = new HashMap<String, String>();
            // 取出查询记录中第2列,第3列的值
            map.put("word", cursor.getString(1));
            map.put("detail", cursor.getString(2));
            result.add(map);
        }
        return result;
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="@dimen/dp_23"
    android:orientation="vertical">

    <EditText
        android:id="@+id/et_atvt_sqlite_example_one"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_45"
        android:hint="输入数据" />

    <EditText
        android:id="@+id/et_atvt_sqlite_example_two"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_45"
        android:hint="输入数据" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_45"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_atvt_sqlite_example_one"
            android:layout_width="0dp"
            android:layout_height="@dimen/dp_45"
            android:layout_weight="1"
            android:text="添加生词" />

    </LinearLayout>

    <EditText
        android:id="@+id/et_atvt_sqlite_example_three"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="输入查找关键字" />

    <Button
        android:id="@+id/btn_atvt_sqlite_example_two"
        android:layout_width="match_parent"
        android:layout_height="@dimen/dp_45"
        android:text="查找" />
</LinearLayout>
package com.fpp.status.activity.eight.four;

import android.content.Intent;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ListView;
import android.widget.SimpleAdapter;

import com.fpp.status.R;

import java.util.List;
import java.util.Map;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * @author fupengpeng
 * @description 描述
 * @data 2018/4/20 0020 14:18
 */

public class ResultActivity extends AppCompatActivity {

    @BindView(R.id.lv_atvt_result)
    ListView lvAtvtResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_result);
        ButterKnife.bind(this);

        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        initView();

    }

    private void initView() {
        Intent intent = getIntent();
        Bundle data = intent.getExtras();
        List<Map<String, String>> list = (List<Map<String, String>>) data.getSerializable("data");
        SimpleAdapter adapter = new SimpleAdapter(ResultActivity.this, list,
                R.layout.line, new String[]{"word", "detail"},
                new int[]{R.id.tv_lvi_title, R.id.file_name});
        lvAtvtResult.setAdapter(adapter);
    }

}

手势(Gesture)

手势检测

  • Android为手势检测提供了一个GestureDetector类,它代表了一个手势检测器,创建时需要传入一个GestureDetector.OnGestureListener实例,GestureDetector.OnGestureListener是一个监听器,负责对用户手势行为提供响应。
  • GestureDetector.OnGestureListener包含的事件处理方法如下:
    • boolean onDown(MotionEvent e):当触碰事件按下时触发该方法。
    • boolean onFling(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):当用户手指在屏幕上”拖过”时触发该方法。其中distanceX、distanceY代表”拖过”动作在横向、竖向上的速度。
    • abstract void onLongPress(MotionEvent e):当用户手指在屏幕上长按时触发该方法。
    • boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY):当用户手指在屏幕上”滚动”时触发该方法
    • void onShowPress(MotionEvent e):当用户手指在触摸屏上按下,而且还未移动和松开时触发该方法。
    • boolean onSingleTapUp(MotionEvent e):当用户手指在屏幕上的轻击事件将会触发该方法。
  • 使用Android的手势检测只需要两个步骤:
    1. 创建一个GestureDetector对象,创建该对象时必须实现一个GestureDetector.OnGestureListener监听器实例。
    2. 为应用程序的Activity(偶尔也可以为特定组件)的TouchEvent事件绑定监听器,在事件处理中指定把Activity(或特定组件)上的TouchEvent事件交给GestureDetector处理。
  • 示例:
package com.fpp.status.activity.eight.four;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

import com.fpp.status.R;
import com.fpp.status.utils.LogUtils;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * @author fupengpeng
 * @description
 * @date 2018/4/20 0020 16:07
 */

public class GestureTwoActivity extends AppCompatActivity {

    // 定义手势检测器
    GestureDetector detector;
    @BindView(R.id.iv_atvt_gesture_two)
    ImageView ivAtvtGestureTwo;

    // 初始的图片资源
    Bitmap bitmap;
    // 定义图片的宽高
    int width,height;
    // 记录当前缩放比
    float currentScale = 1;
    // 控制图片缩放的Matrix对象
    Matrix matrix;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gesture_two);
        ButterKnife.bind(this);

        if (Build.VERSION.SDK_INT >= 21) {
            View decorView = getWindow().getDecorView();
            int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
            decorView.setSystemUiVisibility(option);
            getWindow().setStatusBarColor(Color.TRANSPARENT);
        }

        initView();

    }

    private void initView() {
        // 创建手势检测器
        detector = new GestureDetector(this, onGestureListener);
        matrix = new Matrix();
        // 获取被缩放的源图片
        bitmap = BitmapFactory.decodeResource(this.getResources(),R.drawable.nvshengtouxiang);
        // 获得位图宽
        width = bitmap.getWidth();
        // 获得位图高
        height = bitmap.getHeight();
        // 设置ImageView初始化时显示的图片
        ivAtvtGestureTwo.setImageBitmap(BitmapFactory.decodeResource(this.getResources(),R.drawable.nvshengtouxiang));

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 将Activity上的触碰事件交给GestureDetector处理
        return detector.onTouchEvent(event);
    }

    GestureDetector.OnGestureListener onGestureListener = new GestureDetector.OnGestureListener() {
        @Override
        public boolean onDown(MotionEvent e) {
            LogUtils.e("----onDown----" + "  ----按下");
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            LogUtils.e("----onShowPress----" + "  ----按下未移动时");
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            LogUtils.e("----onSingleTapUp----" + "  ----点击事件");
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            LogUtils.e("----onScroll----" + "  ----拖动事件");
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            LogUtils.e("----onLongPress----" + "  ----长按事件");
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            LogUtils.e("----onFling----" + "  ----滚动事件----拖动之后有速度才会产生滚动");
            velocityX = velocityX > 4000 ? 4000 : velocityX ;
            velocityX = velocityX < -4000 ? -4000 : velocityX ;
            // 根据手势的速度来计算缩放比,如果velocityX > 0 ,则放大图片,否则缩小图片
            currentScale += currentScale * velocityX / 4000.0f;
            // 保证 currentScale 不回等于 0
            currentScale = currentScale > 0.01 ? currentScale : 0.01f ;
            // 重置Matrix
            matrix.reset();
            // 缩放Matrix
            matrix.setScale(currentScale,currentScale,160 , 200 );
            BitmapDrawable tmp = (BitmapDrawable) ivAtvtGestureTwo.getDrawable();
            // 如果图片还未回收,先强制回收该图片
            if (!tmp.getBitmap().isRecycled()){
                tmp.getBitmap().recycle();
            }
            // 根据原始位图和Matrix创建新图片
            Bitmap bitmap2 = Bitmap.createBitmap(bitmap,0,0,width,height,matrix,true);
            // 显示新的位图
            ivAtvtGestureTwo.setImageBitmap(bitmap2);

            return true;
        }
    };



}

增加手势

  • Android使用GestureLibrary来代表手势库,并提供了GestureLibraries工具类来创建手势库,GestureLibraries提供了如下四个静态方法来从不同位置加载手势库:
    • static GestureLibrary fromFile(String path):从path代表的文件中加载手势库。
    • static GestureLibrary fromFile(File path):从path代表的文件中加载手势库。
    • static GestureLibrary fromPrivateFile(Context context , String name):从指定应用程序的数据文件夹的name文件中加载手势库。
    • static GestureLibrary fromRawResource(Context context , int resourceId):从resourceId所代表的资源中加载手势库。
  • 在程序中获得了GestureLibrary对象之后,该对象提供了如下方法来添加手势、识别手势:
    • void addGesture(String entryName, Gesture gesture):添加一个名为entryName的手势。

识别用户手势

猜你喜欢

转载自blog.csdn.net/fu_17791654327/article/details/79999640