android Glide簡單使用


 

版權聲明:大家可以轉載,請寫明轉載申明 https://blog.csdn.net/bzlj2912009596/article/details/81702367

今天,簡單講講Android里Glide的簡單使用。

 

Android框架系列:

一.android EventBus的簡單使用

二.android Glide簡單使用

 

對於Glide這個加載圖片的框架,很多人都在用,我之前使用的是ImageLoader,最近查資料時,發現Glide才是Google推薦的加載圖片框架,功能非常強大,而且還有Google專人維護,要知道,ImageLoader已經沒人維護了,除了問題可沒人解答。所以有必要整理一下Glide的使用。

Glide是谷歌為我們推薦的一個圖片加載庫。為什么要選擇使用Glide呢?

  • 1、代碼有人維護,不至於出現問題,項目組都搞不定的時候問題無法解決。(ImageLoader已沒人維護了)
  • 2、代碼簡潔,可讀性很好。(Fresco是一個非常優秀的庫,但是配置稍顯麻煩,同時代碼風格讀起來有些生疏)
  • 3、功能強大(400多k的包,包含很多功能,例如:像加載Gif圖片就是Picasso做不到的)

下面我們就來介紹下Glide的用法:

Glide的基本使用

導入庫

compile 'com.github.bumptech.glide:glide:3.7.0'

添加代碼混淆(可加可不加)

  1.  
    -keep public class * implements com.bumptech.glide.module.GlideModule
  2.  
    -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
  3.  
    **[] $VALUES;
  4.  
    public *;
  5.  
    }
  6.  
     
  7.  
    # for DexGuard only
  8.  
    -keepresourcexmlelements manifest/application/meta- data@value=GlideModule

這個別忘了,不要粗心哦,很容易忘得,最簡單的問題,往往需要最簡單的搞定啦。

  1.  
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
  2.  
    <uses-permission android:name="android.permission.INTERNET" />

簡單使用例子

  1.  
    // For a simple view:
  2.  
    @Override
  3.  
    public void onCreate(Bundle savedInstanceState) {
  4.  
    ...
  5.  
    ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
  6.  
     
  7.  
    Glide.with( this).load("http://goo.gl/gEgYUd").into(imageView);
  8.  
    }
  9.  
     
  10.  
    // For a simple image list:
  11.  
    @Override
  12.  
    public View getView(int position, View recycled, ViewGroup container) {
  13.  
    final ImageView myImageView;
  14.  
    if (recycled == null) {
  15.  
    myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
  16.  
    } else {
  17.  
    myImageView = (ImageView) recycled;
  18.  
    }
  19.  
     
  20.  
    String url = myUrls.get(position);
  21.  
     
  22.  
    Glide
  23.  
    .with(myFragment)
  24.  
    .load(url)
  25.  
    .centerCrop()
  26.  
    .placeholder(R.drawable.loading_spinner)
  27.  
    .crossFade()
  28.  
    .into(myImageView);
  29.  
     
  30.  
    return myImageView;
  31.  
    }

Glide使用詳解

加載網絡圖片

Glide.with(context).load(internetUrl).into(targetImageView);

從文件加載圖片

  1.  
    File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"Test.jpg");
  2.  
    Glide. with(context).load(file).into(imageViewFile);

從資源id加載圖片

  1.  
    int resourceId = R.mipmap.ic_launcher;
  2.  
    Glide. with(context).load(resourceId).into(imageViewResource);

從uri加載圖片

Glide.with(context).load(uri).into(imageViewUri);

播放本地mp4,只能是本地(獲取MP4視頻的縮略圖)

  1.  
    String filePath = "/storage/emulated/0/Pictures/example_video.mp4";
  2.  
    Glide. with( context ).load( Uri.fromFile( **new **File( filePath ) ) ).into( imageViewGifAsBitmap );

加載Gif圖片

  1.  
    String gifUrl = "xxxxx";
  2.  
    Glide. with( context ).load( gifUrl ).into( imageViewGif );

用bitMap播放Gif.asBitmap()

