Android數(shù)據(jù)存儲(chǔ)幾種方式講解
一、文件存儲(chǔ)
特點(diǎn):openFileInput()和openFileOutput()讀取設(shè)備上的文件。
優(yōu)點(diǎn):適用于存儲(chǔ)大量的數(shù)據(jù),可以存儲(chǔ)圖片、視頻、文本等數(shù)據(jù)。
缺點(diǎn):如果采用內(nèi)部存儲(chǔ)的方式,存儲(chǔ)過(guò)量的數(shù)據(jù)可能會(huì)導(dǎo)致內(nèi)存的不足;如果采用外部sdcard存儲(chǔ)的方式,刪除或者卸載應(yīng)用,相關(guān)的數(shù)據(jù)需要手動(dòng)進(jìn)行刪除,比較麻煩。
默認(rèn)位置:/data/data/<包>/files/.。

(一)內(nèi)部存儲(chǔ)
// 將數(shù)據(jù)存儲(chǔ)到指定的文件中 // name為文件名,mode為文件的操作模式 FileOutputStream fos = openFileOutput(String name,int mode); // 讀取指定文件中的數(shù)據(jù) FileInputStream fis = openFileInput(String name);
mode的取值如下:
MODE_PRIVATE:該文件只能被當(dāng)前程序讀寫(xiě) ;
MODE_APPEND:該文件的內(nèi)容可以追加;
MODE_WORLD_READABLE:該文件的內(nèi)容可以被其他程序讀;
MODE_WORLD_WRITEABLE:該文件的內(nèi)容可以被其他程序?qū)?/p>
注意:Android系統(tǒng)有一套自己的安全模型,默認(rèn)情況下任何應(yīng)用創(chuàng)建的文件都是私有的,其他程序無(wú)法訪問(wèn)。
1.寫(xiě)入文件步驟
String fileName = “data.txt”; // 文件名稱(chēng)
String content = “helloworld”; // 保存數(shù)據(jù)
FileOutputStream fos = openFileOutput(fileName, MODE_PRIVATE);
fos.write(content.getBytes()); //將數(shù)據(jù)寫(xiě)入文件中
fos.close(); //關(guān)閉輸出流
2.讀取文件步驟
String content = “”;
FileInputStream fis = null;
fis = openFileInput(“data.txt”); //獲得文件輸入流對(duì)象
byte[] buffer = new byte[fis.available()]; // 創(chuàng)建緩沖區(qū),并獲取文件長(zhǎng)度
fis.read(buffer); // 將文件內(nèi)容讀取到buffer緩沖區(qū)
content = new String(buffer);//轉(zhuǎn)換成字符串
fis.close(); //關(guān)閉輸入流
3.實(shí)現(xiàn)存儲(chǔ)和讀取用戶(hù)名和密碼實(shí)例
創(chuàng)建UserInfoIO工具類(lèi),實(shí)現(xiàn)存儲(chǔ)數(shù)據(jù)方法(saveUserInfo)和讀取數(shù)據(jù)方法(getUserInfo)
public class UserInfoIO {
// 數(shù)據(jù)的寫(xiě)入
public static boolean saveUserInfo(String username, String password, Context context){
// openFileOutput(要操作的文件名,文件訪問(wèn)模式)
FileOutputStream fos = null;
String msg = null;
try { // 在操作文件的時(shí)候可能會(huì)報(bào)異常,需要進(jìn)行捕獲
fos = context.openFileOutput("MyData.txt",Context.MODE_PRIVATE);
msg = username + ":" + password;
// getBytes()將字符串轉(zhuǎn)換為字節(jié)流
fos.write(msg.getBytes());
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
finally {
try {
fos.close(); // 流是系統(tǒng)中的稀缺資源,在使用完后要及時(shí)關(guān)閉
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 用戶(hù)數(shù)據(jù)的讀取
public static Map<String,String> getUserInfo(Context context){
// 獲取文件輸入流
FileInputStream fis = null;
try {
fis = context.openFileInput("MyData.txt");
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
// 字節(jié)轉(zhuǎn)換為字符串
String msg = new String(buffer);
String[] userInfo = msg.split(":");
Map<String,String> userMap = new HashMap<>();
userMap.put("username",userInfo[0]);
userMap.put("password",userInfo[1]);
return userMap;
} catch (IOException e) {
e.printStackTrace();
return null;
}
finally {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
二、SharedPreferences存儲(chǔ)
特點(diǎn):以XML格式將數(shù)據(jù)存儲(chǔ)到設(shè)備。
優(yōu)點(diǎn):簡(jiǎn)單、方便、輕量級(jí)、易理解。
缺點(diǎn):適用于存儲(chǔ)少量的數(shù)據(jù),并且數(shù)據(jù)的格式只能是基本的數(shù)據(jù)類(lèi)型(int、float、long、boolean)、字符串類(lèi)型(string),無(wú)法進(jìn)行條件查詢(xún)等操作。
SharedPreferences是一個(gè)輕量級(jí)的存儲(chǔ)類(lèi),特別適合用于保存軟件配置參數(shù),其背后是用xml文件存放數(shù)據(jù),文件存放在/data/data//shared_prefs目錄下。
1.寫(xiě)入文件步驟
SharedPreferences對(duì)象本身只能獲取數(shù)據(jù)而不支持存儲(chǔ)和修改,存儲(chǔ)修改是通過(guò)Editor對(duì)象實(shí)現(xiàn)。
SharedPreferences sp = getSharedPreferences(“data”,MODE_PRIVATE);//獲取
SharedPreferences對(duì)象
SharedPreferences.Editor editor = sp.edit(); // 獲取編輯器對(duì)象
editor.putString(“name”, “張三”); // 存入String類(lèi)型數(shù)據(jù)
editor.putInt(“age”, 8); // 存入int類(lèi)型數(shù)據(jù)
editor.commit(); // 提交數(shù)據(jù)
2.讀取文件步驟
SharedPreferences sp = getSharedPreferences(“data”,MODE_PRIVATE);
String data= sp.getString(“name”,“”);
3.刪除文件中數(shù)據(jù)
editor.remove(“name”); // 根據(jù)key刪除數(shù)據(jù)
editor.clear(); // 刪除所有數(shù)據(jù)
4. 實(shí)現(xiàn)存儲(chǔ)和讀取用戶(hù)名和密碼實(shí)例
創(chuàng)建UserInfoSharePre工具類(lèi),實(shí)現(xiàn)存儲(chǔ)數(shù)據(jù)方法(saveUserInfo)和讀取數(shù)據(jù)方法(getUserInfo)
public class UserInfoSharedPre {
// 用戶(hù)數(shù)據(jù)的存儲(chǔ)
public static boolean saveUserInfo(String username, String password, Context context) {
// 獲取SharedPreferences對(duì)象,同時(shí)指定文件名稱(chēng)和訪問(wèn)權(quán)限
SharedPreferences sp = context.getSharedPreferences("MyData", Context.MODE_PRIVATE);
// 獲取獲取SharedPreferences的編輯器對(duì)象
SharedPreferences.Editor edit = sp.edit();
// 通過(guò)編輯器進(jìn)行數(shù)據(jù)的存儲(chǔ)
edit.putString("Uname",username);
edit.putString("Pwd",password);
edit.commit();
return true;
}
// 讀取用戶(hù)數(shù)據(jù)
public static Map<String,String> getUserInfo(Context context) {
// 獲取SharedPreferences對(duì)象,同時(shí)指定文件名稱(chēng)和訪問(wèn)權(quán)限
SharedPreferences sp = context.getSharedPreferences("MyData", Context.MODE_PRIVATE);
String username = sp.getString("Uname", "");
String password = sp.getString("Pwd","");
Map<String,String> userMap = new HashMap<>();
userMap.put("username",username);
userMap.put("password",password);
return userMap;
}
}
三、SQLite數(shù)據(jù)庫(kù)存儲(chǔ)
特點(diǎn):運(yùn)算速度快,占用資源少,還支持基本SQL語(yǔ)法。
優(yōu)點(diǎn):適合存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù)、輕量級(jí)、安全性、隔離性、獨(dú)立性。
缺點(diǎn):并發(fā)的讀寫(xiě)性能不好。
1. 創(chuàng)建數(shù)據(jù)庫(kù)步驟
(一)定義數(shù)據(jù)庫(kù)幫助類(lèi)
SQLiteOpenHelper是SQLiteDatabase的一個(gè)幫助類(lèi),用來(lái)管理數(shù)據(jù)庫(kù)的創(chuàng)建和版本的更新
class MyDbHelper extends SQLiteOpenHelper {
// 構(gòu)造器的作用:(參數(shù):上下文,數(shù)據(jù)庫(kù)文件的名稱(chēng),結(jié)果集工廠,版本號(hào))定義數(shù)據(jù)庫(kù)
public MyDbHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
// 數(shù)據(jù)庫(kù)初始化時(shí)創(chuàng)建的表,用于創(chuàng)建表或視圖文件
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table user(user_id integer primary key autoincrement,userName varchar(10),password varchar(10))");
}
// 升級(jí)方法(當(dāng)數(shù)據(jù)庫(kù)的版本號(hào)增加時(shí)調(diào)用)
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
(二)創(chuàng)建數(shù)據(jù)庫(kù)和表
// 設(shè)置數(shù)據(jù)庫(kù)的相關(guān)參數(shù),初始化數(shù)據(jù)庫(kù) MyDbHelper myDbHelper = new MyDbHelper(SQLiteActivity.this,"MyDatabase.db",null,1); // 通過(guò)幫助類(lèi)獲取到數(shù)據(jù)庫(kù)對(duì)象 SQLiteDatabase db = myDbHelper.getWritableDatabase();
通過(guò)數(shù)據(jù)庫(kù)對(duì)象可以執(zhí)行如下方法:

1.插入方法insert
// 創(chuàng)建ContentValues對(duì)象用于存儲(chǔ)記錄的字段值(鍵值對(duì)方式:鍵對(duì)應(yīng)字段名,值對(duì)應(yīng)字段具體的值)
ContentValues contentValues = new ContentValues();
contentValues.put("userName","張三");
contentValues.put("password","123456");
db.insert("user",null,contentValues);
上面等同于
db.execSQL("insert into user(userName,password) values (?,?)",new Object[]{<!--{C}%3C!%2D%2D%20%2D%2D%3E-->"張三","123456"});執(zhí)行完之后
db.close();
2.查詢(xún)方法query
調(diào)用query方法查詢(xún)數(shù)據(jù)庫(kù)中的數(shù)據(jù),返回一個(gè)行數(shù)集合cursor
public Cursor query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
各參數(shù)說(shuō)明:
各參數(shù)說(shuō)明:
table:表名稱(chēng)
colums:列名稱(chēng)數(shù)組,返回那些字段,null表示所有字段
selection:查詢(xún)條件子句,相當(dāng)于select語(yǔ)句where關(guān)鍵字后面的部分,在條件子句允許使用占位符“?” selectionArgs:對(duì)應(yīng)于selection語(yǔ)句中占位符的值,值在數(shù)組中的位置與占位符在語(yǔ)句中的位置必須一致, 否則就會(huì)有異常。
groupBy:相當(dāng)于select語(yǔ)句group by關(guān)鍵字后面的部分
having:相當(dāng)于select語(yǔ)句having關(guān)鍵字后面的部分
orderBy:排序類(lèi)
limit:分頁(yè)查詢(xún)的限制,指定偏移量和獲取的記錄數(shù)
Cursor:返回值,相當(dāng)于結(jié)果集ResultSet
// Cursor: 結(jié)果集,內(nèi)有游標(biāo)指向結(jié)果集中的某一條記錄,初始時(shí)指向第一條
Cursor cursor = db.query("user", new String[]{"userName,password"}, null, null, null, null, null, null);
cursor.moveToFirst();
while (cursor.moveToNext()) { // 移動(dòng)游標(biāo)指向下一行數(shù)據(jù)
showInfo.append("\n" + "用戶(hù)名" + cursor.getString(0) + ",密碼" + cursor.getString(1));
}
cursor.close();
db.close();
對(duì)于cursor也提供了一些方法如下:

3.刪除方法delete
返回刪除的記錄條數(shù)
public boolean deleteData(String deleteId) {
int i = db.delete("user", "id=?", new String[]{deleteId});
return i > 0 ? true : false;
}
4.修改方法update
返回更新的記錄條數(shù)
ContentValues contentValues = new ContentValues();
contentValues.put("userName","李四");
contentValues.put("password","123123");
int i = db.update("user", contentValues, "id=?", new String[]{updateId});
等同于
db.execSQL("update user set userName=?,password=? where id=?",new Object[]{<!--{C}%3C!%2D%2D%20%2D%2D%3E-->username1,password1,id});四、ContentProvider存儲(chǔ)
特點(diǎn):ContentProvider主要用于不同應(yīng)用程序之間共享數(shù)據(jù),ContentProvider更好的提供了數(shù)據(jù)共享接口的統(tǒng)一性,使不同應(yīng)用共享數(shù)據(jù)更規(guī)范和安全。
優(yōu)點(diǎn):能夠?qū)崿F(xiàn)所有應(yīng)用程序共享的一種數(shù)據(jù)存儲(chǔ)方式,可以存儲(chǔ)音頻,視頻,圖片和通訊錄等。
缺點(diǎn):不能單獨(dú)使用,必須與其他存儲(chǔ)方式結(jié)合使用。
內(nèi)容提供者(ContentProvider)是Android系統(tǒng)四大組件之一,它是不同應(yīng)用程序之間進(jìn)行數(shù)據(jù)共享的標(biāo)準(zhǔn)API,通過(guò)ContentResolver類(lèi)可以訪問(wèn)ContentProvider中共享的數(shù)據(jù)。
ContentProvider的工作原理如下:

常見(jiàn)的使用場(chǎng)景:QQ和微信中文件的相互轉(zhuǎn)發(fā);安裝完某個(gè)app第一次啟動(dòng)的時(shí)候獲取權(quán)限(聯(lián)系人、拍照、位置等)
ContentProvider 使用基于數(shù)據(jù)庫(kù)模型的簡(jiǎn)單表格來(lái)提供需要共享的數(shù)據(jù),在該表格中,每一行表示一條記錄,而每一列代表特定類(lèi)型和含義的數(shù)據(jù),并且其中每一條數(shù)據(jù)記錄都包含一個(gè)名為“_ID”的字段類(lèi)標(biāo)識(shí)每條數(shù)據(jù),可以根據(jù)同一個(gè)ID查詢(xún)幾個(gè)相關(guān)表中的信息。知道各個(gè)字段對(duì)應(yīng)的數(shù)據(jù)類(lèi)型后,可根據(jù)Cursor對(duì)象提供的相關(guān)的方法,如,getInt()、getString()、getLong()等查詢(xún)字段對(duì)應(yīng)的值。

簡(jiǎn)單理解:A程序共享數(shù)據(jù)實(shí)際上就是共享一張表,B程序要去獲取數(shù)據(jù)實(shí)際上就是要去對(duì)表執(zhí)行查詢(xún)操作。
問(wèn)題:B程序如何精確地找到A程序所共享出來(lái)的表?
ContentResolver提供一系列增刪改查的方法對(duì)數(shù)據(jù)進(jìn)行操作,并且這些方法以Uri的形式對(duì)外提供數(shù)據(jù)。
Uri為內(nèi)容提供者中的數(shù)據(jù)建立了唯一標(biāo)識(shí)符。它主要由三部分組成,scheme、authorities(主機(jī)名/域名)和path。
擴(kuò)展:uri與url功能類(lèi)似,通過(guò)uri可以指向安卓系統(tǒng)中唯一的某個(gè)資源。也就是說(shuō)通過(guò)它可以指向共享出來(lái)的唯一的某個(gè)表文件
如下:

scheme部分,“content://”是一個(gè)標(biāo)準(zhǔn)的前綴。
authority(主機(jī)名/域名)部分,是在創(chuàng)建內(nèi)容提供者時(shí)指定的authorities屬性值,通常采用程序包名的方式命名。
path部分,“/person”代表資源(或者數(shù)據(jù)),可以動(dòng)態(tài)改變。
UriMatcher類(lèi):用于對(duì)ContentProvider中的Uri進(jìn)行匹配
1、初始化UriMatcher
UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); // 常量UriMatcher.NO_MATCH表示不匹配任何路徑的返回碼(-1)
2、將Uri注冊(cè)到UriMatcher中
matcher.addURI("cn.itcast.contentprovider", "people", 1);
// 添加需要匹配uri,如果匹配就會(huì)返回匹配碼"1"
matcher.addURI("cn.itcast.contentprovider", "person/#", 2);
// #表示通配符,任意內(nèi)容的意思
1.創(chuàng)建數(shù)據(jù)庫(kù)與表提供數(shù)據(jù)
public class MyDBhelper extends SQLiteOpenHelper {
public MyDBhelper(Context context) {
super(context, "person.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table user(id integer primary key autoincrement,userName varchar(10),phone varchar(10))");
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
2.創(chuàng)建內(nèi)容提供者繼承ContentProvider父類(lèi)
在程序包名處右擊選擇【New】—>【Other】—>【Content Provider】選項(xiàng)
輸入內(nèi)容提供者的Class Name(類(lèi)名稱(chēng))和URI Authorities(唯一標(biāo)識(shí),通常使用包名)
內(nèi)容提供者創(chuàng)建完成后,Android Studio會(huì)自動(dòng)在AndroidManifest.xml中對(duì)內(nèi)容提供者進(jìn)行注冊(cè)。
<application ......>
......
<provider
android:name=".MyContentProvider"
android:authorities="cn.com.myapp"
android:enabled="true"
android:exported="true" >
</provider>
</application>
屬性含義如下:
(1)android:name:該屬性是一個(gè)類(lèi)的全名稱(chēng)
(2)android:authorities:列出一個(gè)或者多個(gè)由content provider的提供的URI的authorities,多個(gè)authorities由分號(hào)隔開(kāi)(自定義)。
(3)android:enabled:該屬性表明了該content provider是否可以被實(shí)例化,默認(rèn)情況下該屬性值是true。
(4)android:exported:該屬性指示了content provider是否可以被其他應(yīng)用程序使用。
public class MyContentProvider extends ContentProvider {
private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int SUCCESS = 1;
private MyDBhelper myDBhelper;
// 靜態(tài)代碼塊,MyContentProvider對(duì)象沒(méi)有創(chuàng)建出來(lái)之前就已經(jīng)存在
static {
// 加載時(shí)為uri適配器添加匹配規(guī)則
uriMatcher.addURI("cn.com.myapp","user",SUCCESS);
// 查詢(xún)表中的某條記錄
uriMatcher.addURI("cn.com.myapp","user/#",2);
}
public MyContentProvider() {
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO: Implement this to handle requests to insert a new row.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public boolean onCreate() {
// 創(chuàng)建數(shù)據(jù)庫(kù)和初始化表的內(nèi)容
myDBhelper = new MyDBhelper(getContext());
return false;
}
@Override
// 未來(lái)會(huì)有另外一個(gè)app通過(guò)uri來(lái)調(diào)用query方法
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO: Implement this to handle query requests from clients.
// 匹配傳入的uri,如果匹配得上再做相應(yīng)的查詢(xún)
int match = uriMatcher.match(uri);
if(match == 1) {
// 查詢(xún)user表中的數(shù)據(jù)并返回
SQLiteDatabase db = myDBhelper.getWritableDatabase();
return db.query("user",projection,selection,selectionArgs,null,null,sortOrder);
} else if(match == 2) {
// 查詢(xún)表中的某條記錄
} else {
return null;
}
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO: Implement this to handle requests to update one or more rows.
throw new UnsupportedOperationException("Not yet implemented");
}
}3.在第一個(gè)app的Activity中給數(shù)據(jù)庫(kù)添加數(shù)據(jù)
public class firstApplicationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_first_application);
MyDBhelper myDBhelper = new MyDBhelper(firstApplicationActivity.this);
SQLiteDatabase db = myDBhelper.getWritableDatabase();
db.execSQL("insert into user(userName,phone) values ('tom','8888')");
db.execSQL("insert into user(userName,phone) values ('jeny','18888')");
db.execSQL("insert into user(userName,phone) values ('jack','38888')");
}
}
4.創(chuàng)建第二個(gè)App作為訪問(wèn)者
布局文件,通過(guò)點(diǎn)擊按鈕獲取第一個(gè)app的數(shù)據(jù)用TextView展示出來(lái)
<?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"
tools:context=".secondApplicationActivity"
android:orientation="vertical"
>
<TextView
android:id="@+id/show"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="9"/>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="獲取共享數(shù)據(jù)"
/>
</LinearLayout>
java文件
public class secondApplicationActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
private TextView tv_show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second_application);
initViews();
setListener();
}
protected void initViews() {
btn = findViewById(R.id.btn);
tv_show = findViewById(R.id.show);
}
protected void setListener() {
btn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn:
// 創(chuàng)建uri,通過(guò)uri來(lái)指向共享的數(shù)據(jù)文件
Uri uri = Uri.parse("content://cn.com.myapp/user");
// 獲取訪問(wèn)對(duì)象(內(nèi)容解析者)
ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(uri, new String[]{"userName", "phone"}, null, null, null);
while (cursor.moveToNext()) {
tv_show.append("用戶(hù)名:" + cursor.getString(0) + "----:" + cursor.getString(1) + "\n");
}
}
}
}
最后,兩個(gè)app都啟動(dòng),點(diǎn)擊第二個(gè)app的按鈕拿到了第一個(gè)app共享的值

