Android系統的五種數據存儲形式(一)

来源:http://www.cnblogs.com/huangjie123/archive/2016/10/14/5962389.html
-Advertisement-
Play Games

Android系統下的基本數據存儲形式,文件存儲、sp存儲、資料庫存儲、網路存儲、Content Provider記憶體提供者 ...


      Android系統有五種數據存儲形式,分別是文件存儲、SP存儲、資料庫存儲、contentprovider 內容提供者、網路存儲。其中,前四個是本地存儲。存儲的類型包括簡單文本、視窗狀態存儲、音頻視頻數據、XML註冊文件的各種數據。各種存儲形式的特點不盡相同,因此對於不同的數據類型有著固定的存儲形式,本文為演示方便給出的案例基本相同,都是是採用賬號登錄來演示數據存儲,保存賬號和密碼信息,下次登錄時記住賬號和密碼。重在說明各種存儲形式的原理。

    文件存儲:

    以I/O流的形式把數據存入手機記憶體或SD卡,可以存儲大數據,如音樂、圖片或視頻等。對於手機記憶體來說系統會根據每個應用的包名創建一個/data/data/包名/的文件夾,訪問自己包名下的目錄是不需要許可權的,並且 Android 已經提供了非常簡便的 API 可以直接去訪問該文件夾。訪問時可以用getFilesDir()和getCacheDir(),兩個的區別是系統會自動清理後者中的內容。

    SD卡中的文件通常位於mnt/sdcard目錄下,不同生產商生產的手機這個路徑可能不同。操作sd卡的時通常要判斷下sd卡是否可用以及剩餘空間是否足夠,因為部分手機的SD卡可卸載,SD卡處於非掛載狀態時,無法進行讀寫操作。另外一點,對SD卡的讀取和寫入操作均需要相應的許可權,否則無法完成。獲取SD卡路徑的方法是Environment.getExternalStorageDirectory(),其餘操作與文件存儲基本類似。

   文件存儲位置:

                

 

     SD卡存儲路徑:

               

      數據存儲在手機記憶體的實現方法:

package com.example.qqload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;

import com.example.qqload_sp.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
    private EditText et_qq;
    private EditText et_password;
    private CheckBox cb_remenber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq = (EditText) findViewById(R.id.et_qq);
        et_password = (EditText) findViewById(R.id.et_password);
        cb_remenber = (CheckBox) findViewById(R.id.cb_remenber);
        File file = new File(getFilesDir(), "info.txt");
//        File file = new File(getCacheDir(), "info.txt");   緩存中存放數據
        if (file.exists() && file.length() > 0) {
            try {
                FileInputStream fis = new FileInputStream(file);
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        fis));
                String line = br.readLine();
                String qq = line.split("##")[0];
                String password = line.split("##")[1];
                et_qq.setText(qq);
                et_password.setText(password);
                fis.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void login(View view) {
        String qq = et_qq.getText().toString().trim();
        String password = et_password.getText().toString().trim();
        if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {
            Toast.makeText(this, "密碼或者用戶名不能為空", 0).show();
            return;
        }
        if (cb_remenber.isChecked()) {
            File file = new File(getFilesDir(), "info.txt");
            try {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write((qq + "##" + password).getBytes());
                fos.close();
                Toast.makeText(MainActivity.this, "保存成功", 0).show();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "保存失敗", 0).show();
                e.printStackTrace();
            }
        }
    }
}

        

        數據存儲在SD卡中的實現方法:     

package com.example.qqload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.text.Format;

import com.example.qqload_sp.R;