Glide.with( context ).load( gifUrl ).asBitmap().into( imageViewGifAsBitmap );

強制轉化為Gif.asGif()

Glide.with( context ).load( gifUrl ).asGif().error( R.drawable.full_cake ).into( imageViewGif );

設置默認占位圖.placeholder()

設置加載失敗的圖片.error()

Glide.with( context ).load( gifUrl ).placeholder( R.drawable.cupcake ).error( R.drawable.full_cake ).into( imageViewGif );

.fallback()

除了上面兩種‘異常情況’,還有一種情形就是打開手機的通訊錄的時候,可以看到你給有些喜歡的人設置了照片,然而有些可憐的人並沒給有,總不能在那里留下一片空白吧,這個時候相當於傳遞了Null,傳遞null時,這個callback方法就會被調用。

  1.  
    Glide.with(context)
  2.  
    .load( null)//加載空指針的時候
  3.  
    .fallback( R.drawable.wuyanzu)
  4.  
    . into( imageViewNoFade );

設置加載動畫

其實這個是默認的,但是你還是可以寫出來,漸顯動畫
1、.crossFade() :Glide提供淡如淡出

Glide.with(context).load().placeholder(R.mipmap.ic_launcher) .error(R.mipmap.future_studio_launcher).crossFade().into(imageViewFade);

這里還有一個.fadeFade(int duration),設置動畫時間。如果你不想要動畫可以加上.dontAnimate()
2、.animate(android.R.anim.slide_in_left):Android系統提供,從左到右滑出加載動畫

調整圖片大小.resize(int ,int )

單位是像素,裁剪你的圖片大小。其實Glide已經會自動根據你ImageView裁剪照片來放在緩存中了。但是不想適應ImageView大小的時候,可以調用這個方法.override()為ImageView指定大小。

Glide.with(context).load(image).override(600, 200) .into(imageViewResize);

裁剪圖片.fitCenter().CenterCrop()

Glide清楚在合適的ImageView中加載合適的Image.當需要裁剪大小時,有個.centerCrop方法,這個方法的裁剪會讓你的ImageView周圍不會留白,還有一個.fitCenter()方法,表示讓你的Image完全顯示,尺寸不對時,周圍會留白。

設置縮略圖.thumbnail()

.thumbnail()方法的目的就是讓用戶先看到一個低解析度的圖,點開后,再加載一個高解析度的圖。

  1.  
    //表示為原圖的十分之一
  2.  
    Glide.with( context ).load(image).thumbnail( 0.1f ).into( imageView2 );

一種更高級的縮略圖加載方式:

當縮略圖也需要通過網絡加載全部解析度的時候。

  1.  
    private void loadImageThumbnailRequest() {
  2.  
    DrawableRequestBuilder< String> thumbnailRequest = Glide.with( context ).load( eatFoodyImages[2] );
  3.  
    Glide. with( context ).load( UsageExampleGifAndVideos.gifUrl ).thumbnail( thumbnailRequest ).into( imageView3 );
  4.  
    }

設置圖片顯示效果(圓角、圓形、高斯模糊、蒙板、裁剪等等).bitmapTransform()

  1.  
    Glide.with( this).load(R.mipmap.ic_image_sample)
  2.  
    //模糊
  3.  
    .bitmapTransform( new BlurTransformation(this))
  4.  
    //圓角
  5.  
    .bitmapTransform( new RoundedCornersTransformation(this, 24, 0, RoundedCornersTransformation.CornerType.ALL))
  6.  
    //遮蓋
  7.  
    .bitmapTransform( new MaskTransformation(this, R.mipmap.ic_launcher))
  8.  
    //灰度
  9.  
    .bitmapTransform( new GrayscaleTransformation(this))
  10.  
    //圓形
  11.  
    .bitmapTransform( new CropCircleTransformation(this))
  12.  
    . into(mResultIv);