五、網(wǎng)絡(luò)存儲(chǔ)
特點(diǎn):通過(guò)網(wǎng)絡(luò)上提供的存儲(chǔ)空間來(lái)上傳(存儲(chǔ))或下載(獲取)我們存儲(chǔ)在網(wǎng)絡(luò)空間中的數(shù)據(jù)信息
優(yōu)點(diǎn):無(wú)需考慮內(nèi)存的影響。
缺點(diǎn):受網(wǎng)絡(luò)的狀態(tài)的影響、需要耗費(fèi)流量等成本。
到此這篇關(guān)于Android數(shù)據(jù)存儲(chǔ)幾種方式講解的文章就介紹到這了,更多相關(guān)Android數(shù)據(jù)存儲(chǔ)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android設(shè)備上非root的抓包實(shí)現(xiàn)方法(Tcpdump方法)
通常我們?cè)贏ndroid應(yīng)用中執(zhí)行某個(gè)命令時(shí)會(huì)使用“Runtime.getRuntime().exec("命令路徑")”這種方式,但是當(dāng)我們執(zhí)行抓包操作時(shí),使用這條命令無(wú)論如何都不行,通過(guò)下面代碼打印結(jié)果發(fā)現(xiàn),該命令一定要在root權(quán)限下才能執(zhí)行,具體實(shí)現(xiàn)思路,請(qǐng)參考本教程2016-11-11
Android中自定義的dialog中的EditText無(wú)法彈出輸入法解決方案
這篇文章主要介紹了Android中自定義的dialog中的EditText無(wú)法彈出輸入法解決方案,需要的朋友可以參考下2017-04-04
Flutter開(kāi)發(fā)之對(duì)角棋游戲?qū)崿F(xiàn)實(shí)例詳解
這篇文章主要為大家介紹了Flutter開(kāi)發(fā)之對(duì)角棋游戲?qū)崿F(xiàn)實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android編程使WebView支持HTML5 Video全屏播放的解決方法
這篇文章主要介紹了Android編程使WebView支持HTML5 Video全屏播放的解決方法,較為詳細(xì)的分析了全屏播放所涉及的相關(guān)技巧,并給出了完整代碼下載地址供讀者參考,需要的朋友可以參考下2015-10-10
Android編程之殺毒的實(shí)現(xiàn)原理及具體實(shí)例
這篇文章主要介紹了Android編程之殺毒的實(shí)現(xiàn)原理及具體實(shí)例,結(jié)合實(shí)例形式分析了Android殺毒功能的原理與簡(jiǎn)單實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-12-12
ImageView 實(shí)現(xiàn)Android colorPikcer 選擇器的示例代碼
本篇文章主要介紹了ImageView 實(shí)現(xiàn)Android colorPikcer 選擇器的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-10-10
Android MPAndroidChart開(kāi)源圖表庫(kù)之餅狀圖的代碼
MPAndroidChart是一款基于Android的開(kāi)源圖表庫(kù),MPAndroidChart不僅可以在Android設(shè)備上繪制各種統(tǒng)計(jì)圖表,而且可以對(duì)圖表進(jìn)行拖動(dòng)和縮放操作,應(yīng)用起來(lái)非常靈活2018-05-05
Android 中Popwindow彈出菜單的兩種方法實(shí)例
這篇文章主要介紹了Android 中Popwindow彈出菜單的兩種方法實(shí)例的相關(guān)資料,這里提供了兩種實(shí)現(xiàn)的方法,并附有實(shí)例代碼,需要的朋友可以參考下2017-03-03
Android編程開(kāi)發(fā)之NotiFication用法詳解
這篇文章主要介紹了Android編程開(kāi)發(fā)之NotiFication用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了NotiFication的功能、使用技巧與注意事項(xiàng),需要的朋友可以參考下2015-12-12

