Android入門(12)| 數據持久化

文章目錄

  • 數據持久化
  • 文件存儲
    • 將數據存儲進文件
      • 實例
    • 從文件中讀取數據
      • 實例
  • SharedPreferences存儲
    • 將數據存儲進文件
      • 實例
    • 從文件中讀取數據
      • 實例
    • 實現記住密碼的功能
  • SQLite數據庫存儲
    • 創建自己的幫助類
    • 調用自己的幫助類
    • 補全 onUpgrade() 方法
    • 增刪查改
      • 增:SQLiteDatabase.insert()
      • 改:SQLiteDatabase.update()
      • 刪:SQLiteDatabase.delete()
      • 查:SQLiteDatabase.query()
    • 通過 SQL語句 實現增刪查改


數據持久化

保存在內存中的數據是屬于瞬時狀態的,而保存在存儲設備中的數據上處于持久狀態的,持久化技術提供了一種可以讓數據在瞬時狀態和持久狀態之間轉換的機制。

Android系統中主要提供了3種常用方式用于簡單地實現數據持久化功能,即文件存儲SharedPreference存儲以及數據庫存儲


文件存儲

將數據存儲進文件

Context類 中提供了一個 openFileOutput 方法,用于將數據存儲到指定的文件中。這個方法接收兩個參數:

  • 第一個參數是文件名:在文件創建的時候使用的就是這個名稱,文件名不可以包含路徑,因為所有的文件都是默認存儲到 /data/data/<packagename>/files/ 目錄下的。
  • 第二個參數是文件的操作模式:主要有兩種模式可以選,MODE_PRIVATE 默認的操作模式,寫入的內容會覆蓋原文件的內容; MODE_APPEND 則表示如果該文件已經存在,就往文件里面追加內容,不存在創建新文件

該方法返回一個 FileOutputStream 對象,得到了這個對象之后就可以使用 Java流 的方式將數據寫入到文件中了。

實例

在布局文件中添加輸入框 EditText 控件:
在這里插入圖片描述
在活動文件中,定義不同生命周期的不同行為:

  • onCreate 方法:獲取 EditText 實例;
  • onDestroy 方法:獲取 EditText 中的內容,并通過自定義方法 save 保存到名為 data 的文件中。
public class SecondActivity extends AppCompatActivity {private EditText editText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.second_layout);editText = findViewById(R.id.edit);}@Overrideprotected void onDestroy() {super.onDestroy();String inputText = editText.getText().toString();save(inputText);}public void save(String inputText){FileOutputStream out = null; // 文件字節輸出流,繼承OutputStream類BufferedWriter writer = null; // 將文本寫入字符輸出流try {// 獲得一個 字節輸出流對象,規定數據存儲到名為data的文件中,文件的操作模式為MODE_PRIVATEout = openFileOutput("data", Context.MODE_PRIVATE);// 借助out構建OutputStreamWriter臨時對象,作為從字符流到字節流的橋接// 再通過臨時對象構建 字符輸出流對象 以便將文本內容寫入到字節流中writer = new BufferedWriter(new OutputStreamWriter(out));// 將文本內容寫入到字符流中writer.write(inputText);} catch (IOException e){e.printStackTrace();} finally {try {if(writer != null){writer.close();}} catch (IOException e){e.printStackTrace();}}}
}

PS:對于上述將文本存入文件的流程,一開始我理解錯了,順著代碼順尋看以為是字節流轉成字符流再寫入文件,把 inputText 當保存文本的文件了。。。

其實正確邏輯是:
在這里插入圖片描述

運行結果:

在文本框內輸入內容:
在這里插入圖片描述
退出程序后,在AS中通過如下操作打開文件頁面:
在這里插入圖片描述
在下圖路徑中找到 data 文件,查看其內容:
在這里插入圖片描述


從文件中讀取數據

Context 類中還提供了一個 openFileInput 方法,用于從文件中讀取數據。這個方法只接受一個參數:

  • 要讀取的文件名:然后系統會自動到 /data/data/<packagename>/files 目錄下去加載這個文件。

該方法返回一個 FileInputStream 對象,得到了這個對象之后再通過 Java流 的方式就可以將數據讀取出來了。

實例

EditText 為空則將文件中的文本讀入到 EditText 中:

public class SecondActivity extends AppCompatActivity {private EditText editText;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.second_layout);editText = findViewById(R.id.edit);String inputText = load();if(!TextUtils.isEmpty(inputText)){editText.setText(inputText);editText.setSelection(inputText.length());Toast.makeText(this, "loading successed", Toast.LENGTH_LONG).show();}}public String load(){FileInputStream in = null;BufferedReader reader = null;StringBuilder content = new StringBuilder();try {in = openFileInput("data"); // 文本字節輸入流// InputStreamReader作為字符流到字節流的橋接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 e){e.printStackTrace();}}}return content.toString();}
}

PS:在判空時使用了 TextUtils.isEmpty() 而非 String.isEmpty(),這是因為:

  • String 類下的 isEmpty() 返回的只是 字符串的長度是否為0,如果 字符串為null 就會直接報 空指針。源碼如下:
public boolean isEmpty() { return count == 0; }
  • TextUtils.isEmpty() 會對 null長度 進行判斷,所以 不會報空指針。源碼如下:
public static boolean isEmpty(CharSequence str) { if (str == null || str.length() == 0) return true; else return false; 
}

此時,一打開界面即可顯示:
在這里插入圖片描述


SharedPreferences存儲

將數據存儲進文件

大致分為兩步,第一步,獲取對象:

SharedPreferences 通過 鍵值對 的方式來存儲數據的。要想存儲數據,需要先獲取 SharedPreferences對象,Android 中主要提供了三種方法用于得到 SharedPreferences 對象:

  • Context類 中的 getSharedPreferences 方法:此方法接受兩個參數,
    1. 第一個參數用于指定 SharedPreferences 文件的名稱,如果文件不存在則創建一個。文件都存放在 /data/data/<packagename>/shared_prefs/ 目錄下。
    2. 第二個參數用于指定 操作模式,目前只有 MODE_PRIVATE 這種默認的操作模式可選,和直接傳入 0 效果是相同的,表示只有當前的應用程序才可以對這個 SharedPreferences 文件進行讀寫
  • Acitvity類 中的 getPreferences 方法:只有一個參數——操作模式自動使用當前活動的類名來作為 SharedPreferences 的文件名。
  • PreferenceManager類 中的 getDefaultSharedPreferences 方法:靜態方法,接收一個 Context 參數,并自動使用當前應用程序的包名作為前綴來命名 SharedPreferences 文件。

第二步,存儲數據:

  1. 調用 SharedPreferences對象 的 edit方法 來獲取一個 SharedPreferences.Editor對象
  2. 向 SharedPreferences.Editor對象 中添加數據,比如添加一個布爾型數據就使用 putBoolean 方法,添加一個字符串則使用 putString 方法。
  3. 調用 apply 方法將添加的數據提交,從而完成數據存儲操作。

實例

實現點擊按鈕保存數據的功能:

        Button button_share = findViewById(R.id.button_share);button_share.setOnClickListener((View v)->{SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit();editor.putString("name", "cmy");editor.putInt("weight", 120);editor.putBoolean("married", false);editor.apply();Toast.makeText(this, "share over", Toast.LENGTH_LONG).show();});

點擊紅框所示按鈕:
在這里插入圖片描述
即可將數據存在如下圖所示的路徑中:
在這里插入圖片描述


從文件中讀取數據

第一步仍是獲取對象,上文已經講過,這里不再贅述。

第二步,通過對應的 get**()方法 獲取對應類型數據,如字符串使用 getString() 方法,這些 get 方法都接受兩個參數:

  • 第一個參數是:也就是 KV模型 中的 Key
  • 第二個參數是默認值:當傳入的找不到對應值時,以默認值返回。

實例

點擊 get sharePreferences 按鈕從 SharedPreferences文件 中讀取數據:
在這里插入圖片描述

再通過 Toast 顯示出來:

在這里插入圖片描述