除此之外還有實現諸如馬賽克、明暗度等更多濾鏡處理:

  • ToonFilterTransformation
  • SepiaFilterTransformation
  • ContrastFilterTransformation
  • InvertFilterTransformation
  • PixelationFilterTransformation
  • SketchFilterTransformation
  • SwirlFilterTransformation
  • BrightnessFilterTransformation
  • KuwaharaFilterTransformation
  • VignetteFilterTransformation

Glide的緩存

用過手機的都知道,當划上划下一個ListView的時候,第二次都比第一次快,就是因為為GlideView對資源進行了緩存,而且封裝的很好,甚至不需要自己去設定緩存大小,Glide會智能地自己給我們根據設備設置緩存大小。

緩存是為了減少或者杜絕多的網絡請求。為了避免緩存,Glide用了內存緩存和‘外存緩存機制’,並且 提供了相應的方法,完全封裝,不需要處理細節。Glide會自動緩存到內存,除非調用.skipMemoryCache( true )。盡管調用了這個,Glide還是會緩存到外存,還有一種情形,就是有一張圖片,但是這張圖變化非常快,這個時候可能並不想緩存到外存中,就使用.diskCacheStrategy( DiskCacheStrategy.NONE )。如果你兩種都不需要,可以兩個方法組合着一起使用。

自定義外存緩存機制

Glide默認會緩存Image的很多個版本,比如原圖,如果你的imageView大小的緩存。.diskCacheStrategy()有以下幾種緩存策略:

  • DiskCacheStrategy.NONE 什么都不緩存
  • DiskCacheStrategy.SOURCE 只緩存最高解析圖的image
  • DiskCacheStrategy.RESULT 緩存最后一次那個image,比如有可能你對image做了轉化
  • DiskCacheStrategy.ALL image的所有版本都會緩存
Glide.with( context ).load( image ).diskCacheStrategy( DiskCacheStrategy.SOURCE ).into( imageViewFile );

修改緩存大小、位置、加載圖片質量

