亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定

Fresco的封裝和使用說明以及獲取緩存中的Bitmap對象

標簽:
Android

Fresco介绍

Fresco是facebook开源的图片加载框架。

关于 Fresco Fresco 是一个强大的图片加载组件。

Fresco 中设计有一个叫做 image pipeline 
的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件)。

Fresco 中设计有一个叫做 Drawees 模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。

Fresco 支持 Android2.3(API level 9) 及其以上系统。

相比其他的图片加载框架功能强大得多,如果还不了解同学可以点击上面的链接学习了解。

它的整个框架设计涉及到很多的设计模式,作为开发者如果不了解足够多的设计模式对开源框架分析理解是在有点困难,所以我的博客会经常更新一些有关设计模式的内容和大家一起学习。

封装理由

Fresco功能强大。如果只是普通的使用很简单。 
如果需要使用它真正强大的功能就很复杂,这是因为它的框架中包含了太多的功能类和设计模式,导致使用起来非常麻烦,相比其他的一行代码就可以解决图片加载,Fresco就麻烦多了。所以我封装了一个ImageLoadFresco类方便我在项目中使用,现在开源出来给作为使用大家参考。

为什么Fresco配置这么复杂? 
因为对整个Fresco图片加载框架 使用了MVC模式 
M层上有很多的图片资源,比如占位图,loading图,error图 
C层决定调用M层上哪些图 
V层对应视图View层,最后绑定M/C层。所以在使用时需要配置M/C层需要很多代码。

使用说明

封装之后调用图片加载就相对简单,简单的使用是没有问题的,只是在Adapter中使用存在控件重复配置的问题,会对内存有些影响。这个等我有时间再深究解决。 
问题提示在这里

在指定一个新的controller的时候,使用setOldController,这可节省不必要的内存分配。

使用示例代码

[代码]java代码:

?

1

2

3

new ImageLoadFresco.LoadImageFrescoBuilder(mContext,view,url)

                .setIsRadius(true)//圆角配置

                .build();

封装代码

说明

针对这个配置属性比较多的类,我采用Builder生成器模式,简化使用时候的代码量。类里面配置很多默认属性。如果需要添加新的属性也不会影响现有代码编译。同时在使用的时候不涉及具体的Fresco代码,后期如果有需求替换图片加载框架,也会方便。

代码

最新的代码点这里,这个封装类我自己也在项目中使用,会根据需求添加新的功能。

[代码]java代码:

?

001

002

003

004

005

006

007

008

009

010

011

012

013

014

015

016

017

018

019

020

021

022

023

024

025

026

027

028

029

030

031

032

033

034

035

036

037

038

039

040

041

042

043

044

045

046

047

048

049

050

051

052

053

054

055

056

057

058

059

060

061

062

063

064

065

066

067

068

069

070

071

072

073

074

075

076

077

078

079

080

081

082

083

084

085

086

087

088

089

090

091

092

093

094

095

096

097

098

099

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

package licola.demo.com.huabandemo.HttpUtils;

 

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.PointF;

import android.graphics.drawable.Drawable;

import android.net.Uri;

import android.support.v4.content.ContextCompat;

 

import com.facebook.common.executors.CallerThreadExecutor;

import com.facebook.common.references.CloseableReference;

import com.facebook.datasource.DataSource;

import com.facebook.drawee.backends.pipeline.Fresco;

import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder;

import com.facebook.drawee.controller.ControllerListener;

import com.facebook.drawee.drawable.AutoRotateDrawable;

import com.facebook.drawee.drawable.ScalingUtils;

import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;

import com.facebook.drawee.generic.RoundingParams;

import com.facebook.drawee.interfaces.DraweeController;

import com.facebook.drawee.view.SimpleDraweeView;

import com.facebook.imagepipeline.common.ResizeOptions;

import com.facebook.imagepipeline.core.ImagePipeline;

import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;

import com.facebook.imagepipeline.image.CloseableImage;

import com.facebook.imagepipeline.request.ImageRequest;

import com.facebook.imagepipeline.request.ImageRequestBuilder;

 

import licola.demo.com.huabandemo.Util.Logger;

 