        Button button_getShare = findViewById(R.id.button_getShare);button_getShare.setOnClickListener((View v)->{SharedPreferences preferences = getSharedPreferences("data", MODE_PRIVATE);String name = preferences.getString("name", "");int weight = preferences.getInt("weight", 0);boolean married = preferences.getBoolean("married", false);String res = name+" "+String.valueOf(weight)+" "+String.valueOf(married);Toast.makeText(this, res, Toast.LENGTH_LONG).show();});

實現記住密碼的功能

之前在本博客里實現過登陸界面,這里為登陸界面新加入一個記住密碼的功能。

修改布局文件,添加以下代碼,實現右側所示布局:
在這里插入圖片描述

這里使用到了一個新控件 復選框:CheckBox ,用戶可以通過點擊來進行選中/取消,以表是否需要記住密碼。

修改 LoginActivity.java 代碼,結合 SharedPreferences 實現記住密碼的功能:

在這里插入圖片描述
增添的內容主要是:

  • 三個相關對象 CheckBox、SharedPreferences、SharedPreferences.Editor 的創建和實例化;
  • 初始化布爾型對象 isRemember 作為 判斷記住密碼功能是否生效 的輔助變量;
    1. 一開當然不存在 remember_password 這個鍵對應的值,isRemember 為默認值 false
    2. 成功登陸一次后,remember_password 這個鍵對應的值就是 true 了。

以及登陸成功后的操作:
在這里插入圖片描述

  • 調用 CheckBoxisChecked() 方法檢查復選框是否被選中,被選中則返回 true
  • true 時表示用戶希望記住密碼,此時:
    1. remember_password 對應的值設為 true
    2. accountpassword 對應的值都存入到 SharedPreferences 文件中并提交。
  • false 表示用戶并不想記住密碼,此時要調用 clean() 方法清楚掉 SharedPreferences 文件中的所有數據。

運行結果:

  • 輸入正確的賬戶和密碼,并選中記住密碼,點擊登錄:
    在這里插入圖片描述
  • 通過強制下線跳轉回登陸界面,此時發現賬號密碼已經自動填充了。
  • 如果此時取消選中復選框,再點擊登錄:
    在這里插入圖片描述
  • 再次返回登陸界面就不會被填充了:
    在這里插入圖片描述
    PS:這里只做示例,實際項目中不能將密碼以明文形式存儲到 SharedPreferences 文件中,因為會被輕易盜取,必須結合加密算法對密碼進行加密。

SQLite數據庫存儲

為了管理數據庫,安卓專門提供了一個 SQLiteOpenHelper 幫助類,這是個抽象類,如果要使用它,需要創建一個 自己的幫助類 去繼承它。下面列舉幾個該類中常用的方法:

  • 兩個抽象方法onCreateonUpgrade,我們必須在 自己的幫助類 里重寫這兩個方法,然后分別在這兩個方法中去實現創建、升級數據庫的邏輯。
  • 兩個實例方法getReadableDatabasegetWritableDatabase。這兩個方法都可以創建或者打開一個現有的數據庫,數據庫文件存放在 /data/data/<packagename>/databases/ 目錄下,并返回一個可對數據庫進行讀寫的對象。不同的是,當數據庫不可寫入的時候,getReadableDatabase 方法返回的對象會用只讀的方式打開數據庫,而 getWritableDatabase 會出現異常
  • 兩個構造函數:常用的一個構造方法接收4個參數:第一個是Context;第二個是數據庫名;第三個參數允許我們在查詢數據的時候返回一個自定義的Cursor,一般都是傳入null;第四個參數表示當前數據庫的版本號,可以用于升級數據庫。

創建自己的幫助類

public class MyDatabaseHelper extends SQLiteOpenHelper {public static final String CREATE_STUDENT = "create table Student ("+ "id integer primary key autoincrement,"+ "gender text,"+ "weight real,"+ "age integer,"+ "name text)";private Context context;public MyDatabaseHelper( Context context,  String name,SQLiteDatabase.CursorFactory factory, int version) {super(context, name, factory, version);this.context = context;}@Overridepublic void onCreate(SQLiteDatabase db) {db.execSQL(CREATE_STUDENT);Toast.makeText(context, "create succeeded", Toast.LENGTH_LONG).show();}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
  • 把建表語句定義成一個字符串常量,integer 表示整型,real 表示浮點型,text 表示文本類型,blob 表示二進制類型。此外,使用了 primary key 將 id 設置為主鍵,并且用 autocrement 關鍵字表示 id 列是自增長的。
  • onCreate 方法中有調用了 SQLiteDatabaseexecSQL 方法去執行這條建表語句。

調用自己的幫助類

創建一個活動 SQLiteActivity,其布局內有一個按鈕,點擊即可創建 Student.db 數據庫:

public class SQLiteActivity extends AppCompatActivity {private MyDatabaseHelper myDatabaseHelper;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.sqlite_layout);myDatabaseHelper = new MyDatabaseHelper(this, "Student.db", null, 1);Button button_create = findViewById(R.id.button_create);button_create.setOnClickListener((View v)->{myDatabaseHelper.getWritableDatabase();Toast.makeText(this, "創建數據庫成功", Toast.LENGTH_LONG).show();});}
}
  • 第一次點擊按鈕時,會檢測到當前程序并沒有 Student.db 這個數據庫,于是會創建該數據庫并調用 MyDatabaseHelper 中的 onCreate 方法,得以創建 Student 表。
  • 之后點擊按鈕就不會再調用 MyDatabaseHelper 中的 onCreate 方法了,因為 Student.db 已經存在了。

