資料儲存與存取之-SharedPreferences保存使用者偏好參數
本節引言:
本節給大家介紹的是第二種儲存使用者資料的方式,使用SharedPreferences(保存使用者偏好參數)保存數據, 當我們的應用程式想要保存使用者的一些偏好參數,例如是否自動登陸,是否記住帳號密碼,是否在Wifi下才能 連網等相關資訊,如果使用資料庫的話,顯得有點大材小用了!我們把上面這些配置資訊稱為使用者的偏好 設置,就是用戶偏好的設置,而這些配置資訊通常是保存在特定的文件中!例如windows使用ini文件, 而J2SE中使用properties屬性檔與xml檔來保存軟體的設定資訊;而在Android我們通常會使用 一個輕量級的儲存類別-SharedPreferences來保存使用者偏好的參數! SharedPreferences也是使用xml檔, 然後類似於Map集合,使用鍵-值的形式來儲存資料;我們只需要呼叫SharedPreferences的getXxx(name), 就可以根據鍵獲得對應的值!使用起來很方便!
1.SharedPreferences使用範例:
#使用流程圖:
實作程式碼範例:
執行效果圖:
#流程是輸入帳號密碼後點選登入,將資訊儲存到SharedPreference檔案, 然後重啟app,看到資料已經顯示在文字方塊中了
另外儲存後,我們可以在File Expoler開啟data/data/<套件名稱>可以看到在shared_prefs目錄下 產生了一個xml檔(因為N5沒root,這裡找了以前的效果圖):
#點選匯出到桌面可以看到裡面的內容:
程式碼實作:
佈局檔案activity_main.xml的寫:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MyActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="用户登陆" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="请输入用户名" /> <EditText android:id="@+id/editname" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="用户名" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请输入密码" /> <EditText android:id="@+id/editpasswd" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="密码" android:inputType="textPassword" /> <Button android:id="@+id/btnlogin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="登录" /> </LinearLayout>
寫簡單的SP工具類別:SharedHelper.java:
/** * Created by Jay on 2015/9/2 0002. */ public class SharedHelper { private Context mContext; public SharedHelper() { } public SharedHelper(Context mContext) { this.mContext = mContext; } //定义一个保存数据的方法 public void save(String username, String passwd) { SharedPreferences sp = mContext.getSharedPreferences("mysp", Context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.putString("username", username); editor.putString("passwd", passwd); editor.commit(); Toast.makeText(mContext, "信息已写入SharedPreference中", Toast.LENGTH_SHORT).show(); } //定义一个读取SP文件的方法 public Map<String, String> read() { Map<String, String> data = new HashMap<String, String>(); SharedPreferences sp = mContext.getSharedPreferences("mysp", Context.MODE_PRIVATE); data.put("username", sp.getString("username", "")); data.put("passwd", sp.getString("passwd", "")); return data; } }
最後是MainActivity.java#實作相關邏輯:
public class MainActivity extends AppCompatActivity { private EditText editname; private EditText editpasswd; private Button btnlogin; private String strname; private String strpasswd; private SharedHelper sh; private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mContext = getApplicationContext(); sh = new SharedHelper(mContext); bindViews(); } private void bindViews() { editname = (EditText)findViewById(R.id.editname); editpasswd = (EditText)findViewById(R.id.editpasswd); btnlogin = (Button)findViewById(R.id.btnlogin); btnlogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { strname = editname.getText().toString(); strpasswd = editpasswd.getText().toString(); sh.save(strname,strpasswd); } }); } @Override protected void onStart() { super.onStart(); Map<String,String> data = sh.read(); editname.setText(data.get("username")); editpasswd.setText(data.get("passwd")); } }
2.讀取其他應用程式的SharedPreferences
#核心: 取得其他app的Context,而這個Context代表存取該app的全域資訊的介面,而決定應用的唯一標識 是應用的套件名稱,所以我們可以透過應用程式包名來獲得對應app的Context 另外有一點要注意的是:其他應用的SP檔案是否能被讀寫的前提就是SP檔案是否指定了可讀或 可寫的權限,我們上面創建的是MODE_PRIVATE的就不行了~所以說你像讀別人的SP裡的數據, 很難,另外,一些關鍵的訊息,像是密碼存到SP裡,通常都是會做加密的,所以只能自己寫自己玩~ 等下會講下常用的MD5加密方法!
實作流程圖:
#程式碼範例:
運行效果圖:
程式碼實作:
我們讀取SP的操作放在MainActivity.java中完成,點擊按鈕後讀取SP,並透過Toast顯示出來:
public class MainActivity extends AppCompatActivity { private Context othercontext; private SharedPreferences sp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnshow = (Button) findViewById(R.id.btnshow); btnshow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //获得第一个应用的包名,从而获得对应的Context,需要对异常进行捕获 try { othercontext = createPackageContext("com.jay.sharedpreferencedemo", Context.CONTEXT_IGNORE_SECURITY); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } //根据Context取得对应的SharedPreferences sp = othercontext.getSharedPreferences("mysp", Context.MODE_WORLD_READABLE); String name = sp.getString("username", ""); String passwd = sp.getString("passwd", ""); Toast.makeText(getApplicationContext(), "Demo1的SharedPreference存的\n用户名为:" + name + "\n密码为:" + passwd, Toast.LENGTH_SHORT).show(); } }); } }
3.使用MD5對SharedPreference的重要資料進行加密
##嘿嘿,上面我們這樣直接把帳號密碼存到sp裡,如果沒root的手機,別的應用程式倒無法存取手機, 如果root了,然後資料給其他應用程式取得到,然後造成了一些後果,這...就不怪我們了,哈哈, 誰叫你root了~,這鍋我們不背,的確是這樣!但身為有責任感的APP開發人員,我們總不能 這樣是吧,我們可以使用一些加密演算法來加密使用者密碼,另外我們一般加密的都是使用者密碼! 下面我們簡畫個簡單的圖幫助大家理解下加密的處理的流程:1.簡單的加密處理流程
流程圖如下:
流程圖解析:
- Step 1.用戶註冊帳號密碼,帳號密碼校驗後(帳號是否重複,密碼位數 > 6位元等), 即帳號密碼有效,註冊成功後,我們提交給伺服器的帳號,以及本地加密過的密碼!
- Step 2.伺服器端將使用者提交的帳號,加密過的密碼儲存到服務端的資料庫中,也就是服務 端並不會保存我們的明文密碼(原始)密碼!
- Step 3.說回客戶端,如果註冊成功或登陸成功,你想保存帳號密碼到SP中,儲存的的密碼 也需要走一趟加密流程!即明文密碼->加密,再儲存!如果不保存,每次請求的時候,明文密碼 也要走一趟家裡流程,然後拿著加密後的密碼來請求伺服器!
- Step 4.伺服器驗證帳號以及加密密碼,成功,分配客戶端一個session標識,後續客戶端可以拿著 這個session來存取服務端提供的相關服務!
嘿嘿,了解吧,加密的方法有很多種,小豬也不是這方面的高玩,以前使用過的加密方法是MD5 加密,本節也跟大家簡單介紹一下這個MD5加密,以及示範下用法~
2.MD5簡單介紹:
1)MD5是什麼鬼? :
答:Message Digest Algorithm MD5(中文名稱為訊息摘要演算法第五版)為電腦安全領域廣泛 使用的一種雜湊函數,用以提供訊息的完整性保護-摘自《百度百科》 簡單點說就是一種加密演算法,可以將一個字串,或是文件,壓縮包,執行MD5加密後, 就可以生產一個固定長度為128bit的串!這個串基本上唯一!另外我們都知道:一個十六進制 需要用4個bit來表示,那麼對應的MD5的字串長度就為:128 / 4 = 32位元了!另外可能 你看到一些md5是16位的,只是將32位MD5碼去掉了前八位以及後八位!不信麼,我們來試試 百度一下:md5線上解密,第一個:http://www.cmd5.com/
2)MD5能破解嗎?
答案:MD5不可逆,就是說沒有對應的演算法,無法從產生的md5值逆向得到原始資料! 當然暴力破解除外,簡單的MD5加密後可以查MD5庫~
3)MD5值唯一嗎?
答案:不唯一,一個原始資料只對應一個MD5值,但一個MD5值可能對應多個原始資料!
3.MD5加密實作例子:
其實網路上有很多寫好的MD5的例子,百度或Google一搜一大堆,這裡提供下小豬用的MD5加密工具類!
Md5Util.java:
/** * Created by Jay on 2015/9/2 0002. */ public class MD5 { public static String getMD5(String content) { try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(content.getBytes()); return getHashString(digest); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } private static String getHashString(MessageDigest digest) { StringBuilder builder = new StringBuilder(); for (byte b : digest.digest()) { builder.append(Integer.toHexString((b >> 4) & 0xf)); builder.append(Integer.toHexString(b & 0xf)); } return builder.toString(); } }
MainActivity.java直接呼叫getMD5這個靜態方法:
Log.e("HeHe", MD5.getMD5("呵呵"));
我們可以看到Logcat上印出:
這就是加密過後的呵呵了,我們可以把這串密文拷貝到上面這個md5的線上解密網站:
嘿嘿,果然,只是這樣加密一次,就直接破解了,有點不安全的樣子,那就加密100次咯, 就是將加密後的字串再加密,重複100次,我們在原先的基礎上加個加密一百次的方法:
public static String getMD5x100(String content){ String s1 = content; for(int i = 0;i < 100;i++){ s1 = getMD5(s1); } return s1; }
然後呼叫下,發現列印這個的Log:
複製介面網站上:
#好的,在裝B成功~
4.SharedPreference工具類:
每次都要自行實例化SP相關的類,肯定很麻煩,這裡貼個SP的工具類,大家可以貼到 在自己的專案中,工具類別來自鴻洋大神的blog~
SPUtils.java
package com.jay.sharedpreferencedemo3; import android.content.Context; import android.content.SharedPreferences; import java.util.Map; /** * Created by Jay on 2015/9/2 0002. */ public class SPUtils { /** * 保存在手机里的SP文件名 */ public static final String FILE_NAME = "my_sp"; /** * 保存数据 */ public static void put(Context context, String key, Object obj) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); if (obj instanceof Boolean) { editor.putBoolean(key, (Boolean) obj); } else if (obj instanceof Float) { editor.putFloat(key, (Float) obj); } else if (obj instanceof Integer) { editor.putInt(key, (Integer) obj); } else if (obj instanceof Long) { editor.putLong(key, (Long) obj); } else { editor.putString(key, (String) obj); } editor.commit(); } /** * 获取指定数据 */ public static Object get(Context context, String key, Object defaultObj) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE); if (defaultObj instanceof Boolean) { return sp.getBoolean(key, (Boolean) defaultObj); } else if (defaultObj instanceof Float) { return sp.getFloat(key, (Float) defaultObj); } else if (defaultObj instanceof Integer) { return sp.getInt(key, (Integer) defaultObj); } else if (defaultObj instanceof Long) { return sp.getLong(key, (Long) defaultObj); } else if (defaultObj instanceof String) { return sp.getString(key, (String) defaultObj); } return null; } /** * 删除指定数据 */ public static void remove(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.remove(key); editor.commit(); } /** * 返回所有键值对 */ public static Map<String, ?> getAll(Context context) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE); Map<String, ?> map = sp.getAll(); return map; } /** * 删除所有数据 */ public static void clear(Context context) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); editor.clear(); editor.commit(); } /** * 检查key对应的数据是否存在 */ public static boolean contains(Context context, String key) { SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE); return sp.contains(key); } }
5.程式碼下載:
SharedPreferenceDemo.zip:下載SharedPreferenceDemo.zipSharedPreferenceDemo2.zip:下載SharedPreferenceDemo2.zip#1Share:下載SharedPreferenceDemo2.zip#SharedSharePrefermodShare :
下載SharedPreferenceDemo3.zip#本節小結:好的,關於Android儲存資料的第二種方式:SharedPreference保存使用者偏好參數的內容就這麼多, 應該可以滿足你日常開發使用SP的需求,如果有任何遺漏,歡迎提出,謝謝~