/**

 * Created by LiCola on    2016/01/16  15:26

 * 用Fresco加载图片的类

 * 针对这个Demo已经配置很多默认的值

 * 用构造器模式便于设置更多形式

 * <p>

 * 使用示例:

 * new   ImageLoadFresco.LoadImageFrescoBuilder(mContext,img_image_user,url_head)

 * .setIsCircle(true)

 * .build();

 */

public class ImageLoadFresco   {

    private static final String   TAG = "ImageLoadFresco";

 

    //必要参数

    private SimpleDraweeView mSimpleDraweeView;

    private Context mContext;

 

 

    /**

     * 私有化的构造函数 得到builder的参数 构造对象

     *

     * @param   frescoBuilder 构造器

     */

    private ImageLoadFresco(LoadImageFrescoBuilder   frescoBuilder) {

        this.mContext   = frescoBuilder.mContext;

        this.mSimpleDraweeView   = frescoBuilder.mSimpleDraweeView;

 

        //初始化M层 用于初始化图片中包含的数据

        GenericDraweeHierarchyBuilder   builderM=new GenericDraweeHierarchyBuilder(mContext.getResources());

 

        //初始化C层 用于控制图片的加载 是主要的实现控制类

        PipelineDraweeControllerBuilder   builderC = Fresco.newDraweeControllerBuilder();

 

        if (frescoBuilder.mUrlLow != null) {

            builderC.setLowResImageRequest(ImageRequest.fromUri(frescoBuilder.mUrlLow));

        }

 

        ImageRequest   request =   ImageRequestBuilder.newBuilderWithSource(Uri.parse(frescoBuilder.mUrl))

                .setResizeOptions(frescoBuilder.mResizeOptions)

                .build();

        builderC.setImageRequest(request);

 

        setViewPerformance(frescoBuilder,   builderM, builderC);

 

        if (frescoBuilder.mControllerListener != null)   {

            builderC.setControllerListener(frescoBuilder.mControllerListener);

        }

 

        DraweeController   draweeController=builderC.build();

 

        if (frescoBuilder.mBitmapDataSubscriber!=null){

            ImagePipeline   imagePipeline = Fresco.getImagePipeline();

 

            DataSource<closeablereference<closeableimage>>   dataSource =

                    imagePipeline.fetchDecodedImage(request,   mSimpleDraweeView.getContext());

            dataSource.subscribe(frescoBuilder.mBitmapDataSubscriber,CallerThreadExecutor.getInstance());

        }

 

        mSimpleDraweeView.setHierarchy(builderM.build());

        mSimpleDraweeView.setController(draweeController);

    }

 

    /**

     * 配置DraweeView的各种表现效果

     * 如 失败图 重试图 圆角或圆形

     * @param   frescoBuilder

     * @param   builderM

     * @param   builderC

     */

    private void setViewPerformance(LoadImageFrescoBuilder frescoBuilder,   GenericDraweeHierarchyBuilder builderM, PipelineDraweeControllerBuilder   builderC) {

 

        //设置图片的缩放形式

        builderM.setActualImageScaleType(frescoBuilder.mActualImageScaleType);

        if (frescoBuilder.mActualImageScaleType ==   ScalingUtils.ScaleType.FOCUS_CROP) {

            builderM.setActualImageFocusPoint(new PointF(0f, 0f));

        }

 

        if (frescoBuilder.mPlaceHolderImage != null)   {

            builderM.setPlaceholderImage(frescoBuilder.mPlaceHolderImage,   ScalingUtils.ScaleType.CENTER);

        }

 

        if (frescoBuilder.mProgressBarImage != null)   {

            Drawable   progressBarDrawable = new AutoRotateDrawable(frescoBuilder.mProgressBarImage, 2000);

            builderM.setProgressBarImage(progressBarDrawable);

            ////   TODO: 2016/3/18 0018 直接设置无效   是自定义Drawable setColor知识为了类里面的取值

//              MyProgressBarDrawable progressBarDrawable=new MyProgressBarDrawable();

//              builderM.setProgressBarImage(progressBarDrawable);

        }

 

        //设置重试图 同时就是设置支持加载视频时重试

        if (frescoBuilder.mRetryImage != null) {

            builderC.setTapToRetryEnabled(true);

            builderM.setRetryImage(frescoBuilder.mRetryImage);

        }

 

        if (frescoBuilder.mFailureImage != null) {

            builderM.setFailureImage(frescoBuilder.mFailureImage);

        }

 

        if (frescoBuilder.mBackgroundImage != null)   {

            builderM.setBackground(frescoBuilder.mBackgroundImage);

        }

 

        if (frescoBuilder.mIsCircle) {

 

            if (frescoBuilder.mIsBorder) {

                //默认白色包边

                builderM.setRoundingParams(RoundingParams.asCircle().setBorder(0xFFFFFFFF,   2));

            }else {

                builderM.setRoundingParams(RoundingParams.asCircle());

            }

//              builderM.setRoundingParams(RoundingParams.asCircle());

        }

 

        //如果圆角取默认值10 或者是已经修改过的mRadius值

        if (frescoBuilder.mIsRadius) {

            builderM.setRoundingParams(RoundingParams.fromCornersRadius(frescoBuilder.mRadius));

        }

 

    }

 

