第九章 Android数据存储与I/O

目录

1 SharedPreferences

1.1 简介

1.2 存储的位置和格式

1.3 示例代码

2 Filter存储

2.1 打开应用数据文件的 I/O 流

2.2 读写SD卡上的文件

3 SQLite数据库

3.1 SQLiteDatabase简介

3.2 创建数据库和表

3.3  使用 SQL 语句操作数据库

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

3.4.1 插入数据

3.4.2 查询数据

3.4.3 更新数据

3.4.4 删除数据

3.5 事务

3.6 SQLiteOpenHelper 类

4 手势

4.1  手势检测

4.2 增加手势


1 SharedPreferences

1.1 简介

SharedPreferences 是 Android 系统中一个轻量级的存储类,主要是保存一些常用的配置比如:应用的配置属性,用户的数据(比如用户名,密码等)。这种方式适合存储少量的数据,它提供了很方便的接口方法。

SharedPreferences 的实现主要是通过使用 XML 文件来存储数据,每一个 SharedPreferences 对象对应一个文件。数据会按照键值对的方式存储在文件中。

1.2 存储的位置和格式

SharedPreferences 的数据存储在设备的内部存储空间,在以下的路径:

/data/data/<package name>/shared_prefs/<name>.xml

其中,<package name> 是你的应用的包名,<name> 是你在创建 SharedPreferences 实例时提供的名字。

SharedPreferences 的数据存储为 XML 格式,比如你存储了一个名为 "username" 的字符串 "User" 和一个名为 "age" 的整数 25,那么生成的 XML 文件可能是这样的:

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="username">User</string>
    <int name="age" value="25" />
</map>

请注意,由于这些文件存储在应用的内部存储空间,所以它们默认情况下只能被你的应用访问。如果你想要让其他应用也能访问这些数据,那么你可能需要使用其他的存储方案。

1.3 示例代码

存储数据的代码如下:

SharedPreferences sharedPreferences = getSharedPreferences("MyPreferences", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString("username", "User");
editor.putString("password", "123456");
editor.apply();

读取数据的代码如下:

SharedPreferences sharedPreferences = getSharedPreferences("MyPreferences", MODE_PRIVATE);
String username = sharedPreferences.getString("username", "");
String password = sharedPreferences.getString("password", "");

2 Filter存储

Android提供了两种文件存储方式,内部存储和外部存储。内部存储的文件默认只能被自己的应用访问,而外部存储的文件则可以被其他应用访问。

2.1 打开应用数据文件的 I/O 流

在Android中写入数据到文件的代码如下:

String filename = "myfile";
String fileContents = "Hello world!";
try (FileOutputStream fos = openFileOutput(filename, Context.MODE_PRIVATE)) {
    fos.write(fileContents.getBytes());
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

读取数据的代码如下:

String filename = "myfile";
try (FileInputStream fis = openFileInput(filename)) {
    InputStreamReader inputStreamReader = new InputStreamReader(fis, StandardCharsets.UTF_8);
    StringBuilder stringBuilder = new StringBuilder();
    try (BufferedReader reader = new BufferedReader(inputStreamReader)) {
        String line = reader.readLine();
        while (line != null) {
            stringBuilder.append(line).append('\n');
            line = reader.readLine();
        }
    } catch (IOException e) {
        // Error occurred when opening raw file for reading.
    } finally {
        String contents = stringBuilder.toString();
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

2.2 读写SD卡上的文件

首先,你需要在你的应用的 manifest 文件中添加读写 SD 卡的权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

然后,你可以使用以下的代码来读写 SD 卡上的文件:

写入数据的代码:

File sdcard = Environment.getExternalStorageDirectory();
File file = new File(sdcard, "myFile.txt");
try (FileOutputStream fos = new FileOutputStream(file)) {
    fos.write("Hello world!".getBytes());
}

读取数据的代码:

File sdcard = Environment.getExternalStorageDirectory();
File file = new File(sdcard, "myFile.txt");
try (FileInputStream fis = new FileInputStream(file)) {
    InputStreamReader inputStreamReader = new InputStreamReader(fis, StandardCharsets.UTF_8);
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader reader = new BufferedReader(inputStreamReader);
    String line = reader.readLine();
    while (line != null) {
        stringBuilder.append(line).append('\n');
        line = reader.readLine();
    }
    String contents = stringBuilder.toString();
}

请注意,在 Android 10(API 等级 29)及更高版本中,直接访问外部存储(如 SD 卡)的方式已经发生了变化,你需要使用 Storage Access Framework (SAF) 或者 MediaStore API 来读写外部存储上的文件。

3 SQLite数据库

3.1 SQLiteDatabase简介

SQLite 是一款轻型的数据库,是由 C 语言编写的,体积非常小,运行速度非常快。它占用资源极少,并且能够支持绝大多数的 SQL 语言标准,是一款非常出色的嵌入式数据库。Android 系统内置了 SQLite 数据库,开发者可以直接使用。

3.2 创建数据库和表

在 Android 中,我们通常会通过继承 SQLiteOpenHelper 类并重写 onCreate() 方法来创建数据库和表。下面是一个例子:

public class MySQLiteHelper extends SQLiteOpenHelper {

    public static final String DATABASE_NAME = "my_database.db";
    public static final String TABLE_NAME = "my_table";
    public static final String COLUMN_ID = "_id";
    public static final String COLUMN_NAME = "name";

    private static final int DATABASE_VERSION = 1;

    // Database creation sql statement
    private static final String DATABASE_CREATE = "create table "
            + TABLE_NAME + "(" + COLUMN_ID
            + " integer primary key autoincrement, " + COLUMN_NAME
            + " text not null);";

    public MySQLiteHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(DATABASE_CREATE);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
        onCreate(db);
    }
}

3.3  使用 SQL 语句操作数据库

Android 提供了 SQLiteDatabase 类来进行数据库操作,我们可以使用它提供的 execSQL() 方法来执行 SQL 语句。以下是插入一条数据的例子:

SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(MySQLiteHelper.COLUMN_NAME, "example");
long newRowId = db.insert(MySQLiteHelper.TABLE_NAME, null, values);

查询数据的例子:

String[] projection = {
    MySQLiteHelper.COLUMN_ID,
    MySQLiteHelper.COLUMN_NAME
};

String sortOrder = MySQLiteHelper.COLUMN_NAME + " DESC";

Cursor cursor = db.query(
    MySQLiteHelper.TABLE_NAME,  
    projection,               
    null,                    
    null,                   
    null,                  
    null,                  
    sortOrder              
);

List<String> itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
  long itemId = cursor.getLong(
      cursor.getColumnIndexOrThrow(MySQLiteHelper.COLUMN_ID));
  itemIds.add(itemId);
}
cursor.close();

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

对于SQLite数据库的操作,除了使用SQL语句之外,Android还提供了一些特定的方法来进行操作,这些方法更加方便和安全。以下是使用这些方法来插入、查询、更新和删除数据的例子:

3.4.1 插入数据

ContentValues values = new ContentValues();
values.put(MySQLiteHelper.COLUMN_NAME, "example");

SQLiteDatabase db = mySQLiteHelper.getWritableDatabase();
long newRowId = db.insert(MySQLiteHelper.TABLE_NAME, null, values);

insert()方法需要一个表名和一个ContentValues对象,这个对象包含了你要插入的数据。

3.4.2 查询数据

String[] projection = {
    MySQLiteHelper.COLUMN_ID,
    MySQLiteHelper.COLUMN_NAME
};

Cursor cursor = db.query(
    MySQLiteHelper.TABLE_NAME,   
    projection,                
    null,                  
    null,                  
    null,                  
    null,                 
    null                
);

List<String> itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
  long itemId = cursor.getLong(
      cursor.getColumnIndexOrThrow(MySQLiteHelper.COLUMN_ID));
  itemIds.add(itemId);
}
cursor.close();

query()方法需要一个表名和一个列名数组,返回一个 Cursor 对象,你可以通过这个对象来遍历查询结果。

3.4.3 更新数据

ContentValues values = new ContentValues();
values.put(MySQLiteHelper.COLUMN_NAME, "new_example");

String selection = MySQLiteHelper.COLUMN_NAME + " LIKE ?";
String[] selectionArgs = { "example" };

int count = db.update(
    MySQLiteHelper.TABLE_NAME,
    values,
    selection,
    selectionArgs);

update() 方法需要一个表名,一个 ContentValues 对象和一些用于定义 WHERE 子句的参数。

3.4.4 删除数据

String selection = MySQLiteHelper.COLUMN_NAME + " LIKE ?";
String[] selectionArgs = { "example" };

int deletedRows = db.delete(MySQLiteHelper.TABLE_NAME, selection, selectionArgs);

delete()方法需要一个表名和一些用于定义 WHERE 子句的参数。

这些特定的方法比直接使用SQL语句更安全,因为它们可以自动防止SQL注入攻击。同时,使用这些方法也更方便,因为你不需要手动拼接SQL语句。

3.5 事务

在操作数据库的过程中,如果涉及到多个操作,且这些操作需要作为一个整体来处理,那么就需要用到事务。 

在SQLite 中,可以通过beginTransaction()setTransactionSuccessful()endTransaction() 方法来开启、设置成功和结束一个事务。

db.beginTransaction();
try {
    db.execSQL("...");
    db.execSQL("...");
    db.setTransactionSuccessful();
} finally {
    db.endTransaction();
}

3.6 SQLiteOpenHelper 类

SQLiteOpenHelper 是一个辅助类,用来管理数据库的创建和版本管理。它提供了两个回调方法来实现这些功能:

  • onCreate(SQLiteDatabase db):这个方法会在数据库第一次被创建的时候调用,可以在这个方法中执行一些初始化操作,比如创建表,初始化数据等。
  • onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion):这个方法会在数据库需要升级的时候调用,可以在这个方法中进行数据库的升级操作。