布局文件 sqlite_layout.xml

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/button_create"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="create database"/>
</LinearLayout>

在這里插入圖片描述

運行結果:

create succeeded 只會在數據庫首次創建時出現:
在這里插入圖片描述

創建數據庫成功 會在每次點擊按鈕后出現:
在這里插入圖片描述

查看數據庫和表的創建情況

在環境變量中添加好 platform-tools 后:
在這里插入圖片描述
在這里插入圖片描述
打開 cmd,輸入 adb shell 進入設備控制臺:
在這里插入圖片描述
通過 su 獲取管理員權限,否則無法進入 /data/data/<packagename>/databases/ 路徑:
在這里插入圖片描述
通過 cd 命令進入數據庫文件所在目錄:
在這里插入圖片描述
該目錄下有兩個數據庫文件,一個是我們創建的 Student.db ;一個是為了讓支持事務的臨時日志文件 Student.db-journal

打開數據庫:
在這里插入圖片描述
查看數據庫中有哪些表:
在這里插入圖片描述
PS:android_metadata 是每個數據庫自動生成的。

查看建表語句:
在這里插入圖片描述
通過 .exit.quit 退出數據庫:
在這里插入圖片描述


補全 onUpgrade() 方法

該方法用于升級數據庫,目前項目中已經有了一張 Student 表用于存放學生的各種詳細數據,如果想再添加一張 Class 表用于記錄學生的班級,怎么做呢?

將建表語句添加到自己的幫助類 MyDatabaseHelper 中:
在這里插入圖片描述
該如上圖所示在 onCreate 階段執行一次 Class 的建表語句嗎?

不是的,正如上一個實例中,數據庫創建完成后,我們再點擊按鈕,只會彈出 創建數據庫成功 而不會彈出 create succeeded 一樣,兩者的根本原因都是 onCreate 方法只會在創建數據庫時執行一次,創建成功后不會再次執行。

因此無法在 Student.db 存在的情況下通過 onCreate 方法添加新表,而應通過 onUpgrade 方法添加新表。 具體做法如下:

@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {//  如果數據庫中存在 Student 表或 Class表,就將他們刪除。db.execSQL("drop table if exists Student");db.execSQL("drop table if exists Class");// 然后調用 onCreate 方法重新創建onCreate(db);}

PS:之所以 不跳過刪除已有表直接調用 onCreate ,是因為 創建表時如果該表已存在會報錯

接下來重新調用 SQLiteOpenHelper 的構造方法,使第四個參數——數據庫版本號大于之前傳入的 1 即可讓 onUpgrade 執行:
在這里插入圖片描述

運行結果:

在這里插入圖片描述

PS:使用 AS 時也可以通過一下流程查看數據庫及建表情況:
在這里插入圖片描述
在這里插入圖片描述


增刪查改

CRUD 操作當然可以通過 SQL 語言實現,但 Android 也提供了一系列輔助方法,前面提到 getReadableDatabasegetWriteableDatabase 方法是會返回一個 SQLiteDatabase 對象,借助這個對象就可以對數據進行操作了。

增:SQLiteDatabase.insert()

該方法有三個參數:

  1. 表名
  2. 用于在未指定添加數據的情況下給某些可為空的列自動賦值為 null
  3. ContentValues 對象,它提供了一系列的 put 方法重載,用于向 ContentValues 中添加數據,只需要將表中的每個列名待添加數據傳入即可。

在布局中添加了一個按鈕用于增加數據:
在這里插入圖片描述
SQLiteActivityonCreate 方法中添加以下代碼:
在這里插入圖片描述

點擊兩次按鈕的運行結果:

在這里插入圖片描述
在這里插入圖片描述
兩張表各添加了兩行數據。


改:SQLiteDatabase.update()

該方法有四個參數:

  1. 表名;
  2. ContentValues 對象;
  3. 第三個、第四個參數用于約束更新某一行或者某幾行的數據,不指定的話默認更新所有行

在布局中添加了一個按鈕用于更新數據:
在這里插入圖片描述
SQLiteActivityonCreate 方法中添加以下代碼:

        Button button_update = findViewById(R.id.button_update);button_update.setOnClickListener((View v)->{SQLiteDatabase db = myDatabaseHelper.getReadableDatabase();ContentValues values = new ContentValues();// 第一條數據values.put("weight", 90);values.put("name", "zj");db.update("Student", values, "id = ?", new String[] {"2"});// 第二條數據values.put("class_name", "電子");values.put("class_num", 183);db.update("Class", values, "id = ?", new String[] {"1"});Toast.makeText(this, "更新完成", Toast.LENGTH_LONG).show();});

以第一條數據為例:

  • values 用以更新 weightname 兩項屬性的值;
  • 第三、第四個參數指定更新 id=2 的行。

點擊按鈕后的運行結果:

在這里插入圖片描述
在這里插入圖片描述


刪:SQLiteDatabase.delete()

該方法接受三個參數:

  1. 表名;
  2. 第二、三個用于約束刪除某幾行的數據,不指定則刪除所有行

SQLiteActivityonCreate 方法中添加以下代碼:

        Button button_delete = findViewById(R.id.button_delete);button_delete.setOnClickListener((View v)->{SQLiteDatabase db = myDatabaseHelper.getReadableDatabase();db.delete("Student", "weight < ?", new String[] {"100"});Toast.makeText(this, "刪除完成", Toast.LENGTH_LONG).show();});
  • 刪除 weight < 100 的行。

點擊按鈕后的運行結果:

在這里插入圖片描述


查:SQLiteDatabase.query()

該方法比前三個復雜一些,最短的一個重載方法也需要傳入七個參數:

  1. 表名;
  2. 用于指定查詢哪幾列;
  3. 三四個參數用于約束查詢某幾行的數據,不指定則默認查詢所有行的數據
  4. 第五個參數用于指定需要去 group by 的列,不指定則不對查詢結果進行分組
  5. 第六個參數用于對 group by 之后的數據進一步過濾;
  6. 第七個參數用于指定查詢結果的排序方式。

在這里插入圖片描述
調用該方法后會返回一個 Cursor 對象,查詢到的所有數據都將從這個對象中取出。

        Button button_query = findViewById(R.id.button_query);button_query.setOnClickListener((View v)->{SQLiteDatabase db = myDatabaseHelper.getReadableDatabase();// 查詢 Class 表中所有數據Cursor cursor = db.query("Class", null, null, null,null, null, null);if(cursor.moveToFirst()){do{String res = "";res += cursor.getString(cursor.getColumnIndex("class_name")) + " ";res += cursor.getString(cursor.getColumnIndex("class_num"));Toast.makeText(this, res, Toast.LENGTH_LONG).show();}while(cursor.moveToNext());}cursor.close();});
  • query方法 首參數設置為 Class,其余參數設置為 null,表示查詢 Class表 所有數據。
  • 調用 moveToFirst方法 將數據指針移動到第一行的位置;
  • 通過 getColumnIndex方法 獲取位置索引以遍歷每一行數據,并將之通過 Toast 打印到屏幕上;
  • 通過 moveToNext方法 移動數據指針遍歷下一行數據,如果指針已經到達了數據指針集的尾后位置,此方法將返回 false

通過 SQL語句 實現增刪查改

除了查詢語句通過 db.rawQuery() 執行之外,其他三種操作都可以通過 db.execSQL() 執行。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443700.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443700.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443700.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Android入門(13)| Android權限 與 內容提供器

文章目錄普通權限與危險權限運行時申請權限內容提供器運用安卓封裝好的內容提供器自實現的內容提供器概念實現普通權限與危險權限 主要用于不同應用程序之間在保證被訪數據的安全性的基礎上&#xff0c;實現數據共享的功能。 在 Android 6.0 開始引入了運行時權限的功能&…

Java實現身份證號碼的驗證,JAVA后臺驗證身份證號碼

代碼如下&#xff1a; package cn.gov.csrc.util;/*** 18 位身份證驗證器* * author admin* */ public class IDCard {final int[] wi { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 };final int[] vi { 1, 0, X, 9, 8, 7, 6, 5, 4, 3, 2 };private int[] ai n…

Android入門(14)| 通知

文章目錄創建通知點擊效果其它小功能實例創建通知 創建通知的步驟&#xff1a; 管理通知的 NotificationManager&#xff0c;通常通過當前 Context 的 getSystemService() 獲取實例。它接受一個字符串參數用于確定獲取系統的什么服務。Android 8.0(O) 版本后需要通知通道&…

Android開發(3) | 權限和內容提供器的應用——調用相機和相冊

文章目錄拍照并保存到 ImageView 控件布局文件 notice_layout.xml按鈕 button_takePhoto 的點擊操作隱式 Intent 啟動后的回調AndroidManifest.xml從相冊選取照片并在 ImageView 控件中顯示布局文件 notice_layout.xml按鈕 button_takePhoto 的點擊操作自定義打開相冊的方法 op…

Android開發(4) | 系統權限、MediaPlayer類 和 VideoView類 的應用——播放多媒體文件

文章目錄MediaPlayer類播放音頻的實例VideoView類播放視頻的實例MediaPlayer類 對多種格式的音頻文件提供了全面的控制方法&#xff1a; 如何獲得MediaPlayer實例&#xff1f; 通過構造函數&#xff1a; MediaPlayer mp new MediaPlayer();調用 MediaPlayer.create() 方法&…

Android入門(15)| 網絡

文章目錄WebViewHTTP使用HttpURLConnection使用OkHttp封裝網絡操作封裝HttpURLConnection封裝OkHttpWebView WebView 可以在 應用程序中&#xff08;而不是瀏覽器&#xff09; 展示一些網頁。 布局文件 web_layout.xml&#xff1a; <LinearLayoutxmlns:android"http…

Java-單例模式

單例模式相信大家都不陌生&#xff0c;在JAVAEE應用中&#xff0c;單例模式是一種應用非常廣泛的設計模式&#xff0c;應用中許多組件都只需要單個實例&#xff0c;下面介紹單例模式。 使用單例模式的優點&#xff1a; 1.減少創建JAVA實例所帶來的系統開銷。 2.便于系統跟蹤單…

Android入門(16)| 服務

文章目錄概念Android 多線程繼承 Thread繼承 Runable 接口匿名類異步消息處理AsyncTask使用服務框架啟動/停止服務綁定/解綁服務服務的生命周期前臺服務IntentService完整版下載示例下載過程的回調接口&#xff1a;DownloadListener繼承 AsyncTask 實現下載功能&#xff1a;Dow…

2020德勤面試開始了嗎_2020國考面試開始,近期面試公告匯總,附結構化小組面試流程...

2020年國家公務員考試面試環節逐步恢復考試&#xff0c;各個招錄部門已經發布面試考察公告&#xff0c;對于進入面試環節的國考考生來說&#xff0c;有必要了解近期國考面試的招錄動態&#xff0c;提前做好面試準備。2020國考國家統計局機關面試面試確認&#xff1a;請進入面試…

項目積壓需求項目計劃_需求變更頻繁,項目經理如何做好需求管理?

項目實施過程中&#xff0c;項目經理常常面臨一個重大挑戰——需求變更。需求變更無處不在&#xff0c;市場條件變化、新業務出現、戰略目標調整、客戶需求修改、資源限制等&#xff0c;都會造成需求變更。需求變更會影響項目的時間、成本和質量&#xff0c;對整個項目和團隊成…

Android | Sensor.TYPE_ORIENTATION被廢棄后的解決辦法

文章目錄概述getOrientation 方法根據 旋轉矩陣R 獲取 設備旋轉弧度getRotationMatrix 方法根據 地磁場、加速度傳感器對象 獲取 旋轉矩陣R代碼參考資料概述 Sensor.TYPE_ORIENTATION 常數在 API 8 中已棄用&#xff0c;官方推薦使用 SensorManager.getOrientation() 替代。關…

【JAVA 開發小問題】 | String操作合集

文章目錄截取特定兩個字符之間的字符串截取特定兩個字符之間的字符串 利用正則表達式&#xff0c;圖片來源

uniapp 刷新后數據都沒有了_環境溫度傳感器都沒有連接,竟然還會有數據?

福田歐曼GTL(福康發動機、康明斯2880系統)匹配ECoffit尿素泵●故障現象&#xff1a;OBD故障燈點亮&#xff0c;不燒尿素&#xff0c;油耗高&#xff0c;動力不足●故障碼&#xff1a;●維修分析&#xff1a;①故障指出加熱器問題&#xff0c;摸下尿素箱溫度&#xff0c;發現燙手…

Android | 再探 RecyclerView 之名詞解析

文章目錄Adapter、ViewHolderchild viewLayoutManagerRecyclerScrapDirtyIndexPositionlayout position 和 adapter position四級緩存瀏覽本文前推薦先閱讀 Android入門&#xff08;九&#xff09;| 滾動控件 ListView 與 RecyclerView Adapter、ViewHolder Adapter: A subcla…

Linux學習:第一章-Linux簡介

一 UNIX發展史1 1965年&#xff0c;美國麻省理工學院&#xff08;MIT&#xff09;、通用電氣公司&#xff08;GE&#xff09;及AT&T的貝爾實驗室聯合開發Multics工程計劃&#xff0c;其目標是開發一種交互式的具有多道程序處理能力的分時操作系統&#xff0c;但因Multics追…

尼爾機器人技能快捷鍵_《尼爾機械紀元》連招操作技巧

《尼爾機械紀元》中的每個角色都可以裝備一個輕武器和一個重武器&#xff0c;技能招式也很豐富&#xff0c;下面為大家帶來了《尼爾機械紀元》連招操作技巧&#xff0c;希望對你們有所幫助。連擊技能展示視頻視頻原址&#xff1a;點擊進入基本沒有什么太難的連段&#xff0c;只…

保姆級教學!Xcode 配置 OpenGL 環境

文章目錄GLFW獲取 GLFWGLAD獲取 GLAD在 Xcode 中配置下載好的 GLFW 和 GLAD配置流程檢測是否配置成功無關配置的題外話——Xcode 下安全的刪除移動操作GLFW Graphics Library Framework&#xff08;圖形庫框架&#xff09;&#xff0c;可以讓我們通過其封裝好的 通用API 來正確…

Android入門(17)| 百度提供的 Android定位SDK

文章目錄配置百度提供的 Android定位SDK用于發布的 SHA1用于測試的 SHA1使用百度定位實例配置百度提供的 Android定位SDK 詳情參見官方文檔&#xff0c;這里僅對獲取 SHA1 做詳細介紹&#xff1a; 用于發布的 SHA1 用于測試的 SHA1 使用百度定位實例 public class LocationAc…

ios 不被遮擋 陰影_為何你沒見到日環食?你不知道的天象常識原來還有這么多 | 返樸...

關注風云之聲提升思維層次導讀說好的日環食呢&#xff0c;為什么上周很多人只等到了日偏食?日食月食的時間和種類是怎么預測的?你真的弄懂了各種日食和月食的成因嗎&#xff1f;你了解它們有什么區別和聯系&#xff0c;又遵循什么樣的時間規律嗎? 日食和月食發生的頻率一樣嗎…

初識貝塞爾(bezier)曲線

文章目錄資料援引貝塞爾曲線的用途一階貝塞爾&#xff08;bezier&#xff09;曲線二階貝塞爾&#xff08;bezier&#xff09;曲線三階貝塞爾&#xff08;bezier&#xff09;曲線高階貝塞爾&#xff08;bezier&#xff09;曲線三階貝塞爾曲線求插值&#xff08;Slerp&#xff09…