和指定HttpClent為OkHttp一樣,只不過我們需要配置一些信息在applyOptions()函數里面

  1.  
    public class GlideConfigModule implements GlideModule {
  2.  
    @Override
  3.  
    public void applyOptions(Context context, GlideBuilder builder) {
  4.  
    // 指定位置在packageName/cache/glide_cache,大小為MAX_CACHE_DISK_SIZE的磁盤緩存
  5.  
    builder.setDiskCache( new InternalCacheDiskCacheFactory(context, "glide_cache", ConfigConstants.MAX_CACHE_DISK_SIZE));
  6.  
    //指定內存緩存大小
  7.  
    builder.setMemoryCache( new LruResourceCache(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
  8.  
    //全部的內存緩存用來作為圖片緩存
  9.  
    builder.setBitmapPool( new LruBitmapPool(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
  10.  
    builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888); //和Picasso配置一樣
  11.  
    }
  12.  
     
  13.  
    @Override
  14.  
    public void registerComponents(Context context, Glide glide) {
  15.  
    }
  16.  
    }
  1.  
    <meta-data android:name= "com.example.imageloadpk.adapter.config.GlideConfigModule"
  2.  
    android: value="GlideModule"/>

一般的圖片加載框架設置了磁盤緩存和內存緩存就行了,但是Glide還設置了一個圖片緩存。
圖片緩存 <= 內存緩存

  1.  
    builder.setDiskCache( new InternalCacheDiskCacheFactory(context, "glide_cache", ConfigConstants.MAX_CACHE_DISK_SIZE));
  2.  
    //指定內存緩存大小
  3.  
    builder.setMemoryCache( new LruResourceCache(ConfigConstants.MAX_CACHE_MEMORY_SIZE));
  4.  
    //全部的內存緩存用來作為圖片緩存
  5.  
    builder.setBitmapPool( new LruBitmapPool(ConfigConstants.MAX_CACHE_MEMORY_SIZE));

這里Glide不僅可以緩存圖片,還可以緩存其他文件譬如視頻之類,也就是說可以把他作為我們的緩存工具來使用,當然緩存方式還是使用LRU。這樣我們就不必再去重新集成LruCache和DiskLruCache,再去申請空間,配置。直接可以復用Glide的。

使用緩存也加載動畫

但是,動畫默認是在圖片沒有緩存的情況下才加載,想想也是合理的,如果圖片已近下載到本地加載速度將會非常快,這個時候使用動畫過渡反而礙事。要讓從緩存中圖片呈現也加載動畫不能通過這種方式實現,可以用監聽器來做。

  1.  
    private RequestListener<String, GlideBitmapDrawable> mAnimationRequestListener = new RequestListener<String, GlideBitmapDrawable>() {
  2.  
    @Override
  3.  
    public boolean onException(Exception e, String model, Target<GlideBitmapDrawable> target, boolean isFirstResource) {
  4.  
    return false;
  5.  
    }
  6.  
     
  7.  
    @Override
  8.  
    public boolean onResourceReady(GlideBitmapDrawable resource, String model, Target<GlideBitmapDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
  9.  
    dissProgress();
  10.  
    if (isFromMemoryCache) {
  11.  
    //如果是從緩存加載,設置動畫效果
  12.  
    mIvShow.setAnimation(AnimationUtils.loadAnimation(mContext, R.anim.scale));
  13.  
    }
  14.  
    //返回true表示攔截不再傳遞,false表示事件會傳遞下去
  15.  
    return false;
  16.  
    }
  17.  
    };

請求優先級.priority()

加載圖片肯定也是有先后順序,Glide提供了.priority()這個方法,它接收以下幾個參數:

  • Priority.LOW
  • Priority.NORMAL
  • Priority.HIGH
  • Priority.IMMEDIATE

但是Glide並不一定會按照你的順序來,只是盡量按照你的順序來。(比如給一張很大的圖片最高的優先權,但是它並不一定比低優先級的圖先加載出來,這個時候只有使用縮略圖了)

  1.  
    Glide.with(mContext).load(Url.IMAGE_URL_TROCHILIDAE)
  2.  
    .priority(Priority.HIGH).into(mIvTonyRight);

利用callback在非標准情況下加載圖片

上面所有的情況都是加載圖片到ImageView中,但是並不是所有的情況都是這樣。譬如加載的控件類型不是ImageView,是個自定義的布局。或者加載為Background的形式。
可以使用SimpleTarget類型,這里指定他的大小為500*100,加載為背景圖片

  1.  
    .into( new SimpleTarget<Drawable>(500, 100) {
  2.  
    @Override
  3.  
    public void onResourceReady(Drawable resource, GlideAnimation<? super Drawable> glideAnimation) {
  4.  
    mBtnClear.setBackground(resource);
  5.  
    }

同理下載圖片原理是一樣

  1.  
    .into( new SimpleTarget<Bitmap>() {
  2.  
    @Override
  3.  
    public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
  4.  
    //toSave
  5.  
    Log.d(TAG, "onResourceReady: save successful");
  6.  
    }
  7.  
    });

Glide中的回調:Targets

從上面的介紹,已經可以看出Glide內部封裝了所有的細節,什么網絡請求,什么緩存機制,當所有都就緒過后,自動切換回UI線程,更新ImageView。Targets就是Glide中的回調,當異步線程中所有的工作做完過后返回結果。說白了就是,當請求圖片完成后,需要回調的方法。

SimpleTarget

  1.  
    private SimpleTarget target = new SimpleTarget<Bitmap>() {
  2.  
    @Override
  3.  
    public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
  4.  
    // do something with the bitmap
  5.  
    // for demonstration purposes, let's just set it to an ImageView
  6.  
    imageView1.setImageBitmap( bitmap );
  7.  
    }
  8.  
    };
  9.  
     
  10.  
    private void loadImageSimpleTarget() {
  11.  
    Glide.with( context ) * // could be an issue!*
  12.  
    .load( eatFoodyImages[ 0] )
  13.  
    .asBitmap() //強制Glide返回一個Bitmap
  14.  
    .into( target );
  15.  
    }

注意事項:

1、上面這段代碼不要寫成匿名內部類的機制,原因就是java的自動垃圾回收機制可能在圖片還沒有加載好的時候就已經把你的Target回收了。

2、注意.with()里面的參數,Glide的請求是和傳進去的Context共存亡的,如果傳一個Activity進去,當Activity GC過后,你的請求也就GC了,但是如果這樣傳:.with(context.getApplicationContext() ).當你的Activity GC過后,請求還是會繼續,回調還是會繼續。
有size的Target

如果傳給into().的是一個ImageView,但是圖片的size比ImageView的Size打,Glide為了節省時間,會加載小的那個size的Image。但是這對Target並不適用,以為這里並不知道SIze。但是如果知道image應該多大,可以傳遞給Target.就像下面這樣:

  1.  
    private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) {
  2.  
    @Override
  3.  
    public void onResourceReady(Bitmap bitmap, GlideAnimation glideAnimation) {
  4.  
    imageView2.setImageBitmap( bitmap );
  5.  
    }
  6.  
    };
  7.  
     
  8.  
    private void loadImageSimpleTargetApplicationContext() {
  9.  
    Glide.with(context.getApplicationContext()); * // safer!*
  10.  
    .load( eatFoodyImages[ 1] )
  11.  
    .asBitmap()
  12.  
    .into( target2 );
  13.  
    }

ViewTarget

適用於想Glide加載到自定義View中去,

  1.  
    public class FutureStudioView extends FrameLayout {
  2.  
    ImageView iv;
  3.  
    TextView tv;
  4.  
     
  5.  
    public void nitialize(Context context) {
  6.  
    inflate( context, R.layout.custom_view_futurestudio, this );
  7.  
    iv = (ImageView) findViewById( R.id.custom_view_image );
  8.  
    tv = (TextView) findViewById( R.id.custom_view_text );
  9.  
    }
  10.  
     
  11.  
    public FutureStudioView(Context context, AttributeSet attrs) {
  12.  
    super( context, attrs );
  13.  
    initialize( context );
  14.  
    }
  15.  
     
  16.  
    public FutureStudioView(Context context,AttributeSet attrs,int defStyleAttr) {
  17.  
    super( context, attrs, defStyleAttr );
  18.  
    initialize( context );
  19.  
    }
  20.  
     
  21.  
    public void setImage(Drawable drawable) {
  22.  
    iv = (ImageView) findViewById( R.id.custom_view_image );
  23.  
    iv.setImageDrawable( drawable );
  24.  
    }
  25.  
    }

還有notificationTarget 和AppWidget作為擴展自行研究嘍。

監聽器配置.listener()

  1.  
    Glide.with(getContext()).load(url)
  2.  
    .listener(mRequestListener) //配置監聽器
  3.  
    .placeholder(Drawables.sPlaceholderDrawable)
  4.  
    .error(Drawables.sErrorDrawable)
  5.  
    .into(mImageView);
  6.  
     
  7.  
    private RequestListener<String, GlideDrawable> mRequestListener = new RequestListener<String, GlideDrawable>() {
  8.  
    @Override
  9.  
    public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
  10.  
    //顯示錯誤信息
  11.  
    Log.w(TAG, "onException: ", e);
  12.  
    //打印請求URL
  13.  
    Log.d(TAG, "onException: " + model);
  14.  
    //打印請求是否還在進行
  15.  
    Log.d(TAG, "onException: " + target.getRequest().isRunning());
  16.  
    return false;
  17.  
    }
  18.  
     
  19.  
    @Override
  20.  
    public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
  21.  
    return false;
  22.  
    }
  23.  
    };

