Android头像加载框架

好久没更新博客,最近在完成实习任务,自己研究出了一套头像加载机制,虽然谈不上高大上,但是使用起来确实比较方便,可以用在任何Android应用中需要头像的地方。


先说一下这个头像加载的思路:

      首先加载本地
      如果本地加载成功
           检查本地头像是不是最新的,如果是最新的,不操作,如果不是最新的,加载网络最新
      如果本地加载失败
          加载网络最新头像


当然实现这个逻辑比较方便,但是考虑到代码的耦合度以及面向对象的单一原则,我单独写了加载头像的类。


在贴上加载头像源码前,需要说明一下上传头像的设计:

上传头像给服务器,首先会给头像命名,命名规则采用随机码,这样两次任意的上传头像的名称都不一样,后台数据库存取头像则存取头像图片的绝对路径,比如每次上传成功之后都存在服务器的linux目录的/opt/headImage/xxxx.jpg。xxxx为生成的随机名称。


上传图片的过程中,会在本地也缓存一份,命名为head.jpg。

还会在本地缓存一份最新生成的随机码,也就是头像的名称。



这样,首先加载本地头像,会先检查缓存目录下有没有head.jpg。如果有,先在ImageView上显示出来,显示出来不能确定是不是最新的,所以这时候还要请求服务器后台,服务器头像的最新名称,检查与本地缓存的名称是否一致,如果不一致,还要加载服务器的头像。


大概逻辑就是这样。


现在贴上源码

package com.example.ev.manage;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;
import android.widget.ImageView;

import com.example.ev.R;
import com.example.ev.utils.HttpUtil;

import org.json.JSONObject;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;


/**
 * 头像加载框架 v1.1
 * 用于加载头像
 * 回调接口可以返回最新的图像bitmap
 * @author 钱海峰
 */
public class HeadImgManager {

    private static final String NETWORK_ERROR = "NETWORK_ERROR";
    private String TAG = "HeadImgManager";
    private Activity mActivity;
    private SharedPreferences mSpData;
    private ImageView mIvPhoto;
    private String path;
    private String mUserAccount;
    private String imgFileName;// = mUserAccount + "_head.jpg";
    private HeadImgManager(Activity ac,ImageView imageView,String mUserAccount) {
        mActivity = ac;
        mSpData = mActivity.getSharedPreferences("data", Context.MODE_PRIVATE);
        mIvPhoto = imageView;
        this.path  = getDiskCacheDir(mActivity) + "EChargerHead/";//路径写死
        this.mUserAccount = mUserAccount;
        imgFileName = mUserAccount + "_head.jpg";
    }

    private static HeadImgManager instance;//单例模式

    public static HeadImgManager getInstance(Activity ac,ImageView imageView,String mUserAccount) {
        if(instance == null) {
            instance = new HeadImgManager(ac,imageView,mUserAccount);

            return instance;
        } else {
            instance.mActivity = ac;
            instance.mIvPhoto = imageView;
            instance.mUserAccount = mUserAccount;
            instance.imgFileName = mUserAccount + "_head.jpg";
            return instance;
        }
    }
    private   String getDiskCacheDir(Context context) {
        boolean externalStorageAvailable = Environment
                .getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
        final String cachePath;
        if (externalStorageAvailable) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }

        return cachePath + File.separator;
    }

    public void loadHeadImg() {
        loadHeadImg(null);
    }


    /**
     * 全部运行在子线程
     * 逻辑
     * 首先加载本地
     * 如果本地加载成功
     *      检查本地头像是不是最新的,如果是最新的,不操作,如果不是最新的,加载网络最新
     * 如果本地加载失败
     *      加载网络最
     */
        public void loadHeadImg(final HeadImgBitapCallBack callBack) {

            //首先加载本地的


            ThreadManager.THREAD_POOL_EXECUTOR.execute(new Runnable() {
                @Override
                public void run() {
                    try {


                        if(loadLocalHeadImg(callBack)) {//本地加载成功,检查头像更新


                            /本地加载成功


                            String imgName = getImgName();
                            Log.e(TAG,imgName + "----");

                            if(imgName == null) {
                                //   imgName == null  网络获取头像失败
                                //本地有缓存,但是网络获取为空,表明切换的账号没有头像

                                Log.e(TAG,"头像为空");

                                File headFile = new File(path + imgFileName);
                                headFile.delete();
                                Log.e(TAG,"删除本地缓存");
                                Resources res= mActivity.getResources();

                                final Bitmap bmp =BitmapFactory.decodeResource(res, R.drawable.found_add_icon);

                                mActivity.runOnUiThread(new Runnable() {


                                    @Override
                                    public void run() {
                                        if(callBack != null) {
                                            callBack.onGetBitmap(bmp);
                                        }
                                        if(mIvPhoto != null) {
                                            mIvPhoto.setImageBitmap(bmp);
                                        }

                                    }
                                });
                            } else if(imgName.equals(NETWORK_ERROR)) {//网络错误


                                Log.e(TAG,"网络错误,就加载本地的");

                            } else { //获取到网络图片名称
                                if (!mSpData.getString("headImgName", "").equals(imgName)) {//本地缓存过老
                                    Log.e(TAG, "本地缓存过老");
                                    loadImgByUrl(imgName,callBack);
                                } else {//本地是最新的

                                }
                            }
                            /本地加载成功

                        } else {//本地加载失败,加载网络


                            Log.e(TAG, "本地没有图片,加载网络图片");
                            String imgName = getImgName();
                            if(imgName != null && !imgName.equals(NETWORK_ERROR)) {
                                loadImgByUrl(imgName,callBack);
                            } else {

                                //本地加载失败,网络加载也失败
                                Log.e(TAG,"本地加载失败,网络加载也失败");
                                if(callBack != null) {

                                    Resources res= mActivity.getResources();

                                    final Bitmap bmp =BitmapFactory.decodeResource(res, R.drawable.found_add_icon);

                                    mActivity.runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            callBack.onGetBitmap(bmp);

                                        }
                                    });
                                }



                            }

                        }


                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        }



    /**
     * 加载本地图片  运行在子线程
     * @return
     */
    private boolean loadLocalHeadImg(final HeadImgBitapCallBack callBack)  {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(path + imgFileName);
            final Bitmap localHead = BitmapFactory.decodeStream(fis);

            if (localHead != null) {
                Log.e(TAG, "localHead: " + localHead);
                Log.e(TAG, "本地有头像文件,先加载本地图片");

                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        if(callBack != null) {
                            callBack.onGetBitmap(localHead);
                        }
                        if(mIvPhoto != null) {
                            mIvPhoto.setImageBitmap(localHead);
                        }

                    }
                });



                return true;
            } else {
                Log.e(TAG, "本地没有图片,加载网络图片");
                return false;
            }
        } catch (FileNotFoundException e) {
            Log.e(TAG, "本地没有图片");
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 通过Image名称加载图片  运行在子线程
     * @param imageName  图片名称
     * @throws IOException
     */
    private void loadImgByUrl(String imageName, final HeadImgBitapCallBack callBack) throws IOException {

        if(imageName == null) {

            return;
        }

        String imgUrl = HttpUtil.URL + "upload/image/" + imageName;
        Log.e(TAG, "imgUrl: " + imgUrl);
        URL url = new URL(imgUrl); //path图片的网络地址
        HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        if (httpURLConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
            final Bitmap bitmap = BitmapFactory.decodeStream(httpURLConnection.getInputStream());


            mActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if(callBack != null) {
                        callBack.onGetBitmap(bitmap);
                    }
                    if(mIvPhoto != null) {
                        mIvPhoto.setImageBitmap(bitmap);
                    }

                }
            });



            if(savePicToSd(bitmap)) {
                Log.e(TAG,"缓存到本地成功");
                SharedPreferences.Editor edit = mSpData.edit();
                edit.putString("headImgName", imageName);
                edit.apply();
            } else {
                Log.e(TAG,"缓存到本地失败");
            }
            //缓存文件名称一份到本地

            Log.e(TAG, "加载网络图片完成");
        }
    }

    //获得个人的头像信息
    private JSONObject getHeadImgName(String phoneNumber) throws Exception {
        //使用Map封装请求参数 gender
        Map<String, String> map = new HashMap<>();
        map.put("phoneNumber", phoneNumber);


        String url = HttpUtil.URL + "getIamge";
        Log.e(TAG, url);
        return new JSONObject(HttpUtil.postRequest(url, map));
    }


    /**
     * 获得 最新头像的名称  没有返回null
     * @return 最新头像的名称
     */
    private String getImgName() {

        try {
            JSONObject jsonImageName = getHeadImgName(mUserAccount);
            Log.e(TAG, jsonImageName.toString());
            if (jsonImageName.getString("errcode").equals(HttpUtil.SUCCESS)) {
                String imageName = jsonImageName.getString("content");

                return imageName;
                /**/


            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return NETWORK_ERROR;
        }

    }

    private boolean savePicToSd(Bitmap mBitmap) {
        String sdStatus = Environment.getExternalStorageState();
        if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) { // 检测sd是否可用
            Log.e(TAG, "保存失败");
            return false;
        }
        FileOutputStream b = null;
        File file = new File(path);
        file.mkdirs();// 创建文
        String fileName = path + imgFileName;//图片名字
        Log.e(TAG, "imgFileName: " + fileName);
        try {
            b = new FileOutputStream(fileName);
            mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, b);// 把数据写入文件
            Log.e(TAG, "保存成功");
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            Log.e(TAG, "保存失败");
            return false;
        } finally {
            try {
                //关闭流
                b.flush();
                b.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }


    /**
     * 回调接口  用于返回bitmap对象
     * @author 钱海峰
     */
    public interface HeadImgBitapCallBack {
        void onGetBitmap(Bitmap img);
    }


}



现在对代码作一些解读,我在代码中加入了一个回调接口,HeadImgBitapCallBack,里面只有一个方法onGetBitmap,目的很明确就是用于获取最新的头像bitmap对象的,用回调的方式将结果返回,如果需要返回bitmap对象,可以调用方法loadHeadImg(HeadImgBitapCallBack callBack),如果不需要返回bitmap对象,可以调用方法loadHeadImg();


使用这个头像加载框架也是很方便; 

如下为不需要返回bitmap对象的,this为上下文,mIvPhoto对ImageView,mUserAccount为当前账户手机号,用于请求后台服务器的。

        HeadImgManager imgManager = HeadImgManager.getInstance(this, mIvPhoto, mUserAccount);

        imgManager.loadHeadImg();


如果需要返回bitmap对象

        HeadImgManager imgManager = HeadImgManager.getInstance(this, null, mUserAccount);

        imgManager.loadHeadImg(new HeadImgManager.HeadImgBitapCallBack() {
            @Override
            public void onGetBitmap(Bitmap img) {
                myHeadBitmap =  img;
                
            }
        });

比如我在意见反馈界面就用到这个头像bitmap对象,大概效果如下:




将最新的头像显示在ListView中。


也可以是这样








  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值