文章目錄
- 資料存儲與通路之——SharedPreferences儲存使用者偏好參數
- 本節引言
- 1.SharedPreferences使用示例
- 2.讀取其他應用的SharedPreferences
- 3.使用MD5對SharedPreference的重要資料進行加密
- 3.1 簡單的加密處理流程
- 3.2 MD5簡單介紹
- 3.3 MD5加密實作例子
- 4.SharedPreference工具類:
資料存儲與通路之——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:
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開發人員,我們總不能 這樣是吧,我們可以使用一些加密算法對使用者密碼進行加密,另外我們一般加密的都是使用者密碼! 下面我們簡畫個簡單的圖幫助大家了解下加密的處理的流程:
3.1 簡單的加密處理流程
流程圖如下:
流程圖解析:
- Step 1.使用者新增賬號密碼,賬号密碼校驗後(賬号是否重複,密碼位數 > 6位等), 即賬号密碼有效,注冊成功後,我們送出給伺服器的賬号,以及本地加密過的密碼!
- Step 2.伺服器端将使用者送出的賬号,加密過的密碼儲存到服務端的資料庫中,也就是服務 端并不會儲存我們的明文密碼(原始)密碼!
- Step 3.說回用戶端,如果注冊成功或者登陸成功,你想儲存賬号密碼到SP中,儲存的的密碼 也需要走一趟加密流程!即明文密碼——>加密,再儲存!如果不儲存,每次請求的時候,明文密碼 也要走一趟家裡流程,然後拿着加密後的密碼來請求伺服器!
- Step 4.伺服器驗證賬号以及加密密碼,成功,配置設定用戶端一個session辨別,後續用戶端可以拿着 這個session來通路服務端提供的相關服務!
嘿嘿,了解了吧,加密的方法有很多種,小豬也不是這方面的高玩,以前使用過的加密方法是MD5 加密,本節也給大家簡單介紹一下這個MD5加密,以及示範下用法~
傳回頂部
3.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.3 MD5加密實作例子
其實網上有很多寫好的MD5的例子,百度或者谷歌一搜一大堆,這裡提供下小豬用的MD5加密工具類!
Md5Util.java:
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~
package com.jay.sharedpreferencedemo3;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Map;
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);
}
}