这样的设计使得数据库的创建和版本管理变得更加简单。

4 手势

在 Android 中,你可以使用 Gesture Detector 类来识别用户的各种手势。同时,你也可以通过 Gesture Library 来保存和识别用户定义的手势。

4.1  手势检测

你可以使用 GestureDetector 类来检测各种手势,如单击、双击、滑动等。以下是一个简单的例子:

public class MyActivity extends Activity implements GestureDetector.OnGestureListener {

    private GestureDetector gestureDetector;

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

        gestureDetector = new GestureDetector(this, this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    @Override
    public boolean onDown(MotionEvent event) {
        // 用户按下屏幕时触发
        return false;
    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) {
        // 用户在屏幕上“滑动”时触发
        return false;
    }

    // 其他的回调方法...
}

你需要在 onTouchEvent() 方法中调用 GestureDetectoronTouchEvent() 方法,然后根据需要重写 onDown()onFling() 等方法。

4.2 增加手势

要识别用户自定义的手势,你需要使用 GestureOverlayViewGestureLibrary。用户可以在 GestureOverlayView 上绘制手势,然后你可以把这个手势保存到 GestureLibrary,以便以后识别。

以下是一个简单的例子:

public class MyActivity extends Activity {

    private GestureLibrary gestureLib;

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

        GestureOverlayView gestures = findViewById(R.id.gestureOverlayView);
        gestures.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() {
            @Override
            public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
                // 当用户在 GestureOverlayView 上绘制手势时,将这个手势保存到 GestureLibrary
                gestureLib.addGesture("myGesture", gesture);
                gestureLib.save();
            }
        });

        gestureLib = GestureLibraries.fromRawResource(this, R.raw.gestures);
        if (!gestureLib.load()) {
            finish();
        }
    }
}

在这个例子中,当用户在 GestureOverlayView 上绘制手势时,这个手势会被保存到 GestureLibrary。然后你可以调用 GestureLibraryrecognize() 方法来识别这个手势。

猜你喜欢

转载自blog.csdn.net/m0_52537869/article/details/131235711