加载用户头像的过程是,首先从本地查看是否存储了用户的头像,如果有,则从本地读取后加载到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;
}
以上整个代码中融入了我自己项目处理的一些逻辑,实际使用中还要根据自己项目的需要来适当更改。