import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
    private EditText et_qq;
    private EditText et_password;
    private CheckBox cb_remenber;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq = (EditText) findViewById(R.id.et_qq);
        et_password = (EditText) findViewById(R.id.et_password);
        cb_remenber = (CheckBox) findViewById(R.id.cb_remenber);
        File file = new File(Environment.getExternalStorageDirectory(), "info.txt");
        if (file.exists() && file.length() > 0) {
            try {
                FileInputStream fis = new FileInputStream(file);
                BufferedReader br = new BufferedReader(new InputStreamReader(
                        fis));
                String line = br.readLine();
                String qq = line.split("##")[0];
                String password = line.split("##")[1];
                et_qq.setText(qq);
                et_password.setText(password);
                fis.close();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public void login(View view) {
        String qq = et_qq.getText().toString().trim();
        String password = et_password.getText().toString().trim();
        if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {
            Toast.makeText(this, "密碼或者用戶名不能為空", 0).show();
            return;
        }
        if (cb_remenber.isChecked()) {
            File file = new File(Environment.getExternalStorageDirectory(), "info.txt");
            //判斷SD卡是否掛載
            if(!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                Toast.makeText(MainActivity.this, "SD卡不可用", 0).show();
                return;
            }
            //判斷SD卡大小是否充足
            long size = Environment.getExternalStorageDirectory().getFreeSpace();
            String info = Formatter.formatFileSize(this, size);
            //此處存儲數據較小就不進行判斷
            Toast.makeText(this, "可用空間" + info, 0).show();
            
            try {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write((qq + "##" + password).getBytes());
                fos.close();
                Toast.makeText(MainActivity.this, "保存成功", 0).show();
            } catch (Exception e) {
                Toast.makeText(MainActivity.this, "保存失敗", 0).show();
                e.printStackTrace();
            }
        }
    }
}

 

     SP存儲:

     SP存儲本質上是一個XML文件,以鍵值對的形式存入手機記憶體中。常用於存儲簡單的參數設置,如登陸賬號密碼的存儲,視窗功能狀態的存儲等,該存儲文件位於:data/data/包名/shared_prefs文件夾中。使用的時候,首先需要通過context.getSharedPrefrences(String name,int mode)獲取SharedPrefrences的實例對象,存儲數據時,用SharedPrefrences的實例對象得到SharedPrefrences文件的編輯器,在編輯器中用putXxx()添加數據,之後務必用commit提交數據,否則無法獲取數據。取數據時,直接用getXxx()方法。

     sp存儲自動生成xml文件,其的路徑如下:

    

     sp存儲的實現方法:

package com.example.qqload;
import com.example.qqload_sp.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends Activity {
    private EditText et_qq;
    private EditText et_password;
    private CheckBox cb_remenber;
     private SharedPreferences sp;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq = (EditText) findViewById(R.id.et_qq);
        et_password = (EditText) findViewById(R.id.et_password);
        cb_remenber = (CheckBox) findViewById(R.id.cb_remenber);
        sp = this.getSharedPreferences("config", 0);
        String qq = sp.getString("qq","");
        String password = sp.getString("password","");
        et_qq.setText(qq);
        et_password.setText(password);
    }
    public void login(View view){
        String qq = et_qq.getText().toString().trim();
        String password = et_password.getText().toString().trim();
        if(TextUtils.isEmpty(qq)||TextUtils.isEmpty(password)){
            Toast.makeText(this,"密碼或者用戶名不能為空",0).show();
            return;
        }
        if(cb_remenber.isChecked()){
            Editor edit = sp.edit();
            edit.putString("qq",qq);
            edit.putString("password",password);
            edit.commit();
        }
    }
}

    

      資料庫存儲:

      資料庫所有信息都存儲在單一文件內,占用記憶體小,並且支持基本SQL語法,是項目中經常被採用的一種數據存儲方式,通常用於存儲用戶信息等,例如在手機上做一個學生信息管理系統。SQLite 是一款內置到移動設備上的輕量型的資料庫,SQLiteOpenHelper 是Android 提供的一個抽象工具類,負責管理資料庫的創建、升級工作。資料庫的路徑為:/data/data/應用包名/databases/資料庫。如果想創建資料庫,就需要自定義一個類繼承SQLiteOpenHelper,然後覆寫其中的抽象方法,指定資料庫名、版本號。在onCreate() 方法中通過執行sql 語句實現表的創建。如果只是創建出來該類並不會真正的去創建資料庫,而是需要通過執行helper.getWritableDatabase()或者hepler.getReadableDatabase()。另外想要對創建的資料庫進行增刪改查的操作可以單獨定義一個類實現。增刪改查操作有兩種方式,一是直接執行sql語句,另一個是Android自身的API實現。用資料庫實現賬號登錄顯得有些大材小用,為演示資料庫的原理本文給出的案例是用資料庫記錄多個用戶的賬號和密碼信息,並把最後一個賬號信息回顯在界面。但實際應用中很少這樣做。

     從手機文件中導出資料庫文件並不可以直接打開,因此可以用可視化工具和sqlite3操作工具進行查看。這裡介紹sqlite3工具的使用。具體需要的步驟如下: 

        1. 執行adb shell命令進入Linuxne內核;

        2. 使用cd進入資料庫所在的路徑 cd: /data/data/應用包名/databases;

        3. 進入資料庫模式: sqlite3 資料庫名.db;

        4. 執行SQL語句        

        Sqlite3操作演示:

         

        資料庫存儲路徑:

     

       資料庫實現方法,先創建一個類繼承SqliteOpenHelper,在類中創建資料庫和表:

package com.example.qqload.db;

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

public class UserDBOpenhelper extends SQLiteOpenHelper {
    public UserDBOpenhelper(Context context) {
        super(context, "user.db", null, 1);
        // TODO Auto-generated constructor stub
    }
    @Override
    public void onCreate(SQLiteDatabase arg0) {
        arg0.execSQL("create table user (_id integer primary key autoincrement,name vachar(20),password varchar(20))");
    }
    @Override
    public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
        // TODO Auto-generated method stub
    }
}

      

       創建一個工具類實現對資料庫的操作:

package com.example.qqload.db.dao;

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

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

import com.example.qqload.db.UserDBOpenhelper;

public class UserDao {
    private UserDBOpenhelper helper; 
    public UserDao(Context context){
        helper = new UserDBOpenhelper(context);
    }
    public long add(String name,String password){
        SQLiteDatabase  db = helper.getWritableDatabase();
        //用SQL語句實現增加數據的功能
        //db.execSQL("insert into user (name,passeord) values (?,?)", new Object[]{name,password});
        //android自身API實現修改功能可以有返回值
        ContentValues values =new ContentValues();
        values.put("name", name);
        values.put("password", password);
        long result = db.insert("user", null, values); //帶返回值,表示添加在哪一行
        db.close();
        return result;
    }
    public List<user> findAll(){
        List<user> list =new ArrayList<user>();
        SQLiteDatabase  db = helper.getReadableDatabase();
        //Cursor cursor = db.rawQuery("select name, password from user", null);
        Cursor cursor =  db.query("user", new String[]{"name","password"}, null, null, null, null, null);
        while(cursor.moveToNext()){
            String name = cursor.getString(0);
            String password = cursor.getString(1);
            user us = new user();
            us.setName(name);
            us.setPassword(password);
            list.add(us);
        }
        cursor.close();
        db.close();
        return list;
    }
}

        在主方法中實現賬號登錄和記錄

package com.example.qqload;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.List;

import com.example.qqload.db.dao.UserDao;
import com.example.qqload.db.dao.user;
import com.example.qqload.R;