    //构造器 作为类级内部类

    public static class LoadImageFrescoBuilder   {

        //必要参数

        private Context mContext;

        private SimpleDraweeView mSimpleDraweeView;

        private String mUrl;

 

        //非必要参数

        private String mUrlLow;//低分率图地址

 

        private Drawable mPlaceHolderImage;//占位图

        private Drawable mProgressBarImage;//loading

        private Drawable mRetryImage;//重试图

        private Drawable mFailureImage;//失败图

        private Drawable mBackgroundImage;//背景图

 

        private ScalingUtils.ScaleType   mActualImageScaleType = ScalingUtils.ScaleType.CENTER_CROP;

        private boolean mIsCircle = false;//是否圆形图片

        private boolean mIsRadius = false;//是否圆角

        private boolean mIsBorder = false;//是否有包边

        private float mRadius = 10;//圆角度数   默认10

        private ResizeOptions mResizeOptions = new ResizeOptions(3000, 3000);//图片的大小限制

 

        private ControllerListener mControllerListener;//图片加载的回调

 

        private BaseBitmapDataSubscriber   mBitmapDataSubscriber;

        /**

         *   构造器的构造方法 传入必要参数

         *

         *   @param mContext

         *   @param mSimpleDraweeView

         *   @param mUrl

         */

        public LoadImageFrescoBuilder(Context mContext,   SimpleDraweeView mSimpleDraweeView, String mUrl) {

            this.mContext   = mContext;

            this.mSimpleDraweeView   = mSimpleDraweeView;

            this.mUrl   = mUrl;

        }

 

        /**

         *   构造器的build方法   构造真正的对象 并返回

         *   构造之前需要检查

         *

         *   @return

         */

        public ImageLoadFresco build() {

 

//              if (TextUtils.isEmpty(mUrl)) {

//                  throw new IllegalArgumentException("URL不能为空");

//              }

 

            //不能同时设定 圆形圆角

            if (mIsCircle && mIsRadius) {

                throw new IllegalArgumentException("图片不能同时设置圆角和圆形");

            }

 

            return new ImageLoadFresco(this);

        }

 

        public LoadImageFrescoBuilder   setBitmapDataSubscriber(BaseBitmapDataSubscriber mBitmapDataSubscriber){

            this.mBitmapDataSubscriber   = mBitmapDataSubscriber;

            return this;

        }

 

        public LoadImageFrescoBuilder setUrlLow(String   urlLow) {

            this.mUrlLow   = urlLow;

            return this;

        }

 

        public LoadImageFrescoBuilder   setActualImageScaleType(ScalingUtils.ScaleType mActualImageScaleType) {

            this.mActualImageScaleType   = mActualImageScaleType;

            return this;

        }

 

        public LoadImageFrescoBuilder   setPlaceHolderImage(Drawable mPlaceHolderImage) {

            this.mPlaceHolderImage   = mPlaceHolderImage;

            return this;

        }

 

        public LoadImageFrescoBuilder setProgressBarImage(Drawable   mProgressBarImage) {

            this.mProgressBarImage   = mProgressBarImage;

            return this;

        }

 

        public LoadImageFrescoBuilder   setRetryImage(Drawable mRetryImage) {

            this.mRetryImage   = mRetryImage;

            return this;

        }

 

        public LoadImageFrescoBuilder   setFailureImage(Drawable mFailureImage) {

            this.mFailureImage   = mFailureImage;

            return this;

        }

 

        public LoadImageFrescoBuilder   setBackgroundImage(Drawable mBackgroundImage) {

            this.mBackgroundImage   = mBackgroundImage;

            return this;

        }

 

        public LoadImageFrescoBuilder   setBackgroupImageColor(int colorId) {

            Drawable   color = ContextCompat.getDrawable(mContext, colorId);

            this.mBackgroundImage   = color;

            return this;

        }

 

        public LoadImageFrescoBuilder setIsCircle(boolean mIsCircle) {

            this.mIsCircle   = mIsCircle;

            return this;

        }

 

        public LoadImageFrescoBuilder setIsCircle(boolean mIsCircle, boolean mIsBorder) {

            this.mIsBorder   = mIsBorder;

            this.mIsCircle   = mIsCircle;

            return this;

        }

 

        public LoadImageFrescoBuilder setIsRadius(boolean mIsRadius) {

            this.mIsRadius   = mIsRadius;

            return this;

        }

 

        public LoadImageFrescoBuilder setIsRadius(boolean mIsRadius, float mRadius) {

            this.mRadius   = mRadius;

            return setIsRadius(mIsRadius);

        }

 

        public LoadImageFrescoBuilder setRadius(float mRadius) {

            this.mRadius   = mRadius;

            return this;

        }

 

        public LoadImageFrescoBuilder   setResizeOptions(ResizeOptions mResizeOptions) {

            this.mResizeOptions   = mResizeOptions;

            return this;

        }

 

        public LoadImageFrescoBuilder   setControllerListener(ControllerListener mControllerListener) {

            this.mControllerListener   = mControllerListener;

            return this;

        }

 

    }

}</closeablereference<closeableimage></p>

得到Bitmap对象

在使用Fresco存在这样一个问题,把图片缓存封装得太好,导致很难直接得到缓存中的Bitmap对象,当然也不是不能。 
根据:数据源和数据订阅者文中说明的代码。 
我也在上面的封装代码中加入了获取Bitmap对象的回调功能。使用如下在回调中得到对象。

[代码]java代码:

?

01

02

03

04

05

06

07

08

09

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

new ImageLoadFresco.LoadImageFrescoBuilder(getApplicationContext(),   mImageUser, url)

                   .setBitmapDataSubscriber(new BaseBitmapDataSubscriber() {

                       @Override

                       protected void onNewResultImpl(Bitmap bitmap) {

                         if (bitmap == null) {

                               Logger.d("bitmap   is null");

                           }   else {

                               Logger.d("bitmap   is not null");

                               Drawable   backDrawable = new BitmapDrawable(getResources(), FastBlurUtil.doBlur(bitmap, 25, false));

                               if (Looper.getMainLooper() !=   Looper.myLooper()) {

                                   mAppBar.post(new Runnable() {

                                       @Override

                                       public void run() {

                                           mAppBar.setBackground(backDrawable);

                                       }

                                   });

                               }   else {

                                   mAppBar.setBackground(backDrawable);

                               }

                           }

                       }

 

                       @Override

                       protected void onFailureImpl(DataSource<closeablereference<closeableimage>>   dataSource) {

 

                       }

                   })

                   .build();</closeablereference<closeableimage>

提示:

千万不要把bitmap复制给onNewResultImpl函数范围之外的任何变量。订阅者执行完操作之后,image pipeline 会回收这个bitmap,释放内存。在这个函数范围内再次使用这个Bitmap对象进行绘制将会导致IllegalStateException。

Bitmap对象对象回调线程有可能是在UI主线程回调,也有可能在子线程中回调,如果需要更新UI,需要做判断进行不同的逻辑处理。

我上面的代码,用bitmap对象构造Drawable对象使用是不会发生异常,已经足够我的开发使用,以后想到什么再更新。

总结

·         本文主要是介绍Fresco和封装理由

·         封装采用构造器模式,我之后会写有关构造器模式的博文,帮助大家理解参考。

·         最后介绍Fresco的复杂使用,经过实际运行是满足功能需求,提供大家在使用Fresco的需要获取Bitmap时的参考。

原文链接:http://www.apkbus.com/blog-705730-60692.html

點擊查看更多內容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優質文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學習,寫下你的評論
感謝您的支持,我會繼續努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學

大額優惠券免費領

立即參與 放棄機會
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號

舉報

0/150
提交
取消