Android載入使用者頭像的功能實現
阿新 • • 發佈:2018-12-19
載入使用者頭像的過程是,首先從本地檢視是否儲存了使用者的頭像,如果有,則從本地讀取後加載到ImageView中,如果沒有,則去伺服器下載頭像儲存到本地,並載入。
public void initData() { super.initData(); SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(MyApplication.getContext()); final String u_id = pref.getString("u_id", ""); // 聯網請求個人中心的資料 getDataFromServer(u_id); }
在Fragment的onCreateView()中呼叫initData()方法,該方法使用使用者的id去聯網請求個人中心的資料。
private void getDataFromServer(String u_id) { String address = Constant.PERSONAL_CENTER_URL; HttpUtil.sendPostRequest(address, u_id, new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { if (null == response.body()) { return; } String responseText = URLDecoder.decode(response.body().string(), "utf-8"); // 解析資料 processData(responseText); } }); }
在 getDataFromServer()方法中呼叫了自己寫的HttpUtil工具類中的方法去請求伺服器資料。這個HttpUtil的方法如下:
public static void sendPostRequest(String address, String json, okhttp3.Callback callback) { OkHttpClient client = new OkHttpClient(); RequestBody requestBody = RequestBody.create(JSON, json); Request request = new Request.Builder().url(address).post(requestBody).build(); client.newCall(request).enqueue(callback); }
下面進入解析資料的部分,取出客戶端返回的資料,用Gson轉換為PersonMsg物件後取出User,用這個User中的資料來更新介面。從User中取出使用者id,利用id去sd卡中獲取到壓縮後的Bitmap點陣圖(這裡是個大坑,不壓縮很容易造成記憶體溢位OOM的錯誤,填坑請看我另一篇博文:解決使用Bitmap造成OOM記憶體溢位的問題)。如果取出的Bitmap不為空,則表示從本地載入到了使用者頭像,否則就從伺服器請求頭像資料。
private void processData(String response) {
final PersonMsg personMsg = Utility.handlePersonMsgResponse(response);
if (null == personMsg) {
return;
}
final User user = personMsg.getUser();
// 更新介面
if (getActivity() == null) {
return;
}
final Bitmap bitmap = ImageUtils.getPhotoFromStorage(user.getU_id());
if (bitmap != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Log.i("載入使用者頭像", "本地載入頭像");
Glide.with(getActivity()).load(bitmap).into(mIvPhoto);
}
});
} else {
// 從伺服器請求頭像資料
asyncGet(Constant.BASE_PHOTO_URL + user.getU_photo());
}
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mTvNick.setText(user.getU_nick());
mTvGain.setText(String.valueOf(user.getU_gain()));
boolean male = user.getU_sex() == 1;
if (male) {
Glide.with(getActivity()).load(R.drawable.ic_male).into(mIvSex);
} else {
Glide.with(getActivity()).load(R.drawable.ic_female).into(mIvSex);
}
}
});
// 儲存使用者資料到本地資料庫
saveToDatabase(personMsg);
}
附上用到的ImageUtils.getPhotoFromStorage()的程式碼部分,這部分程式碼就是從sd卡中取出圖片並壓縮的過程:
public static Bitmap getPhotoFromStorage(String u_id) {
String photoPath = android.os.Environment.getExternalStorageDirectory() + "/photo/" + u_id + ".jpg";
return getBitmapFromPath(photoPath, 80, 80);
}
// 從路徑獲取Bitmap
public static Bitmap getBitmapFromPath(String imgPath, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imgPath, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
//避免出現記憶體溢位的情況,進行相應的屬性設定。
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inDither = true;
return BitmapFactory.decodeFile(imgPath, options);
}
public static int calculateInSampleSize( //參2和3為ImageView期待的圖片大小
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// 圖片的實際大小
final int height = options.outHeight;
final int width = options.outWidth;
//預設值
int inSampleSize = 1;
//動態計算inSampleSize的值
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height/2;
final int halfWidth = width/2;
while( (halfHeight/inSampleSize) >= reqHeight && (halfWidth/inSampleSize) >= reqWidth){
inSampleSize *= 2;
}
}
return inSampleSize;
}
從伺服器獲取圖片的程式碼如下:
private void asyncGet(String imgUrl) {
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder().get()
.url(imgUrl)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
if (response.body() != null) {
byte[] bytes = response.body().bytes();
final Bitmap bitmap = ImageUtils.getBitmapFromByte(bytes, 70, 70);
ImageUtils.savePhotoToStorage(bitmap, pref.getString("u_id", ""));
if (getActivity() != null) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Glide.with(getActivity()).load(bitmap).into(mIvPhoto);
}
});
Log.i("載入使用者頭像", "從伺服器載入頭像");
}
}
}
}
});
}
伺服器返回的是圖片的位元組陣列,我將其轉換為壓縮後的Bitmap,並將其儲存到sd卡,下次讀取時就可直接從sd卡中獲取。
// 儲存圖片到sd卡
public static void savePhotoToStorage(Bitmap photoBitmap, String u_id) {
//更改的名字
String photoName = u_id + ".jpg";
String photoPath = android.os.Environment.getExternalStorageDirectory() +
"/photo";
File fileDir = new File(photoPath);
if(!fileDir.exists()){
fileDir.mkdirs();
}
FileOutputStream fos = null;
File photoFile = null;
try{
//重新命名並儲存
photoFile = new File(photoPath, photoName);
photoFile.createNewFile();
fos = new FileOutputStream(photoFile);
photoBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static Bitmap getBitmapFromByte(byte[] imgByte, int reqWidth, int reqHeight) {
InputStream input = null;
Bitmap bitmap = null;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);;
input = new ByteArrayInputStream(imgByte);
SoftReference softRef = new SoftReference(BitmapFactory.decodeStream(
input, null, options));
bitmap = (Bitmap) softRef.get();
if (imgByte != null) {
imgByte = null;
}
try {
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
以上整個程式碼中融入了我自己專案處理的一些邏輯,實際使用中還要根據自己專案的需要來適當更改。