import android.os.Bundle;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.text.TextUtils;
import android.view.Menu;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {
    private EditText et_qq;
    private EditText et_password;
    private CheckBox cb_remenber;
    private UserDao dao;
    private List<user> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_qq = (EditText) findViewById(R.id.et_qq);
        et_password = (EditText) findViewById(R.id.et_password);
        cb_remenber = (CheckBox) findViewById(R.id.cb_remenber);
        user u = new user();
        dao = new UserDao(MainActivity.this);
        list = dao.findAll();
        if (list.size() == 0) {
            et_qq.setText("");
            et_password.setText("");
        } else {
            System.out.println("大小:" + list.size());
            for (int i = 0; i < list.size(); i++) {
                System.out.println(list.get(i).getName() + "::::" + list.get(i).getPassword());
            }
            u = list.get(list.size()-1);
            String qq = u.getName();
            String password = u.getPassword();
            et_qq.setText(qq);
            et_password.setText(password);
        }
    }

    public void login(View view) {
        String qq = et_qq.getText().toString().trim();
        String password = et_password.getText().toString().trim();
        if (TextUtils.isEmpty(qq) || TextUtils.isEmpty(password)) {
            Toast.makeText(this, "密碼或者用戶名不能為空", 0).show();
            return;
        }
        if (cb_remenber.isChecked()) {
            dao.add(qq, password);           //在工具類添加增加功能
            Toast.makeText(MainActivity.this, "保存成功", 0).show();
        }
    }
}

 

          用資料庫實現賬號登錄案例的目錄結構如下所示:

            

 

   

       

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 學習內容來自:《JavaScript高級程式設計(第三版)》 正文:我們知道,在js中,函數實際上是一個對象,每個函數都是Function類型的實例,並且都與其他引用類型一樣具有屬性和方法。因此,函數名實際上是指向函數對象的指針,不與某個函數綁定。在常見的兩種定義方式(見下文)之外,還有一種定義的方 ...
  • 有關localStorage和sessionStorage的特性。 localStorage本身帶有方法有 添加鍵值對:localStorage.setItem(key,value),如果key存在時,更新value。 獲取鍵值:localStorage.getItem(key),如果key不存在返 ...
  • 在做移動端web app的時候,眾所周知,移動設備解析度五花八門,雖然我們可以通過CSS3的media query來實現適配,例如下麵這樣: 但是這種做法並不能適配所有設備,於是就有了實現全適配的JS解決方案,例如下麵這樣: 另外附上淘寶移動端適配解決方案flexible.js源碼: 1 ;(fun ...
  • 今天做form表單提交遇到了兩個問題: 1.提交後不能跳轉到指定頁面 jsp代碼 js提交事件處理: 這種寫法在頁面點擊保存後在當前頁面跳轉, 而不執行post請求function(data){}中的方法:window.history.back()返回到上一級歷史頁面,分析原因是button的typ ...
  • 最近在使用jquery.form.js提交包含文件的表單時,碰到了一個問題:當碰上網速較慢時,而我們又設置了timeout時,例如: 我們的頁面會死在這裡,貼上F12開發者工具返回的結果: 此時,我們並沒有處理錯誤的回調函數,而百度出來的例子中也只有這兩個回調函數: beforeSubmit: sh ...
  • react實例之todo, 做一個實時響應的列表操作 在所有的mvc框架中,最常見的例子不是hello world,而是todo,由於reactjs的簡單性,在不引用flux和redux的情況下,我們也一樣可以做出很好的效果來。 本文的例子在react中國首頁中可以看到,它的源代碼請點擊這裡http ...
  • 對於一個從後臺轉到前端的web開發者來說,最大的麻煩就是寫CSS,瞭解CSS的人都知道,它可以開髮網頁樣式,但是沒法用它編程,感覺耦合性相當的高,如果想要方便以後維護,只能逐句修改甚至重寫相當一部分的CSS。隨著後臺人員大量的涌入前端這個行業,CSS又煥發了新的春天,人們開始為CSS加入編程元素,也 ...
  • 讓前端程式更具可維護性,是一個老生常談的問題,大多數時候我們都關註於應用層面的代碼可維護性,如:OO、模塊化、MVC,編碼規範、可擴展和復用性,但這都是屬於設計層面需要考慮的事情,可維護性還應包含另一個方面,也是很多coder容易忽略的地方,就是將自己寫的程式以文檔的形式沉澱起來,對自己工作有一個結 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...