這里的onException捕獲異常,如果返回true表示我們自己處理掉了異常,false表示交給Glide去處理,因為我們定義了.error()那么就顯示error里面的內容。

這里onResourceReady表示是否准備資源顯示,返回true表示用戶自己已經設置好資源,包括截取操作,動畫操作之類的,准備好顯示。false表示交給Glide

如此修改后,就能夠看到圖片加載日志了,方便我們調試

替換掉自帶的HttpClient

只需兩步
Step1:
導入需要替換的HttpClient,可以選擇Volley也可以選擇OkHttp,我們使用Okhttp,在Module的build.gradle文件中配置

  1.  
    dependencies {
  2.  
    compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
  3.  
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
  4.  
     
  5.  
    or
  6.  
     
  7.  
    compile 'com.github.bumptech.glide:volley-integration:1.4.0@aar'
  8.  
    compile 'com.mcxiaoke.volley:library:1.0.8'
  9.  
    }

這個版本具體選擇多少,可以在https://github.com/bumptech/glide/wiki/Integration-Libraries這里查詢到
Step2:
在AndroidMainfest.xml文件中寫入

這個版本具體選擇多少,可以在https://github.com/bumptech/glide/wiki/Integration-Libraries這里查詢到
Step2:
在AndroidMainfest.xml文件中寫入

  1.  
    <meta-data android:name= "com.bumptech.glide.integration.okhttp3.OkHttpGlideModule"
  2.  
    android: value="GlideModule"/>

你可能會有和我一樣的疑問,Glide可以通過在配置清單里面配置
能不能寫幾個meta-data標簽,一個標簽里面配置一點參數
經過測試,發現這樣做也是可以的。但是如果是同一種配置信息,比如你集成了OkHttp,又寫一個標簽集成Volley,最后一個會把前面的覆蓋掉。

注意事項

1、前面我們已經學習到asGif()可以加載gif圖,asBitmap()可以加載靜態gif圖即gif圖的第一幀,如果非gif圖用asGif()方法加載呢?這時候會報錯。。Glide默認可以自動識別圖片格式,加載gif圖,所以在不確定圖片格式的情況下,不要直接寫asGif哦。

2、You cannot start a load for a destroyed activity這樣的異常如何處理?
記住不要再非主線程里面使用Glide加載圖片,如果真的使用了,請把context參數換成getApplicationContext。希望可以幫你避免這個問題。

3、為什么有的圖片第一次加載的時候只顯示占位圖,第二次才顯示正常的圖片呢?
.如果你剛好使用了這個圓形Imageview庫或者其他的一些自定義的圓形Imageview,而你又剛好設置了占位的話,那么,你就會遇到第一個問題。如何解決呢?

方案一: 不設置占位;
方案二:使用Glide的Transformation API自定義圓形Bitmap的轉換。這里是一個已有的例子;
方案三:使用下面的代碼加載圖片:

  1.  
    Glide.with(mContext)
  2.  
    .load(url)
  3.  
    .placeholder(R.drawable.loading_spinner)
  4.  
    .into( new SimpleTarget<Bitmap>(width, height) {
  5.  
    @Override
  6.  
    public void onResourceReady(Bitmap bitmap, GlideAnimation anim) {
  7.  
    // setImageBitmap(bitmap) on CircleImageView
  8.  
    }
  9.  
    };

4、圖片大小拉伸問題
有時候你會發現網絡加載完了之后會有拉伸現象,而你的控件大小明明是自適應的呀,這是為什么呢,請你檢查下你是否設置了占位圖,有的話請去掉就ok了。

 

簡單總結一下,我這里講了Glide比較全面的用法,有如何加載圖片,Glide的緩沖設置,Glide設置圓角,Glide設置圖片的background,Glide加載GIF圖片等,大家使用的話一般了解加載圖片和圓角圖片就可以了。這里在列舉一下。

  1.  
    //圓形裁剪
  2.  
    Glide.with( this)
  3.  
    .load( "http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
  4.  
    .bitmapTransform( new CropCircleTransformation(this))
  5.  
    . into(iv_0);
  6.  
    //圓角處理
  7.  
    Glide.with( this)
  8.  
    .load( "http://inthecheesefactory.com/uploads/source/nestedfragment/fragments.png")
  9.  
    .bitmapTransform( new RoundedCornersTransformation(this,30,0, RoundedCornersTransformation.CornerType.ALL))
  10.  
    . into(iv_0);

android Glide簡單使用就講完了。

就這么簡單。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM