├── .gitignore ├── .travis.yml ├── API.md ├── GSYFrescoImageLoader ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── shuyu │ │ └── gsyfrescoimageloader │ │ ├── GSYFrescoFactory.kt │ │ └── GSYFrescoImageLoader.kt │ └── res │ └── values │ └── strings.xml ├── GSYGlideLoader ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── shuyu │ │ └── gsygiideloader │ │ ├── GSYGlideCacheKey.kt │ │ ├── GSYGlideImageLoader.kt │ │ └── GSYImageDownLoadTarget.kt │ └── res │ └── values │ └── strings.xml ├── GSYImageLoader ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── shuyu │ │ └── gsyimageloader │ │ ├── GSYImageConst.kt │ │ ├── GSYImageLoader.kt │ │ ├── GSYImageLoaderManager.kt │ │ ├── GSYLoadOption.kt │ │ └── GSYReflectionHelpers.kt │ └── res │ └── values │ └── strings.xml ├── GSYPicassoLoader ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── shuyu │ │ └── gsypicassoloader │ │ └── GSYPicassoImageLoader.kt │ └── res │ └── values │ └── strings.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── gysimageloader │ │ ├── Debuger.kt │ │ ├── GSYApplication.kt │ │ ├── MainActivity.kt │ │ └── process │ │ ├── custom │ │ └── CustomLoader.kt │ │ ├── fresco │ │ ├── BrightnessFilterPostprocessor.kt │ │ └── GPUFilterPostprocessor.kt │ │ ├── glide │ │ ├── BitmapTransformation.kt │ │ ├── BlurTransformation.kt │ │ ├── FastBlur.kt │ │ └── RSBlur.kt │ │ └── picasso │ │ └── ColorFilterTransformations.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── layout_fresco_image_item.xml │ └── layout_image_item.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── dependencies.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── logo.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | jdk: oraclejdk8 3 | android: 4 | components: 5 | - platform-tools 6 | - tools 7 | - build-tools-27.0.2 8 | - android-27 9 | - extra-android-support 10 | - extra-android-m2repository 11 | 12 | before_install: 13 | - chmod +x gradlew 14 | 15 | script: 16 | - cd app 17 | - ../gradlew assembleRelease -------------------------------------------------------------------------------- /API.md: -------------------------------------------------------------------------------- 1 | 2 | ### API 3 | 4 | [1、GSYImageLoaderManager](https://github.com/CarGuo/GSYImageLoader/blob/master/GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYImageLoaderManager.kt) 5 | 6 | ``` 7 | /** 8 | * 静态初始化、建议Application中初始化 9 | * @param imageLoader 内含GSYPicassoImageLoader、GSYFrescoImageLoader、GSYPicassoImageLoader 10 | */ 11 | fun initialize(imageLoader: IGSYImageLoader) 12 | 13 | /** 14 | * 图片加载对象 15 | */ 16 | fun imageLoader(): IGSYImageLoader 17 | 18 | /** 19 | * 强制转换的图片加载对象 20 | */ 21 | fun imageLoaderExtend(): T 22 | 23 | ``` 24 | 25 | [2、IGSYImageLoader](https://github.com/CarGuo/GSYImageLoader/blob/master/GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYImageLoader.kt) 26 | 27 | ``` 28 | /** 29 | * 加载图片 30 | * @param loadOption 加载图片配置 31 | * @param target 加载目标对象,ImageView or SimpleDraweeView 32 | * @param callback 加载回调 33 | * @param extendOption 额外配置接口 34 | */ 35 | fun loadImage(loadOption: GSYLoadOption, target: Any?, callback: Callback?, extendOption: ExtendedOptions? = null) 36 | 37 | /** 38 | * 清除缓存 39 | * @param type GSYImageConst,清除类型 40 | */ 41 | fun clearCache(type: Int = GSYImageConst.CLEAR_DISK_CACHE) 42 | 43 | /** 44 | * 清除指定缓存 45 | * @param type GSYImageConst,清除类型 46 | * @param loadOption 加载图片配置 47 | */ 48 | fun clearCacheKey(type: Int = GSYImageConst.CLEAR_DISK_CACHE, loadOption: GSYLoadOption) 49 | 50 | /** 51 | * 是否已经缓存到本地 52 | * @param loadOption 加载图片配置 53 | * @param extendOption 额外配置接口 54 | * @return Boolean 是否已经缓存到本地 55 | */ 56 | fun isCache(loadOption: GSYLoadOption, extendOption: IGSYImageLoader.ExtendedOptions? = null): Boolean 57 | 58 | /** 59 | * 获取本地缓存 60 | * @param loadOption 加载图片配置 61 | * @param extendOption 额外配置接口 62 | * @return File 63 | */ 64 | fun getLocalCache(loadOption: GSYLoadOption, extendOption: IGSYImageLoader.ExtendedOptions? = null): File? 65 | 66 | /** 67 | * 获取本地缓存bitmap 68 | * @param loadOption 加载图片配置 69 | * @param extendOption 额外配置接口 70 | * @return Bitmap 71 | */ 72 | fun getLocalCacheBitmap(loadOption: GSYLoadOption, extendOption: IGSYImageLoader.ExtendedOptions? = null): Bitmap? 73 | 74 | 75 | /** 76 | * 获取本地缓存大小 77 | * @return Long 78 | */ 79 | fun getCacheSize(): Long? 80 | 81 | 82 | /** 83 | * 下载图片 84 | * @param loadOption 加载图片配置 85 | * @param callback 加载回调 86 | * @param extendOption 额外配置接口 87 | * @return Bitmap 88 | */ 89 | fun downloadOnly(loadOption: GSYLoadOption, callback: IGSYImageLoader.Callback?, extendOption: IGSYImageLoader.ExtendedOptions? = null) 90 | 91 | /** 92 | * 额外配置支持 93 | */ 94 | interface ExtendedOptions { 95 | /** 96 | * @param option 配置对象 97 | * Glide com.bumptech.glide.request.RequestOptions 98 | * Picasso com.squareup.picasso.RequestCreator 99 | * Fresco com.facebook.imagepipeline.request.ImageRequestBuilder 100 | */ 101 | fun onOptionsInit(option: Any?) 102 | } 103 | 104 | /** 105 | * 回调接口 106 | */ 107 | @UiThread 108 | interface Callback { 109 | fun onStart() 110 | 111 | fun onSuccess(result: Any?) 112 | 113 | fun onFail(error: Exception?) 114 | } 115 | ``` 116 | -------------------------------------------------------------------------------- /GSYFrescoImageLoader/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /GSYFrescoImageLoader/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | 9 | def globalConfiguration = rootProject.extensions.getByName("ext") 10 | compileSdkVersion globalConfiguration.androidCompileSdkVersion 11 | buildToolsVersion globalConfiguration.androidBuildToolsVersion 12 | 13 | defaultConfig { 14 | 15 | minSdkVersion globalConfiguration.androidMinSdkVersion 16 | targetSdkVersion globalConfiguration.androidTargetSdkVersion 17 | 18 | versionCode 1 19 | versionName "1.0" 20 | 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | sourceSets { 29 | main { 30 | jniLibs.srcDirs = ['libs'] 31 | } 32 | } 33 | 34 | } 35 | 36 | dependencies { 37 | implementation fileTree(dir: 'libs', include: ['*.jar']) 38 | def androidDependencies = rootProject.ext.androidDependencies 39 | def dataDependencies = rootProject.ext.dataDependencies 40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 41 | implementation androidDependencies.appcompat_v7 42 | api dataDependencies.fresco 43 | api dataDependencies.frescoGif 44 | 45 | implementation project(':GSYImageLoader') 46 | 47 | } 48 | -------------------------------------------------------------------------------- /GSYFrescoImageLoader/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /GSYFrescoImageLoader/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /GSYFrescoImageLoader/src/main/java/com/shuyu/gsyfrescoimageloader/GSYFrescoFactory.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyfrescoimageloader 2 | 3 | import android.content.Context 4 | import android.graphics.drawable.Animatable 5 | import android.net.Uri 6 | import com.facebook.drawee.backends.pipeline.Fresco 7 | import com.facebook.drawee.controller.ControllerListener 8 | import com.facebook.drawee.generic.RoundingParams 9 | import com.facebook.drawee.interfaces.DraweeController 10 | import com.facebook.drawee.view.SimpleDraweeView 11 | import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory 12 | import com.facebook.imagepipeline.common.ResizeOptions 13 | import com.facebook.imagepipeline.core.ImagePipelineFactory 14 | import com.facebook.imagepipeline.request.BasePostprocessor 15 | import com.facebook.imagepipeline.request.ImageRequest 16 | import com.facebook.imagepipeline.request.ImageRequestBuilder 17 | import com.shuyu.gsyimageloader.GSYImageLoader 18 | import com.shuyu.gsyimageloader.GSYLoadOption 19 | 20 | /** 21 | * Fresco 基础 22 | * Created by guoshuyu on 2018/1/19. 23 | */ 24 | interface GSYFrescoFactory { 25 | 26 | fun isCached(context: Context, uri: Uri?): Boolean { 27 | val imagePipeline = Fresco.getImagePipeline() 28 | val dataSource = imagePipeline.isInDiskCache(uri) ?: return false 29 | val imageRequest = ImageRequest.fromUri(uri) 30 | val cacheKey = DefaultCacheKeyFactory.getInstance() 31 | .getEncodedCacheKey(imageRequest, context) 32 | val resource = ImagePipelineFactory.getInstance() 33 | .mainFileCache.getResource(cacheKey) 34 | return resource != null && dataSource.result != null && dataSource.result!! 35 | } 36 | 37 | fun getUri(targetUri: Any?): Uri? { 38 | var loadUri: Uri? = null 39 | when (targetUri) { 40 | is String -> { 41 | val uri = Uri.parse(targetUri) 42 | loadUri = uri 43 | } 44 | is Uri -> { 45 | loadUri = targetUri 46 | } 47 | } 48 | return loadUri 49 | } 50 | 51 | fun initFrescoView(simpleDraweeView: SimpleDraweeView, loadOption: GSYLoadOption) { 52 | if (loadOption.mDefaultImg > 0) { 53 | simpleDraweeView.hierarchy.setPlaceholderImage(loadOption.mDefaultImg) 54 | } 55 | if (loadOption.mErrorImg > 0) { 56 | simpleDraweeView.hierarchy.setFailureImage(loadOption.mErrorImg) 57 | } 58 | if (loadOption.isCircle) { 59 | setRoundingParmas(simpleDraweeView, getRoundingParams(simpleDraweeView).setRoundAsCircle(true)) 60 | } else { 61 | setRoundingParmas(simpleDraweeView, getRoundingParams(simpleDraweeView).setRoundAsCircle(false)) 62 | } 63 | } 64 | 65 | fun buildImageRequestWithResource(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): ImageRequest? { 66 | val remoteTarget = loadOption.mUri 67 | var builder: ImageRequestBuilder? = null 68 | when (remoteTarget) { 69 | is Int -> { 70 | builder = ImageRequestBuilder.newBuilderWithResourceId(remoteTarget) 71 | } 72 | is Uri -> { 73 | builder = ImageRequestBuilder.newBuilderWithSource(remoteTarget) 74 | 75 | } 76 | is String -> { 77 | val uri = Uri.parse(remoteTarget) 78 | builder = ImageRequestBuilder.newBuilderWithSource(uri) 79 | } 80 | } 81 | if (loadOption.mSize != null) { 82 | builder?.resizeOptions = ResizeOptions(loadOption.mSize!!.x, loadOption.mSize!!.y) 83 | } else { 84 | builder?.resizeOptions = null 85 | } 86 | if(loadOption.mTransformations.isNotEmpty()) { 87 | builder?.postprocessor = loadOption.mTransformations[0] as BasePostprocessor 88 | } 89 | extendOption?.let { 90 | extendOption.onOptionsInit(builder) 91 | } 92 | return builder?.build() 93 | } 94 | 95 | fun buildLowImageRequest(simpleDraweeView: SimpleDraweeView, loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): ImageRequest? { 96 | /*var lowThumbnail: String? = null 97 | if (TextUtils.isEmpty(fresco.getLowThumbnailUrl())) { 98 | return null 99 | } 100 | lowThumbnail = fresco.getLowThumbnailUrl() 101 | val uri = Uri.parse(lowThumbnail) 102 | return ImageRequest.fromUri(uri)*/ 103 | return null 104 | } 105 | 106 | fun buildDraweeController(simpleDraweeView: SimpleDraweeView, loadOption: GSYLoadOption, callback: GSYImageLoader.Callback?, 107 | imageRequest: ImageRequest?, lowRequest: ImageRequest?): DraweeController { 108 | return Fresco.newDraweeControllerBuilder() 109 | .setImageRequest(imageRequest) 110 | .setAutoPlayAnimations(loadOption.isPlayGif) 111 | //.setTapToRetryEnabled(fresco.getTapToRetryEnabled()) 112 | .setLowResImageRequest(lowRequest) 113 | .setControllerListener(object : ControllerListener { 114 | override fun onSubmit(id: String?, callerContext: Any?) { 115 | callback?.onStart() 116 | } 117 | 118 | override fun onFinalImageSet(id: String?, imageInfo: Any?, animatable: Animatable?) { 119 | callback?.onSuccess(Exception(id)) 120 | } 121 | 122 | override fun onRelease(id: String?) { 123 | 124 | } 125 | 126 | override fun onIntermediateImageFailed(id: String?, throwable: Throwable?) { 127 | callback?.onFail(Exception(throwable)) 128 | } 129 | 130 | override fun onFailure(id: String?, throwable: Throwable?) { 131 | callback?.onFail(Exception(throwable)) 132 | } 133 | 134 | override fun onIntermediateImageSet(id: String?, imageInfo: Any?) { 135 | callback?.onSuccess(id) 136 | } 137 | }) 138 | .setOldController(simpleDraweeView.controller) 139 | .build() 140 | } 141 | 142 | fun getRoundingParams(simpleDraweeView: SimpleDraweeView): RoundingParams { 143 | var roundingParams = simpleDraweeView.hierarchy.roundingParams 144 | if (roundingParams == null) { 145 | roundingParams = RoundingParams() 146 | } 147 | return roundingParams 148 | } 149 | 150 | fun setRoundingParmas(simpleDraweeView: SimpleDraweeView, roundingParmas: RoundingParams?) { 151 | simpleDraweeView.hierarchy.roundingParams = roundingParmas 152 | } 153 | } -------------------------------------------------------------------------------- /GSYFrescoImageLoader/src/main/java/com/shuyu/gsyfrescoimageloader/GSYFrescoImageLoader.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyfrescoimageloader 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import com.facebook.binaryresource.FileBinaryResource 6 | import com.facebook.common.executors.CallerThreadExecutor 7 | import com.facebook.datasource.BaseDataSubscriber 8 | import com.facebook.datasource.DataSource 9 | import com.facebook.drawee.backends.pipeline.Fresco 10 | import com.facebook.drawee.view.SimpleDraweeView 11 | import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory 12 | import com.facebook.imagepipeline.core.ImagePipelineConfig 13 | import com.facebook.imagepipeline.core.ImagePipelineFactory 14 | import com.facebook.imagepipeline.image.CloseableBitmap 15 | import com.facebook.imagepipeline.request.ImageRequest 16 | import com.shuyu.gsyimageloader.GSYImageConst 17 | import com.shuyu.gsyimageloader.GSYImageLoader 18 | import com.shuyu.gsyimageloader.GSYLoadOption 19 | import java.io.File 20 | 21 | /** 22 | * Fresco 图片加载 23 | * Created by guoshuyu on 2018/1/19. 24 | */ 25 | class GSYFrescoImageLoader(private val context: Context, private var config: ImagePipelineConfig? = null) : GSYImageLoader, GSYFrescoFactory { 26 | 27 | init { 28 | if (config == null) { 29 | config = ImagePipelineConfig.newBuilder(context.applicationContext) 30 | .setDownsampleEnabled(true) 31 | .build() 32 | } 33 | Fresco.initialize(context.applicationContext, config) 34 | } 35 | 36 | override fun loadImage(loadOption: GSYLoadOption, target: Any?, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 37 | val frescoView = target as SimpleDraweeView 38 | try { 39 | initFrescoView(frescoView, loadOption) 40 | val request = buildImageRequestWithResource(loadOption, extendOption) 41 | val lowRequest = buildLowImageRequest(frescoView, loadOption, extendOption) 42 | frescoView.controller = buildDraweeController(frescoView, loadOption, callback, request, lowRequest) 43 | } catch (e: Exception) { 44 | e.printStackTrace() 45 | } 46 | } 47 | 48 | override fun clearCache(type: Int) { 49 | when (type) { 50 | GSYImageConst.CLEAR_ALL_CACHE -> { 51 | Fresco.getImagePipeline().clearCaches() 52 | } 53 | GSYImageConst.CLEAR_MEMORY_CACHE -> 54 | Fresco.getImagePipeline().clearMemoryCaches() 55 | GSYImageConst.CLEAR_DISK_CACHE -> 56 | Fresco.getImagePipeline().clearDiskCaches() 57 | } 58 | } 59 | 60 | override fun clearCacheKey(type: Int, loadOption: GSYLoadOption) { 61 | val loadUri = getUri(loadOption.mUri) 62 | when (type) { 63 | GSYImageConst.CLEAR_ALL_CACHE -> { 64 | Fresco.getImagePipeline().evictFromCache(loadUri) 65 | } 66 | GSYImageConst.CLEAR_MEMORY_CACHE -> 67 | Fresco.getImagePipeline().evictFromMemoryCache(loadUri) 68 | GSYImageConst.CLEAR_DISK_CACHE -> 69 | Fresco.getImagePipeline().evictFromDiskCache(loadUri) 70 | 71 | } 72 | } 73 | 74 | override fun isCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Boolean { 75 | val loadUri = getUri(loadOption.mUri) 76 | return isCached(context, loadUri) 77 | } 78 | 79 | override fun getLocalCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): File? { 80 | val loadUri = getUri(loadOption.mUri) 81 | if (!isCached(context, loadUri)) 82 | return null 83 | val imageRequest = ImageRequest.fromUri(loadUri) 84 | val cacheKey = DefaultCacheKeyFactory.getInstance() 85 | .getEncodedCacheKey(imageRequest, context) 86 | val resource = ImagePipelineFactory.getInstance() 87 | .mainFileCache.getResource(cacheKey) 88 | return (resource as FileBinaryResource).file 89 | } 90 | 91 | override fun getLocalCacheBitmap(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Bitmap? { 92 | val loadUri = getUri(loadOption.mUri) 93 | if (!isCached(context, loadUri)) 94 | return null 95 | val request = buildImageRequestWithResource(loadOption, extendOption) 96 | val cacheKey = DefaultCacheKeyFactory.getInstance() 97 | .getBitmapCacheKey(request, context) 98 | val resource = ImagePipelineFactory.getInstance() 99 | .bitmapCountingMemoryCache.get(cacheKey) 100 | return (resource?.get() as CloseableBitmap).underlyingBitmap 101 | } 102 | 103 | 104 | override fun getCacheSize(): Long? { 105 | return ImagePipelineFactory.getInstance() 106 | .mainFileCache.size 107 | } 108 | 109 | override fun downloadOnly(loadOption: GSYLoadOption, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 110 | val imageRequest = buildImageRequestWithResource(loadOption, extendOption) 111 | val imagePipeline = Fresco.getImagePipeline() 112 | val dataSource2 = imagePipeline.prefetchToDiskCache(imageRequest, context) 113 | dataSource2.subscribe(object : BaseDataSubscriber() { 114 | override fun onNewResultImpl(dataSource: DataSource) { 115 | val file = getLocalCache(loadOption, extendOption) 116 | callback?.onSuccess(file) 117 | } 118 | 119 | override fun onFailureImpl(dataSource: DataSource) { 120 | callback?.onFail(null) 121 | } 122 | }, CallerThreadExecutor.getInstance()) 123 | 124 | } 125 | } -------------------------------------------------------------------------------- /GSYFrescoImageLoader/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GSYFrescoImageLoader 3 | 4 | -------------------------------------------------------------------------------- /GSYGlideLoader/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /GSYGlideLoader/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | 9 | def globalConfiguration = rootProject.extensions.getByName("ext") 10 | compileSdkVersion globalConfiguration.androidCompileSdkVersion 11 | buildToolsVersion globalConfiguration.androidBuildToolsVersion 12 | 13 | defaultConfig { 14 | 15 | minSdkVersion globalConfiguration.androidMinSdkVersion 16 | targetSdkVersion globalConfiguration.androidTargetSdkVersion 17 | 18 | versionCode 1 19 | versionName "1.0" 20 | 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | sourceSets { 29 | main { 30 | jniLibs.srcDirs = ['libs'] 31 | } 32 | } 33 | 34 | } 35 | 36 | dependencies { 37 | implementation fileTree(dir: 'libs', include: ['*.jar']) 38 | def androidDependencies = rootProject.ext.androidDependencies 39 | def dataDependencies = rootProject.ext.dataDependencies 40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 41 | implementation androidDependencies.appcompat_v7 42 | api dataDependencies.glide 43 | api dataDependencies.glideIntegration 44 | 45 | implementation project(':GSYImageLoader') 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /GSYGlideLoader/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /GSYGlideLoader/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /GSYGlideLoader/src/main/java/com/shuyu/gsygiideloader/GSYGlideCacheKey.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsygiideloader 2 | 3 | import com.bumptech.glide.load.Key 4 | import java.security.MessageDigest 5 | 6 | /** 7 | * Glide原图缓存Key 8 | * Created by guoshuyu on 2018/1/22. 9 | */ 10 | class GSYGlideCacheKey constructor(private val id: String, private val signature: Key) : Key { 11 | 12 | override fun equals(o: Any?): Boolean { 13 | if (this === o) { 14 | return true 15 | } 16 | if (o == null || javaClass != o.javaClass) { 17 | return false 18 | } 19 | 20 | val that = o as GSYGlideCacheKey? 21 | 22 | return id == that!!.id && signature == that.signature 23 | } 24 | 25 | override fun hashCode(): Int { 26 | var result = id.hashCode() 27 | result = 31 * result + signature.hashCode() 28 | return result 29 | } 30 | 31 | override fun updateDiskCacheKey(messageDigest: MessageDigest) { 32 | messageDigest.update(id.toByteArray(charset(Key.STRING_CHARSET_NAME))) 33 | signature.updateDiskCacheKey(messageDigest) 34 | } 35 | } -------------------------------------------------------------------------------- /GSYGlideLoader/src/main/java/com/shuyu/gsygiideloader/GSYGlideImageLoader.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsygiideloader 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.drawable.Drawable 6 | import android.widget.ImageView 7 | import com.bumptech.glide.Glide 8 | import com.bumptech.glide.RequestManager 9 | import com.bumptech.glide.disklrucache.DiskLruCache 10 | import com.bumptech.glide.load.DataSource 11 | import com.bumptech.glide.load.MultiTransformation 12 | import com.bumptech.glide.load.Transformation 13 | import com.bumptech.glide.load.engine.GlideException 14 | import com.bumptech.glide.request.RequestListener 15 | import com.bumptech.glide.request.RequestOptions 16 | import com.bumptech.glide.request.target.Target 17 | import com.shuyu.gsyimageloader.GSYImageConst 18 | import com.shuyu.gsyimageloader.GSYImageLoader 19 | import com.shuyu.gsyimageloader.GSYLoadOption 20 | import java.lang.IllegalStateException 21 | import java.io.File 22 | import com.bumptech.glide.signature.EmptySignature 23 | import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper 24 | import com.bumptech.glide.load.engine.cache.MemoryCache 25 | import com.shuyu.gsyimageloader.GSYReflectionHelpers 26 | 27 | 28 | /** 29 | * Glide 图片加载 30 | * Created by guoshuyu on 2018/1/18. 31 | */ 32 | class GSYGlideImageLoader(private val context: Context) : GSYImageLoader { 33 | 34 | 35 | override fun loadImage(loadOption: GSYLoadOption, target: Any?, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 36 | if (target !is ImageView) { 37 | throw IllegalStateException("target must be ImageView") 38 | } 39 | loadImage(loadOption, extendOption) 40 | .load(loadOption.mUri) 41 | .listener(object : RequestListener { 42 | override fun onLoadFailed(e: GlideException?, model: Any, target: Target, isFirstResource: Boolean): Boolean { 43 | callback?.let { 44 | it.onFail(e) 45 | } 46 | return false 47 | } 48 | 49 | override fun onResourceReady(resource: Drawable, model: Any, target: Target, dataSource: DataSource, isFirstResource: Boolean): Boolean { 50 | callback?.let { 51 | it.onSuccess(resource) 52 | } 53 | return false 54 | } 55 | }) 56 | .into(target) 57 | } 58 | 59 | override fun clearCache(type: Int) { 60 | when (type) { 61 | GSYImageConst.CLEAR_ALL_CACHE -> { 62 | Glide.get(context.applicationContext).clearMemory() 63 | Glide.get(context.applicationContext).clearDiskCache() 64 | } 65 | GSYImageConst.CLEAR_MEMORY_CACHE -> 66 | Glide.get(context.applicationContext).clearMemory() 67 | GSYImageConst.CLEAR_DISK_CACHE -> 68 | Glide.get(context.applicationContext).clearDiskCache() 69 | } 70 | } 71 | 72 | override fun clearCacheKey(type: Int, loadOption: GSYLoadOption) { 73 | val deleteDisk = { 74 | val diskCache = DiskLruCacheWrapper.create(Glide.getPhotoCacheDir(context), (250 * 1024 * 1024).toLong()) 75 | val key = GSYGlideCacheKey(loadOption.mUri as String, EmptySignature.obtain()) 76 | diskCache.delete(key) 77 | } 78 | val deleteMemory = { 79 | try { 80 | val key = GSYGlideCacheKey(loadOption.mUri as String, EmptySignature.obtain()); 81 | val cache = GSYReflectionHelpers.getField(Glide.get(context.applicationContext), "memoryCache") 82 | cache.remove(key) 83 | } catch (e: Exception) { 84 | e.printStackTrace() 85 | } 86 | } 87 | when (type) { 88 | GSYImageConst.CLEAR_ALL_CACHE -> { 89 | deleteMemory.invoke() 90 | deleteDisk.invoke() 91 | } 92 | GSYImageConst.CLEAR_MEMORY_CACHE -> { 93 | deleteMemory() 94 | } 95 | GSYImageConst.CLEAR_DISK_CACHE -> { 96 | deleteDisk.invoke() 97 | } 98 | 99 | } 100 | } 101 | 102 | override fun getLocalCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): File? { 103 | val future = loadImage(loadOption, extendOption) 104 | .asFile().load(loadOption.mUri) 105 | return future.submit().get() 106 | } 107 | 108 | 109 | override fun isCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Boolean { 110 | // 寻找缓存图片 111 | val file = DiskLruCacheWrapper.create(Glide.getPhotoCacheDir(context), (250 * 1024 * 1024).toLong()) 112 | .get(GSYGlideCacheKey(loadOption.mUri as String, EmptySignature.obtain())) 113 | return file != null 114 | } 115 | 116 | override fun getLocalCacheBitmap(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Bitmap? { 117 | val future = loadImage(loadOption, extendOption) 118 | .asBitmap().load(loadOption.mUri) 119 | return future.submit().get() 120 | } 121 | 122 | 123 | override fun getCacheSize(): Long? { 124 | val cache = DiskLruCacheWrapper.create(Glide.getPhotoCacheDir(context), (250 * 1024 * 1024).toLong()) 125 | val diskLruCache = GSYReflectionHelpers.getField(cache, "diskLruCache") 126 | return diskLruCache.size() 127 | } 128 | 129 | override fun downloadOnly(loadOption: GSYLoadOption, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 130 | loadImage(loadOption, extendOption).downloadOnly().load(loadOption.mUri).into(GSYImageDownLoadTarget(callback)) 131 | } 132 | 133 | private fun loadImage(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): RequestManager { 134 | return Glide.with(context.applicationContext) 135 | .setDefaultRequestOptions(getOption(loadOption, extendOption)) 136 | } 137 | 138 | @SuppressWarnings("CheckResult") 139 | private fun getOption(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): RequestOptions { 140 | val requestOptions = RequestOptions() 141 | if (loadOption.mErrorImg > 0) { 142 | requestOptions.error(loadOption.mErrorImg) 143 | } 144 | if (loadOption.mDefaultImg > 0) { 145 | requestOptions.placeholder(loadOption.mDefaultImg) 146 | } 147 | if (loadOption.isCircle) { 148 | requestOptions.circleCrop() 149 | } 150 | loadOption.mSize?.let { 151 | requestOptions.override(it.x, it.y) 152 | } 153 | if(loadOption.mTransformations.isNotEmpty()) { 154 | requestOptions.transform(MultiTransformation(loadOption.mTransformations as ArrayList>)) 155 | } 156 | extendOption?.let { 157 | extendOption.onOptionsInit(requestOptions) 158 | } 159 | return requestOptions 160 | } 161 | 162 | } 163 | 164 | -------------------------------------------------------------------------------- /GSYGlideLoader/src/main/java/com/shuyu/gsygiideloader/GSYImageDownLoadTarget.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsygiideloader 2 | 3 | import android.graphics.drawable.Drawable 4 | 5 | import com.bumptech.glide.request.target.SimpleTarget 6 | import com.bumptech.glide.request.transition.Transition 7 | import com.shuyu.gsyimageloader.GSYImageLoader 8 | 9 | import java.io.File 10 | 11 | /** 12 | * Glide 图片下载对象 13 | * Created by guoshuyu on 2018/1/18. 14 | */ 15 | class GSYImageDownLoadTarget constructor(private val mCallback: GSYImageLoader.Callback?) : SimpleTarget() { 16 | 17 | override fun onResourceReady(resource: File, transition: Transition?) { 18 | mCallback?.onSuccess(resource) 19 | } 20 | 21 | override fun onLoadStarted(placeholder: Drawable?) { 22 | super.onLoadStarted(placeholder) 23 | mCallback?.onStart() 24 | } 25 | 26 | override fun onLoadFailed(errorDrawable: Drawable?) { 27 | super.onLoadFailed(errorDrawable) 28 | mCallback?.onFail(null) 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /GSYGlideLoader/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GSYGIideLoader 3 | 4 | -------------------------------------------------------------------------------- /GSYImageLoader/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /GSYImageLoader/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | 9 | def globalConfiguration = rootProject.extensions.getByName("ext") 10 | compileSdkVersion globalConfiguration.androidCompileSdkVersion 11 | buildToolsVersion globalConfiguration.androidBuildToolsVersion 12 | 13 | defaultConfig { 14 | 15 | minSdkVersion globalConfiguration.androidMinSdkVersion 16 | targetSdkVersion globalConfiguration.androidTargetSdkVersion 17 | 18 | versionCode 1 19 | versionName "1.0" 20 | 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | sourceSets { 29 | main { 30 | jniLibs.srcDirs = ['libs'] 31 | } 32 | } 33 | 34 | } 35 | 36 | dependencies { 37 | implementation fileTree(dir: 'libs', include: ['*.jar']) 38 | def androidDependencies = rootProject.ext.androidDependencies 39 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 40 | implementation androidDependencies.appcompat_v7 41 | 42 | } 43 | -------------------------------------------------------------------------------- /GSYImageLoader/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /GSYImageLoader/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYImageConst.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyimageloader 2 | 3 | /** 4 | * 静态工具类 5 | * Created by guoshuyu on 2018/1/18. 6 | */ 7 | class GSYImageConst { 8 | companion object { 9 | /** 10 | * 清除内存与本地 11 | */ 12 | const val CLEAR_ALL_CACHE = 1 13 | /** 14 | * 清除内存 15 | */ 16 | const val CLEAR_MEMORY_CACHE = 2 17 | /** 18 | * 清除本地 19 | */ 20 | const val CLEAR_DISK_CACHE = 3 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYImageLoader.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyimageloader 2 | 3 | 4 | import android.graphics.Bitmap 5 | import android.support.annotation.UiThread 6 | import java.io.File 7 | 8 | /** 9 | * 图片加载接口 10 | * Created by guoshuyu on 2018/1/18. 11 | */ 12 | interface GSYImageLoader { 13 | 14 | /** 15 | * 加载图片 16 | * @param loadOption 加载图片配置 17 | * @param target 加载目标对象,ImageView or SimpleDraweeView 18 | * @param callback 加载回调 19 | * @param extendOption 额外配置接口 20 | */ 21 | fun loadImage(loadOption: GSYLoadOption, target: Any?, callback: Callback?, extendOption: ExtendedOptions? = null) 22 | 23 | /** 24 | * 清除缓存 25 | * @param type GSYImageConst,清除类型 26 | */ 27 | fun clearCache(type: Int = GSYImageConst.CLEAR_DISK_CACHE) 28 | 29 | /** 30 | * 清除指定缓存 31 | * @param type GSYImageConst,清除类型 32 | * @param loadOption 加载图片配置 33 | */ 34 | fun clearCacheKey(type: Int = GSYImageConst.CLEAR_DISK_CACHE, loadOption: GSYLoadOption) 35 | 36 | /** 37 | * 是否已经缓存到本地 38 | * @param loadOption 加载图片配置 39 | * @param extendOption 额外配置接口 40 | * @return Boolean 是否已经缓存到本地 41 | */ 42 | fun isCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions? = null): Boolean 43 | 44 | /** 45 | * 获取本地缓存 46 | * @param loadOption 加载图片配置 47 | * @param extendOption 额外配置接口 48 | * @return File 49 | */ 50 | fun getLocalCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions? = null): File? 51 | 52 | /** 53 | * 获取本地缓存bitmap 54 | * @param loadOption 加载图片配置 55 | * @param extendOption 额外配置接口 56 | * @return Bitmap 57 | */ 58 | fun getLocalCacheBitmap(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions? = null): Bitmap? 59 | 60 | 61 | /** 62 | * 获取本地缓存大小 63 | * @return Long 64 | */ 65 | fun getCacheSize(): Long? 66 | 67 | 68 | /** 69 | * 下载图片 70 | * @param loadOption 加载图片配置 71 | * @param callback 加载回调 72 | * @param extendOption 额外配置接口 73 | * @return Bitmap 74 | */ 75 | fun downloadOnly(loadOption: GSYLoadOption, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions? = null) 76 | 77 | /** 78 | * 额外配置支持 79 | */ 80 | interface ExtendedOptions { 81 | /** 82 | * @param option 配置对象 83 | * Glide com.bumptech.glide.request.RequestOptions 84 | * Picasso com.squareup.picasso.RequestCreator 85 | * Fresco com.facebook.imagepipeline.request.ImageRequestBuilder 86 | */ 87 | fun onOptionsInit(option: Any?) 88 | } 89 | 90 | /** 91 | * 回调接口 92 | */ 93 | @UiThread 94 | interface Callback { 95 | fun onStart() 96 | 97 | fun onSuccess(result: Any?) 98 | 99 | fun onFail(error: Exception?) 100 | } 101 | } -------------------------------------------------------------------------------- /GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYImageLoaderManager.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyimageloader 2 | 3 | import kotlin.properties.Delegates 4 | 5 | /** 6 | * 图片加载管理 7 | * Created by guoshuyu on 2018/1/18. 8 | */ 9 | class GSYImageLoaderManager private constructor(private var mImageLoader: GSYImageLoader) : GSYImageLoader by mImageLoader { 10 | 11 | companion object { 12 | //委托notNull,这个值在被获取之前没有被分配,它就会抛出一个异常。 13 | var sInstance: GSYImageLoaderManager by Delegates.notNull() 14 | 15 | /** 16 | * 静态初始化、建议Application中初始化 17 | * @param imageLoader 内含GSYPicassoImageLoader、GSYFrescoImageLoader、GSYPicassoImageLoader 18 | */ 19 | fun initialize(imageLoader: GSYImageLoader) { 20 | sInstance = GSYImageLoaderManager(imageLoader) 21 | } 22 | } 23 | 24 | /** 25 | * 图片加载对象 26 | */ 27 | fun imageLoader(): GSYImageLoader { 28 | return this 29 | } 30 | 31 | /** 32 | * 强制转换的图片加载对象 33 | */ 34 | fun imageLoaderExtend(): T { 35 | return this as T 36 | } 37 | } -------------------------------------------------------------------------------- /GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYLoadOption.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyimageloader 2 | 3 | import android.graphics.Point 4 | 5 | /** 6 | * 图片加载配置 7 | */ 8 | class GSYLoadOption { 9 | 10 | //默认图片 11 | var mDefaultImg: Int = 0 12 | 13 | //错误图片 14 | var mErrorImg: Int = 0 15 | 16 | //是否圆形 17 | var isCircle: Boolean = false 18 | 19 | //是否播放gif 20 | var isPlayGif: Boolean = true 21 | 22 | //大小 23 | var mSize: Point? = null 24 | 25 | //图片 26 | var mUri: Any? = null 27 | 28 | val mTransformations: ArrayList = ArrayList() 29 | 30 | fun setDefaultImg(defaultImg: Int): GSYLoadOption { 31 | this.mDefaultImg = defaultImg 32 | return this 33 | } 34 | 35 | fun setErrorImg(errorImg: Int): GSYLoadOption { 36 | this.mErrorImg = errorImg 37 | return this 38 | } 39 | 40 | /** 41 | * 是否圆形,目前支持fresco 、 glide 42 | */ 43 | fun setCircle(circle: Boolean): GSYLoadOption { 44 | isCircle = circle 45 | return this 46 | } 47 | 48 | /** 49 | * 是否播放gif,只支持Fresco目前 50 | */ 51 | fun setPlayGif(playGif: Boolean): GSYLoadOption { 52 | isPlayGif = playGif 53 | return this 54 | } 55 | 56 | /** 57 | * 目标尺寸 58 | */ 59 | fun setSize(size: Point?): GSYLoadOption { 60 | this.mSize = size 61 | return this 62 | } 63 | 64 | /** 65 | * 播放目标 string、uri、int 66 | */ 67 | fun setUri(uri: Any): GSYLoadOption { 68 | this.mUri = uri 69 | return this 70 | } 71 | 72 | /** 73 | * 图片处理 74 | * picasso https://github.com/wasabeef/picasso-transformations 75 | * glide https://github.com/wasabeef/glide-transformations 76 | * fresco https://github.com/wasabeef/fresco-processors 77 | */ 78 | fun setTransformations(transform: Any): GSYLoadOption { 79 | mTransformations.add(transform) 80 | return this 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /GSYImageLoader/src/main/java/com/shuyu/gsyimageloader/GSYReflectionHelpers.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsyimageloader 2 | 3 | import java.lang.reflect.Field 4 | import java.lang.reflect.InvocationTargetException 5 | import java.lang.reflect.Modifier 6 | import java.lang.reflect.Proxy 7 | import java.util.Collections 8 | import java.util.HashMap 9 | 10 | /** 11 | * Collection of helper methods for calling methods and accessing fields reflectively. 12 | */ 13 | object GSYReflectionHelpers { 14 | private val PRIMITIVE_RETURN_VALUES = Collections.unmodifiableMap(object : HashMap() { 15 | init { 16 | put("boolean", java.lang.Boolean.FALSE) 17 | put("int", 0) 18 | put("long", 0.toLong()) 19 | put("float", 0.toFloat()) 20 | put("double", 0.toDouble()) 21 | put("short", 0.toShort()) 22 | put("byte", 0.toByte()) 23 | } 24 | })!! 25 | 26 | fun createNullProxy(clazz: Class): T { 27 | return Proxy.newProxyInstance(clazz.classLoader, 28 | arrayOf>(clazz)) { proxy, method, args -> PRIMITIVE_RETURN_VALUES[method.returnType.name] } as T 29 | } 30 | 31 | fun defaultsFor(annotation: Class): A { 32 | return annotation.cast( 33 | Proxy.newProxyInstance(annotation.classLoader, arrayOf>(annotation) 34 | ) { proxy, method, args -> method.defaultValue }) 35 | } 36 | 37 | /** 38 | * Reflectively get the value of a field. 39 | * 40 | * @param object Target object. 41 | * @param fieldName The field name. 42 | * @param The return type. 43 | * @return Value of the field on the object. 44 | */ 45 | fun getField(`object`: Any, fieldName: String): R { 46 | try { 47 | return traverseClassHierarchy(`object`.javaClass, NoSuchFieldException::class.java, object : InsideTraversal { 48 | @Throws(Exception::class) 49 | override fun run(traversalClass: Class<*>): R { 50 | val field = traversalClass.getDeclaredField(fieldName) 51 | field.isAccessible = true 52 | return field.get(`object`) as R 53 | } 54 | }) 55 | } catch (e: Exception) { 56 | throw RuntimeException(e) 57 | } 58 | 59 | } 60 | 61 | /** 62 | * Reflectively set the value of a field. 63 | * 64 | * @param object Target object. 65 | * @param fieldName The field name. 66 | * @param fieldNewValue New value. 67 | */ 68 | fun setField(`object`: Any, fieldName: String, fieldNewValue: Any) { 69 | try { 70 | traverseClassHierarchy(`object`.javaClass, NoSuchFieldException::class.java, object : InsideTraversal { 71 | @Throws(Exception::class) 72 | override fun run(traversalClass: Class<*>): Any? { 73 | val field = traversalClass.getDeclaredField(fieldName) 74 | field.isAccessible = true 75 | field.set(`object`, fieldNewValue) 76 | return null 77 | } 78 | }) 79 | } catch (e: Exception) { 80 | throw RuntimeException(e) 81 | } 82 | 83 | } 84 | 85 | /** 86 | * Reflectively set the value of a field. 87 | * 88 | * @param type Target type. 89 | * @param object Target object. 90 | * @param fieldName The field name. 91 | * @param fieldNewValue New value. 92 | */ 93 | fun setField(type: Class<*>, `object`: Any, fieldName: String, fieldNewValue: Any) { 94 | try { 95 | val field = type.getDeclaredField(fieldName) 96 | field.isAccessible = true 97 | field.set(`object`, fieldNewValue) 98 | } catch (e: Exception) { 99 | throw RuntimeException(e) 100 | } 101 | 102 | } 103 | 104 | /** 105 | * Reflectively get the value of a static field. 106 | * 107 | * @param field Field object. 108 | * @param The return type. 109 | * @return Value of the field. 110 | */ 111 | fun getStaticField(field: Field): R { 112 | try { 113 | makeFieldVeryAccessible(field) 114 | return field.get(null) as R 115 | } catch (e: Exception) { 116 | throw RuntimeException(e) 117 | } 118 | 119 | } 120 | 121 | /** 122 | * Reflectively get the value of a static field. 123 | * 124 | * @param clazz Target class. 125 | * @param fieldName The field name. 126 | * @param The return type. 127 | * @return Value of the field. 128 | */ 129 | fun getStaticField(clazz: Class<*>, fieldName: String): R { 130 | try { 131 | return getStaticField(clazz.getDeclaredField(fieldName)) 132 | } catch (e: Exception) { 133 | throw RuntimeException(e) 134 | } 135 | 136 | } 137 | 138 | /** 139 | * Reflectively set the value of a static field. 140 | * 141 | * @param field Field object. 142 | * @param fieldNewValue The new value. 143 | */ 144 | fun setStaticField(field: Field, fieldNewValue: Any) { 145 | try { 146 | makeFieldVeryAccessible(field) 147 | field.set(null, fieldNewValue) 148 | } catch (e: Exception) { 149 | throw RuntimeException(e) 150 | } 151 | 152 | } 153 | 154 | /** 155 | * Reflectively set the value of a static field. 156 | * 157 | * @param clazz Target class. 158 | * @param fieldName The field name. 159 | * @param fieldNewValue The new value. 160 | */ 161 | fun setStaticField(clazz: Class<*>, fieldName: String, fieldNewValue: Any) { 162 | try { 163 | setStaticField(clazz.getDeclaredField(fieldName), fieldNewValue) 164 | } catch (e: Exception) { 165 | throw RuntimeException(e) 166 | } 167 | 168 | } 169 | 170 | /** 171 | * Reflectively call an instance method on an object. 172 | * 173 | * @param instance Target object. 174 | * @param methodName The method name to call. 175 | * @param classParameters Array of parameter types and values. 176 | * @param The return type. 177 | * @return The return value of the method. 178 | */ 179 | fun callInstanceMethod(instance: Any, methodName: String, vararg classParameters: ClassParameter<*>): R { 180 | try { 181 | val classes = ClassParameter.getClasses(*classParameters) 182 | val values = ClassParameter.getValues(*classParameters) 183 | 184 | return traverseClassHierarchy(instance.javaClass, NoSuchMethodException::class.java, object : InsideTraversal { 185 | @Throws(Exception::class) 186 | override fun run(traversalClass: Class<*>): R { 187 | val declaredMethod = traversalClass.getDeclaredMethod(methodName, *classes) 188 | declaredMethod.isAccessible = true 189 | return declaredMethod.invoke(instance, *values) as R 190 | } 191 | }) 192 | } catch (e: InvocationTargetException) { 193 | if (e.targetException is RuntimeException) { 194 | throw e.targetException as RuntimeException 195 | } 196 | if (e.targetException is Error) { 197 | throw e.targetException as Error 198 | } 199 | throw RuntimeException(e.targetException) 200 | } catch (e: Exception) { 201 | throw RuntimeException(e) 202 | } 203 | 204 | } 205 | 206 | /** 207 | * Reflectively call an instance method on an object on a specific class. 208 | * 209 | * @param cl The class. 210 | * @param instance Target object. 211 | * @param methodName The method name to call. 212 | * @param classParameters Array of parameter types and values. 213 | * @param The return type. 214 | * @return The return value of the method. 215 | */ 216 | fun callInstanceMethod(cl: Class<*>, instance: Any, methodName: String, vararg classParameters: ClassParameter<*>): R { 217 | try { 218 | val classes = ClassParameter.getClasses(*classParameters) 219 | val values = ClassParameter.getValues(*classParameters) 220 | 221 | val declaredMethod = cl.getDeclaredMethod(methodName, *classes) 222 | declaredMethod.isAccessible = true 223 | return declaredMethod.invoke(instance, *values) as R 224 | } catch (e: InvocationTargetException) { 225 | if (e.targetException is RuntimeException) { 226 | throw e.targetException as RuntimeException 227 | } 228 | if (e.targetException is Error) { 229 | throw e.targetException as Error 230 | } 231 | throw RuntimeException(e.targetException) 232 | } catch (e: Exception) { 233 | throw RuntimeException(e) 234 | } 235 | 236 | } 237 | 238 | /** 239 | * Reflectively call a static method on a class. 240 | * 241 | * @param clazz Target class. 242 | * @param methodName The method name to call. 243 | * @param classParameters Array of parameter types and values. 244 | * @param The return type. 245 | * @return The return value of the method. 246 | */ 247 | fun callStaticMethod(clazz: Class<*>, methodName: String, vararg classParameters: ClassParameter<*>): R { 248 | try { 249 | val classes = ClassParameter.getClasses(*classParameters) 250 | val values = ClassParameter.getValues(*classParameters) 251 | 252 | val method = clazz.getDeclaredMethod(methodName, *classes) 253 | method.isAccessible = true 254 | return method.invoke(null, *values) as R 255 | } catch (e: InvocationTargetException) { 256 | if (e.targetException is RuntimeException) { 257 | throw e.targetException as RuntimeException 258 | } 259 | if (e.targetException is Error) { 260 | throw e.targetException as Error 261 | } 262 | throw RuntimeException(e.targetException) 263 | } catch (e: Exception) { 264 | throw RuntimeException(e) 265 | } 266 | 267 | } 268 | 269 | /** 270 | * Load a class. 271 | * 272 | * @param classLoader The class loader. 273 | * @param fullyQualifiedClassName The fully qualified class name. 274 | * @return The class object. 275 | */ 276 | fun loadClass(classLoader: ClassLoader, fullyQualifiedClassName: String): Class<*> { 277 | try { 278 | return classLoader.loadClass(fullyQualifiedClassName) 279 | } catch (e: ClassNotFoundException) { 280 | throw RuntimeException(e) 281 | } 282 | 283 | } 284 | 285 | /** 286 | * Create a new instance of a class 287 | * 288 | * @param cl The class object. 289 | * @param The class type. 290 | * @return New class instance. 291 | */ 292 | fun newInstance(cl: Class): T { 293 | try { 294 | return cl.newInstance() 295 | } catch (e: InstantiationException) { 296 | throw RuntimeException(e) 297 | } catch (e: IllegalAccessException) { 298 | throw RuntimeException(e) 299 | } 300 | 301 | } 302 | 303 | /** 304 | * Reflectively call the constructor of an object. 305 | * 306 | * @param clazz Target class. 307 | * @param classParameters Array of parameter types and values. 308 | * @param The return type. 309 | * @return The return value of the method. 310 | */ 311 | fun callConstructor(clazz: Class, vararg classParameters: ClassParameter<*>): R { 312 | try { 313 | val classes = ClassParameter.getClasses(*classParameters) 314 | val values = ClassParameter.getValues(*classParameters) 315 | 316 | val constructor = clazz.getDeclaredConstructor(*classes) 317 | constructor.isAccessible = true 318 | return constructor.newInstance(*values) 319 | } catch (e: InstantiationException) { 320 | throw RuntimeException("error instantiating " + clazz.name, e) 321 | } catch (e: InvocationTargetException) { 322 | if (e.targetException is RuntimeException) { 323 | throw e.targetException as RuntimeException 324 | } 325 | if (e.targetException is Error) { 326 | throw e.targetException as Error 327 | } 328 | throw RuntimeException(e.targetException) 329 | } catch (e: Exception) { 330 | throw RuntimeException(e) 331 | } 332 | 333 | } 334 | 335 | @Throws(Exception::class) 336 | private fun traverseClassHierarchy(targetClass: Class<*>, exceptionClass: Class, insideTraversal: InsideTraversal): R { 337 | var hierarchyTraversalClass: Class<*>? = targetClass 338 | while (true) { 339 | try { 340 | return insideTraversal.run(hierarchyTraversalClass!!) 341 | } catch (e: Exception) { 342 | if (!exceptionClass.isInstance(e)) { 343 | throw e 344 | } 345 | hierarchyTraversalClass = hierarchyTraversalClass!!.superclass 346 | if (hierarchyTraversalClass == null) { 347 | throw RuntimeException(e) 348 | } 349 | } 350 | 351 | } 352 | } 353 | 354 | @Throws(NoSuchFieldException::class, IllegalAccessException::class) 355 | private fun makeFieldVeryAccessible(field: Field) { 356 | field.isAccessible = true 357 | 358 | val modifiersField = Field::class.java.getDeclaredField("modifiers") 359 | modifiersField.isAccessible = true 360 | modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv()) 361 | } 362 | 363 | fun defaultValueForType(returnType: String): Any? { 364 | return PRIMITIVE_RETURN_VALUES[returnType] 365 | } 366 | 367 | private interface InsideTraversal { 368 | @Throws(Exception::class) 369 | fun run(traversalClass: Class<*>): R 370 | } 371 | 372 | /** 373 | * Typed parameter used with reflective method calls. 374 | * 375 | * @param The value of the method parameter. 376 | */ 377 | class ClassParameter(val clazz: Class, val `val`: V) { 378 | companion object { 379 | 380 | fun from(clazz: Class, `val`: V): ClassParameter { 381 | return ClassParameter(clazz, `val`) 382 | } 383 | 384 | fun fromComponentLists(classes: Array>, values: Array): Array?> { 385 | val classParameters = arrayOfNulls>(classes.size) 386 | for (i in classes.indices) { 387 | classParameters[i] = ClassParameter.from(classes[i], values[i]) 388 | } 389 | return classParameters 390 | } 391 | 392 | fun getClasses(vararg classParameters: ClassParameter<*>): Array?> { 393 | val classes = arrayOfNulls>(classParameters.size) 394 | for (i in classParameters.indices) { 395 | val paramClass = classParameters[i].clazz 396 | classes[i] = paramClass 397 | } 398 | return classes 399 | } 400 | 401 | fun getValues(vararg classParameters: ClassParameter<*>): Array { 402 | val values = arrayOfNulls(classParameters.size) 403 | for (i in classParameters.indices) { 404 | val paramValue = classParameters[i].`val` 405 | values[i] = paramValue 406 | } 407 | return values 408 | } 409 | } 410 | } 411 | 412 | /** 413 | * String parameter used with reflective method calls. 414 | * 415 | * @param The value of the method parameter. 416 | */ 417 | class StringParameter(val className: String, val `val`: V) { 418 | companion object { 419 | 420 | fun from(className: String, `val`: V): StringParameter { 421 | return StringParameter(className, `val`) 422 | } 423 | } 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /GSYImageLoader/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GSYImageLoader 3 | 4 | -------------------------------------------------------------------------------- /GSYPicassoLoader/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /GSYPicassoLoader/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | 9 | def globalConfiguration = rootProject.extensions.getByName("ext") 10 | compileSdkVersion globalConfiguration.androidCompileSdkVersion 11 | buildToolsVersion globalConfiguration.androidBuildToolsVersion 12 | 13 | defaultConfig { 14 | 15 | minSdkVersion globalConfiguration.androidMinSdkVersion 16 | targetSdkVersion globalConfiguration.androidTargetSdkVersion 17 | 18 | versionCode 1 19 | versionName "1.0" 20 | 21 | } 22 | buildTypes { 23 | release { 24 | minifyEnabled false 25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | sourceSets { 29 | main { 30 | jniLibs.srcDirs = ['libs'] 31 | } 32 | } 33 | 34 | } 35 | 36 | dependencies { 37 | implementation fileTree(dir: 'libs', include: ['*.jar']) 38 | def androidDependencies = rootProject.ext.androidDependencies 39 | def dataDependencies = rootProject.ext.dataDependencies 40 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 41 | implementation androidDependencies.appcompat_v7 42 | api dataDependencies.picasso 43 | 44 | implementation project(':GSYImageLoader') 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /GSYPicassoLoader/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /GSYPicassoLoader/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | -------------------------------------------------------------------------------- /GSYPicassoLoader/src/main/java/com/shuyu/gsypicassoloader/GSYPicassoImageLoader.kt: -------------------------------------------------------------------------------- 1 | package com.shuyu.gsypicassoloader 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.drawable.Drawable 6 | import android.net.Uri 7 | import android.util.Log 8 | import android.widget.ImageView 9 | import com.shuyu.gsyimageloader.GSYImageLoader 10 | import com.shuyu.gsyimageloader.GSYLoadOption 11 | import com.shuyu.gsyimageloader.GSYReflectionHelpers 12 | import com.squareup.picasso.* 13 | import com.squareup.picasso.Target 14 | import java.io.File 15 | import java.io.IOException 16 | import java.lang.IllegalStateException 17 | 18 | /** 19 | * Picasso图片加载 20 | * Created by guoshuyu on 2018/1/19. 21 | */ 22 | class GSYPicassoImageLoader(private val context: Context, builder: Picasso.Builder? = null) : GSYImageLoader { 23 | 24 | private var mPicassoLoader: Picasso = if (builder != null) { 25 | builder.build() 26 | } else { 27 | Picasso.with(context) 28 | } 29 | 30 | override fun loadImage(loadOption: GSYLoadOption, target: Any?, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 31 | if (target !is ImageView) { 32 | throw IllegalStateException("target must be ImageView") 33 | } 34 | getRequest(loadOption, extendOption)?.let { 35 | it.into(target, object : Callback { 36 | override fun onSuccess() { 37 | callback?.onSuccess(null) 38 | } 39 | 40 | override fun onError() { 41 | callback?.onFail(null) 42 | } 43 | }) 44 | } 45 | } 46 | 47 | override fun clearCache(type: Int) { 48 | try { 49 | val cache = GSYReflectionHelpers.getField(mPicassoLoader, "cache") 50 | cache.clear() 51 | } catch (e: Exception) { 52 | e.printStackTrace() 53 | } 54 | } 55 | 56 | override fun clearCacheKey(type: Int, loadOption: GSYLoadOption) { 57 | val targetPath: Any? = loadOption.mUri 58 | when (targetPath) { 59 | is File -> { 60 | mPicassoLoader.invalidate(targetPath) 61 | } 62 | is String -> { 63 | mPicassoLoader.invalidate(targetPath) 64 | } 65 | is Uri -> { 66 | mPicassoLoader.invalidate(targetPath) 67 | } 68 | } 69 | } 70 | 71 | override fun getLocalCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): File? { 72 | Log.e(javaClass::getName.toString(), "not support for picasso") 73 | return null 74 | } 75 | 76 | override fun isCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Boolean { 77 | Log.e(javaClass::getName.toString(), "not support for picasso") 78 | return false 79 | } 80 | 81 | override fun getLocalCacheBitmap(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Bitmap? { 82 | var bitmap: Bitmap? = null 83 | try { 84 | bitmap = getRequest(loadOption, extendOption)?.get() 85 | } catch (e: IOException) { 86 | e.printStackTrace() 87 | } 88 | return bitmap 89 | } 90 | 91 | override fun getCacheSize(): Long? { 92 | return mPicassoLoader.snapshot.size.toLong() 93 | } 94 | 95 | override fun downloadOnly(loadOption: GSYLoadOption, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 96 | getRequest(loadOption, extendOption)?.into(object : Target { 97 | override fun onPrepareLoad(placeHolderDrawable: Drawable?) { 98 | callback?.onStart() 99 | } 100 | 101 | override fun onBitmapFailed(errorDrawable: Drawable?) { 102 | callback?.onFail(null); 103 | } 104 | 105 | override fun onBitmapLoaded(bitmap: Bitmap?, from: Picasso.LoadedFrom?) { 106 | callback?.onSuccess(bitmap) 107 | } 108 | }) 109 | } 110 | 111 | private fun getRequest(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): RequestCreator? { 112 | val targetPath: Any? = loadOption.mUri 113 | var request: RequestCreator? = null 114 | when (targetPath) { 115 | is File -> { 116 | request = mPicassoLoader.load(targetPath) 117 | } 118 | is String -> { 119 | request = mPicassoLoader.load(targetPath) 120 | } 121 | is Uri -> { 122 | request = mPicassoLoader.load(targetPath) 123 | } 124 | is Int -> { 125 | request = mPicassoLoader.load(targetPath) 126 | } 127 | } 128 | request?.let { 129 | if (loadOption.mErrorImg > 0) { 130 | it.error(loadOption.mErrorImg) 131 | } 132 | if (loadOption.mDefaultImg > 0) { 133 | it.placeholder(loadOption.mDefaultImg) 134 | } 135 | if (loadOption.isCircle) { 136 | 137 | } 138 | loadOption.mSize?.let { 139 | request?.resize(it.x, it.y) 140 | } 141 | if (loadOption.mTransformations.isNotEmpty()) { 142 | request?.transform(loadOption.mTransformations as List) 143 | } 144 | extendOption?.let { 145 | extendOption.onOptionsInit(request) 146 | } 147 | } 148 | return request 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /GSYPicassoLoader/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | GSYPicassoLoader 3 | 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![](https://github.com/CarGuo/GSYImageLoader/blob/master/logo.png) 3 | 4 | # GSYImageLoader 图片加载管理器 5 | 6 | 集成Glide、Picasso、Fresco的kotlin图片管理器,一键切换图片加载类,提供常用的图片相关功能接口。 7 | 8 | [![](https://jitpack.io/v/CarGuo/GSYImageLoader.svg)](https://jitpack.io/#CarGuo/GSYImageLoader) 9 | [![Build Status](https://travis-ci.org/CarGuo/GSYImageLoader.svg?branch=master)](https://travis-ci.org/CarGuo/GSYImageLoader) 10 | [![GitHub issues](https://img.shields.io/github/issues/CarGuo/GSYImageLoader.svg)](https://github.com/CarGuo/GSYImageLoader/issues) 11 | [![GitHub forks](https://img.shields.io/github/forks/CarGuo/GSYImageLoader.svg)](https://github.com/CarGuo/GSYImageLoader/network) 12 | [![GitHub stars](https://img.shields.io/github/stars/CarGuo/GSYImageLoader.svg)](https://github.com/CarGuo/GSYImageLoader/stargazers) 13 | [![GitHub license](https://img.shields.io/github/license/CarGuo/GSYImageLoader.svg)](https://github.com/CarGuo/GSYImageLoader/blob/master/LICENSE) 14 | 15 | 状态 | 功能 16 | -------- | --- 17 | **已完成**|**Glide相关** 18 | **已完成**|**Picasso相关** 19 | **已完成**|**Fresco相关** 20 | 21 | 22 | ### 一、依赖版本 23 | 24 | #### 1、在project下的build.gradle添加 25 | ``` 26 | allprojects { 27 | repositories { 28 | ... 29 | maven { url 'https://jitpack.io' } 30 | } 31 | } 32 | ``` 33 | #### 2、在module下的build.gradle添加 34 | ``` 35 | dependencies { 36 | implementation 'com.github.CarGuo.GSYImageLoader:GSYGlideLoader:v1.0.1' 37 | 38 | //选择你需要的 39 | implementation 'com.github.CarGuo.GSYImageLoader:GSYPicassoLoader:v1.0.1' 40 | implementation 'com.github.CarGuo.GSYImageLoader:GSYFrescoImageLoader:v1.0.1' 41 | implementation 'com.github.CarGuo.GSYImageLoader:GSYImageLoader:v1.0.1' 42 | } 43 | 44 | ``` 45 | 46 | ### 二、当前版本核心 47 | 48 | * GSYGlideLoader 当前版本 Glide 4.5.0 49 | 50 | * GSYPicassoLoader 当前版本 Picasso 2.5.2 51 | 52 | * GSYFrescoLoader 当前版本 Fresco 1.8.0 53 | 54 | 55 | ### 三、使用方法 56 | 57 | #### 1、在Application中初始化 58 | 59 | ``` 60 | override fun onCreate() { 61 | GSYImageLoaderManager.initialize(GSYGlideImageLoader(this)) 62 | } 63 | ``` 64 | 65 | #### 2、加载图片 66 | 67 | ``` 68 | GSYImageLoaderManager.sInstance.imageLoader().loadImage(loadOption, holder.imageView, object : IGSYImageLoader.Callback { 69 | override fun onStart() { 70 | 71 | } 72 | 73 | override fun onSuccess(result: Any?) { 74 | } 75 | 76 | override fun onFail(error: Exception?) { 77 | } 78 | }) 79 | ``` 80 | 81 | #### 3、更多使用请参考DEMO 82 | 83 | ### [四、API接口](https://github.com/CarGuo/GSYImageLoader/blob/master/API.md) 84 | 85 | ### [五、其他资料-Android图片加载开源库深度推荐](https://www.jianshu.com/p/cd058a924288) 86 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-android-extensions' 6 | 7 | android { 8 | def globalConfiguration = rootProject.extensions.getByName("ext") 9 | compileSdkVersion globalConfiguration.androidCompileSdkVersion 10 | buildToolsVersion globalConfiguration.androidBuildToolsVersion 11 | 12 | defaultConfig { 13 | applicationId "com.example.gsyimageloader" 14 | 15 | minSdkVersion globalConfiguration.androidMinSdkVersion 16 | targetSdkVersion globalConfiguration.androidTargetSdkVersion 17 | 18 | versionCode 1 19 | versionName "1.0" 20 | 21 | javaCompileOptions { 22 | annotationProcessorOptions.includeCompileClasspath = true 23 | } 24 | ndk { 25 | //设置支持的SO库架构 26 | abiFilters 'armeabi', 'armeabi-v7a', 'x86' 27 | } 28 | 29 | } 30 | 31 | buildTypes { 32 | 33 | release { 34 | minifyEnabled false 35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 36 | } 37 | 38 | debug { 39 | minifyEnabled false 40 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 41 | } 42 | } 43 | 44 | sourceSets { 45 | main { 46 | jniLibs.srcDirs = ['libs'] 47 | } 48 | } 49 | } 50 | 51 | dependencies { 52 | def androidDependencies = rootProject.ext.androidDependencies 53 | def dataDependencies = rootProject.ext.dataDependencies 54 | implementation fileTree(dir: 'libs', include: ['*.jar']) 55 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" 56 | implementation androidDependencies.appcompat_v7 57 | implementation androidDependencies.support_v4 58 | implementation androidDependencies.kotlinAnko 59 | 60 | implementation project(':GSYImageLoader') 61 | implementation project(':GSYGlideLoader') 62 | implementation project(':GSYPicassoLoader') 63 | implementation project(':GSYFrescoImageLoader') 64 | 65 | 66 | implementation dataDependencies.universalimageloader 67 | //implementation "com.github.CarGuo.GSYImageLoader:GSYGlideLoader:$gsyImageLoaderVersion" 68 | 69 | //选择你需要的 70 | //implementation "com.github.CarGuo.GSYImageLoader:GSYPicassoLoader:$gsyImageLoaderVersion" 71 | //implementation "com.github.CarGuo.GSYImageLoader:GSYFrescoImageLoader:$gsyImageLoaderVersion" 72 | //implementation "com.github.CarGuo.GSYImageLoader:GSYImageLoader:$gsyImageLoaderVersion" 73 | 74 | implementation dataDependencies.gpuImage 75 | } 76 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/Debuger.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader 2 | 3 | import android.app.Activity 4 | import android.text.TextUtils 5 | import android.util.Log 6 | import android.widget.Toast 7 | 8 | /** 9 | * Debuger log 10 | * Created by guoshuyu on 2018/1/18. 11 | */ 12 | object Debuger { 13 | 14 | private val LOG_TAG = "GSYIMAGELOADER" 15 | 16 | var debugMode = BuildConfig.DEBUG 17 | internal set 18 | 19 | fun enable() { 20 | debugMode = true 21 | } 22 | 23 | fun disable() { 24 | debugMode = false 25 | } 26 | 27 | fun printfLog(tag: String, log: String?) { 28 | if (debugMode && log != null) { 29 | if (!TextUtils.isEmpty(log)) 30 | Log.i(tag, log) 31 | } 32 | } 33 | 34 | fun printfLog(log: String) { 35 | printfLog(LOG_TAG, log) 36 | } 37 | 38 | fun printfWarning(tag: String, log: String?) { 39 | if (debugMode && log != null) { 40 | if (!TextUtils.isEmpty(log)) 41 | Log.w(tag, log) 42 | } 43 | } 44 | 45 | fun printfWarning(log: String) { 46 | printfWarning(LOG_TAG, log) 47 | } 48 | 49 | fun printfError(log: String) { 50 | if (debugMode) { 51 | if (!TextUtils.isEmpty(log)) 52 | Log.e(LOG_TAG, log) 53 | } 54 | } 55 | 56 | fun printfError(Tag: String, log: String) { 57 | if (debugMode) { 58 | if (!TextUtils.isEmpty(log)) 59 | Log.e(Tag, log) 60 | } 61 | } 62 | 63 | fun printfError(log: String, e: Exception) { 64 | if (debugMode) { 65 | if (!TextUtils.isEmpty(log)) 66 | Log.e(LOG_TAG, log) 67 | e.printStackTrace() 68 | } 69 | } 70 | 71 | fun Toast(activity: Activity, log: String) { 72 | if (debugMode) { 73 | if (!TextUtils.isEmpty(log)) 74 | Toast.makeText(activity, log, Toast.LENGTH_SHORT).show() 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/GSYApplication.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader 2 | 3 | import android.app.Application 4 | import com.example.gysimageloader.process.custom.CustomLoader 5 | import com.shuyu.gsyfrescoimageloader.GSYFrescoImageLoader 6 | import com.shuyu.gsygiideloader.GSYGlideImageLoader 7 | import com.shuyu.gsyimageloader.GSYImageLoaderManager 8 | import com.shuyu.gsyimageloader.GSYImageLoader 9 | import com.shuyu.gsypicassoloader.GSYPicassoImageLoader 10 | import kotlin.properties.Delegates 11 | 12 | /** 13 | * 应用的Application 14 | * Created by guoshuyu on 2018/1/18. 15 | */ 16 | class GSYApplication : Application() { 17 | 18 | lateinit var mImageList: List 19 | 20 | companion object { 21 | //委托notNull,这个值在被获取之前没有被分配,它就会抛出一个异常。 22 | var instance: GSYApplication by Delegates.notNull() 23 | var sLoader: GSYImageLoader by Delegates.notNull() 24 | } 25 | 26 | override fun onCreate() { 27 | super.onCreate() 28 | instance = this 29 | mImageList = listOf("http://img4.imgtn.bdimg.com/it/u=1420363952,1374463682&fm=21&gp=0.jpg", 30 | "http://c.hiphotos.baidu.com/zhidao/pic/item/77094b36acaf2eddb990270a8f1001e9380193eb.jpg", 31 | "http://d.hiphotos.baidu.com/zhidao/pic/item/4ec2d5628535e5dd5c955af875c6a7efce1b6258.jpg", 32 | "http://imgsrc.baidu.com/forum/w%3D580/sign=a418fbfeb8014a90813e46b599763971/a8ec8a13632762d04d0ce0f3a1ec08fa513dc648.jpg", 33 | "http://img4.imgtn.bdimg.com/it/u=1420363952,1374463682&fm=21&gp=0.jpg", 34 | "https://user-images.githubusercontent.com/512439/32188373-da40378e-bd64-11e7-88f7-b6c29b81760d.gif", 35 | "http://imgsrc.baidu.com/forum/pic/item/64380cd7912397dd704437ee5982b2b7d0a2871f.jpg", 36 | "http://d.hiphotos.baidu.com/zhidao/pic/item/4ec2d5628535e5dd5c955af875c6a7efce1b6258.jpg", 37 | "http://img.hb.aicdn.com/d2024a8a998c8d3e4ba842e40223c23dfe1026c8bbf3-OudiPA_fw580", 38 | "http://img4.imgtn.bdimg.com/it/u=1420363952,1374463682&fm=21&gp=0.jpg", 39 | "http://c.hiphotos.baidu.com/zhidao/pic/item/77094b36acaf2eddb990270a8f1001e9380193eb.jpg", 40 | "http://d.hiphotos.baidu.com/zhidao/pic/item/4ec2d5628535e5dd5c955af875c6a7efce1b6258.jpg", 41 | "http://imgsrc.baidu.com/forum/w%3D580/sign=a418fbfeb8014a90813e46b599763971/a8ec8a13632762d04d0ce0f3a1ec08fa513dc648.jpg", 42 | "http://img4.imgtn.bdimg.com/it/u=1420363952,1374463682&fm=21&gp=0.jpg", 43 | "http://c.hiphotos.baidu.com/zhidao/pic/item/77094b36acaf2eddb990270a8f1001e9380193eb.jpg", 44 | "http://imgsrc.baidu.com/forum/pic/item/64380cd7912397dd704437ee5982b2b7d0a2871f.jpg", 45 | "http://d.hiphotos.baidu.com/zhidao/pic/item/4ec2d5628535e5dd5c955af875c6a7efce1b6258.jpg", 46 | "http://img.hb.aicdn.com/d2024a8a998c8d3e4ba842e40223c23dfe1026c8bbf3-OudiPA_fw580" 47 | ) 48 | sLoader = getInitImageLoader() 49 | GSYImageLoaderManager.initialize(sLoader) 50 | 51 | } 52 | 53 | private fun getInitImageLoader(): GSYImageLoader { 54 | //return GSYGlideImageLoader(this) 55 | //return GSYPicassoImageLoader(this) 56 | return GSYFrescoImageLoader(this) 57 | //return CustomLoader(this) 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Context 5 | import android.graphics.Bitmap 6 | import android.graphics.Color 7 | import android.graphics.Point 8 | import android.os.Bundle 9 | import android.support.v7.app.AppCompatActivity 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.view.ViewGroup 13 | import android.widget.AdapterView 14 | import android.widget.BaseAdapter 15 | import android.widget.ImageView 16 | import com.bumptech.glide.request.RequestOptions 17 | import com.example.gysimageloader.process.fresco.BrightnessFilterPostprocessor 18 | import com.example.gysimageloader.process.glide.BlurTransformation 19 | import com.example.gysimageloader.process.picasso.ColorFilterTransformations 20 | import com.facebook.drawee.view.SimpleDraweeView 21 | import com.facebook.imagepipeline.common.RotationOptions 22 | import com.facebook.imagepipeline.request.ImageRequestBuilder 23 | import com.shuyu.gsyfrescoimageloader.GSYFrescoImageLoader 24 | import com.shuyu.gsygiideloader.GSYGlideImageLoader 25 | import com.shuyu.gsyimageloader.GSYImageLoaderManager 26 | import com.shuyu.gsyimageloader.GSYImageLoader 27 | import com.shuyu.gsyimageloader.GSYLoadOption 28 | import com.shuyu.gsypicassoloader.GSYPicassoImageLoader 29 | import com.squareup.picasso.RequestCreator 30 | import kotlinx.android.synthetic.main.activity_main.* 31 | import org.jetbrains.anko.async 32 | import java.io.File 33 | 34 | 35 | class MainActivity : AppCompatActivity() { 36 | 37 | companion object { 38 | 39 | /** 40 | * 获取当前加载器 41 | */ 42 | private fun getLoader(): GSYImageLoader { 43 | return GSYImageLoaderManager.sInstance.imageLoader() 44 | } 45 | 46 | /** 47 | * 获取图片加载配置 48 | */ 49 | private fun getOption(url: String, po: Int = 0): GSYLoadOption { 50 | val loadOption = GSYLoadOption() 51 | .setDefaultImg(R.mipmap.ic_launcher) 52 | .setErrorImg(R.mipmap.ic_launcher) 53 | .setCircle(po == 2) 54 | .setSize(if (po == 1) Point(10, 10) else null) 55 | .setUri(url) 56 | val process = getProcess() 57 | if (po == 3) { 58 | process?.let { 59 | loadOption.setTransformations(process) 60 | } 61 | } 62 | return loadOption 63 | } 64 | 65 | /** 66 | * 获取图片处理 67 | */ 68 | private fun getProcess(): Any? { 69 | var process: Any? = null 70 | when (GSYApplication.sLoader) { 71 | is GSYFrescoImageLoader -> { 72 | process = BrightnessFilterPostprocessor(GSYApplication.instance, -0.8f) 73 | } 74 | is GSYGlideImageLoader -> { 75 | process = BlurTransformation() 76 | } 77 | is GSYPicassoImageLoader -> { 78 | process = ColorFilterTransformations(Color.GREEN) 79 | } 80 | } 81 | return process 82 | } 83 | } 84 | 85 | override fun onCreate(savedInstanceState: Bundle?) { 86 | super.onCreate(savedInstanceState) 87 | setContentView(R.layout.activity_main) 88 | 89 | 90 | val adapter = if (GSYApplication.sLoader is GSYFrescoImageLoader) { 91 | ImageFrescoAdapter(this, GSYApplication.instance.mImageList) 92 | } else { 93 | ImageAdapter(this, GSYApplication.instance.mImageList) 94 | } 95 | 96 | 97 | imageList.adapter = adapter 98 | imageList.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ -> 99 | 100 | } 101 | 102 | /** 103 | * 清除缓存 104 | */ 105 | clearCache.setOnClickListener { 106 | async { 107 | getLoader().clearCache() 108 | //getLoader().clearCacheKey(GSYLoadOption = getOption(GSYApplication.instance.mImageList[0])) 109 | //getLoader().clearCacheKey(GSYImageConst.CLEAR_ALL_CACHE, getOption(GSYApplication.instance.mImageList[0])) 110 | //getLoader().clearCache(GSYImageConst.CLEAR_ALL_CACHE) 111 | } 112 | } 113 | 114 | /** 115 | * 获取本地缓存 116 | */ 117 | getCache.setOnClickListener { 118 | val isCache = getLoader().isCache(getOption(GSYApplication.instance.mImageList[0])) 119 | Debuger.printfLog("isCache " + isCache) 120 | Debuger.printfLog("Cache Size " + getLoader().getCacheSize()) 121 | async { 122 | val file = getLoader().getLocalCache(getOption(GSYApplication.instance.mImageList[0])) 123 | file?.let { 124 | Debuger.printfLog(it.absolutePath) 125 | } 126 | } 127 | } 128 | 129 | /** 130 | * 获取bitmap缓存 131 | */ 132 | getBitmap.setOnClickListener { 133 | async { 134 | val file = getLoader().getLocalCacheBitmap(getOption(GSYApplication.instance.mImageList[0])) 135 | file?.let { 136 | Debuger.printfLog(it.toString()) 137 | } 138 | } 139 | } 140 | 141 | /** 142 | * 下载图片 143 | */ 144 | downLoad.setOnClickListener { 145 | getLoader().downloadOnly(getOption(GSYApplication.instance.mImageList[0]), object : GSYImageLoader.Callback { 146 | override fun onStart() { 147 | Debuger.printfLog("download onStart") 148 | } 149 | 150 | override fun onSuccess(result: Any?) { 151 | result?.let { 152 | when (result) { 153 | is File -> { 154 | Debuger.printfLog("download onSuccess " + result.absolutePath) 155 | } 156 | is Bitmap -> { 157 | Debuger.printfLog("download onSuccess " + result.toString()) 158 | } 159 | } 160 | } 161 | } 162 | 163 | override fun onFail(error: Exception?) { 164 | Debuger.printfLog("download onFail") 165 | } 166 | }) 167 | 168 | } 169 | 170 | 171 | } 172 | 173 | /** 174 | * 额外配置处理 175 | */ 176 | class ObjectExtendOption(private val position: Int) : GSYImageLoader.ExtendedOptions { 177 | 178 | /** 179 | * @param option 配置对象 180 | * Glide com.bumptech.glide.request.RequestOptions 181 | * Picasso com.squareup.picasso.RequestCreator 182 | * Fresco com.facebook.imagepipeline.request.ImageRequestBuilder 183 | */ 184 | @SuppressLint("CheckResult") 185 | override fun onOptionsInit(option: Any?) { 186 | when (option) { 187 | is RequestOptions -> { 188 | //Glide 189 | if (position == 6) { 190 | option.circleCrop() 191 | option.override(100, 100) 192 | } 193 | } 194 | is RequestCreator -> { 195 | //Picasso 196 | if (position == 2) { 197 | option.rotate(60F) 198 | } 199 | } 200 | is ImageRequestBuilder -> { 201 | //Fresco 202 | if (position == 2) { 203 | option.rotationOptions = RotationOptions.forceRotation(180) 204 | } else { 205 | option.rotationOptions = null 206 | } 207 | } 208 | } 209 | } 210 | } 211 | 212 | class ImageAdapter(private val context: Context, private val dataList: List) : BaseAdapter() { 213 | 214 | override fun getView(p0: Int, convertView: View?, p2: ViewGroup?): View? { 215 | val holder: ViewHolder 216 | val view: View 217 | if (convertView == null) { 218 | holder = ViewHolder() 219 | view = LayoutInflater.from(context).inflate(R.layout.layout_image_item, null) 220 | holder.imageView = view.findViewById(R.id.image_item) 221 | view.tag = holder 222 | } else { 223 | view = convertView 224 | holder = convertView.tag as ViewHolder 225 | } 226 | val loadOption = getOption(dataList[p0], p0) 227 | getLoader().loadImage(loadOption, holder.imageView, object : GSYImageLoader.Callback { 228 | override fun onStart() { 229 | 230 | } 231 | 232 | override fun onSuccess(result: Any?) { 233 | } 234 | 235 | override fun onFail(error: Exception?) { 236 | } 237 | }, ObjectExtendOption(p0)) 238 | return view 239 | } 240 | 241 | override fun getItem(p0: Int): Any { 242 | return dataList[p0] 243 | } 244 | 245 | override fun getItemId(p0: Int): Long { 246 | return 0 247 | } 248 | 249 | override fun getCount(): Int { 250 | return dataList.size 251 | } 252 | 253 | internal inner class ViewHolder { 254 | var imageView: ImageView? = null 255 | } 256 | } 257 | 258 | 259 | class ImageFrescoAdapter(private val context: Context, private val dataList: List) : BaseAdapter() { 260 | 261 | override fun getView(p0: Int, convertView: View?, p2: ViewGroup?): View? { 262 | val holder: ViewHolder 263 | val view: View 264 | if (convertView == null) { 265 | holder = ViewHolder() 266 | view = LayoutInflater.from(context).inflate(R.layout.layout_fresco_image_item, null) 267 | holder.imageView = view.findViewById(R.id.image_item_fresco) 268 | view.tag = holder 269 | } else { 270 | view = convertView 271 | holder = convertView.tag as ViewHolder 272 | } 273 | val loadOption = getOption(dataList[p0], p0) 274 | getLoader().loadImage(loadOption, holder.imageView, object : GSYImageLoader.Callback { 275 | override fun onStart() { 276 | 277 | } 278 | 279 | override fun onSuccess(result: Any?) { 280 | } 281 | 282 | override fun onFail(error: Exception?) { 283 | } 284 | }, ObjectExtendOption(p0)) 285 | return view 286 | } 287 | 288 | override fun getItem(p0: Int): Any { 289 | return dataList[p0] 290 | } 291 | 292 | override fun getItemId(p0: Int): Long { 293 | return 0 294 | } 295 | 296 | override fun getCount(): Int { 297 | return dataList.size 298 | } 299 | 300 | internal inner class ViewHolder { 301 | var imageView: SimpleDraweeView? = null 302 | } 303 | } 304 | 305 | } 306 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/custom/CustomLoader.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.custom 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.view.View 6 | import android.widget.ImageView 7 | import com.nostra13.universalimageloader.core.DisplayImageOptions 8 | import com.nostra13.universalimageloader.core.ImageLoader 9 | import com.nostra13.universalimageloader.core.ImageLoaderConfiguration 10 | import com.nostra13.universalimageloader.core.assist.FailReason 11 | import com.nostra13.universalimageloader.core.listener.ImageLoadingListener 12 | import com.shuyu.gsyimageloader.GSYImageConst 13 | import com.shuyu.gsyimageloader.GSYImageLoader 14 | import com.shuyu.gsyimageloader.GSYLoadOption 15 | import java.io.File 16 | import java.lang.IllegalStateException 17 | 18 | /** 19 | * 自定义的loader 20 | * Created by guoshuyu on 2018/1/23. 21 | */ 22 | 23 | class CustomLoader(private val context: Context) : GSYImageLoader { 24 | 25 | init { 26 | val config = ImageLoaderConfiguration.Builder(context.applicationContext) 27 | .threadPoolSize(5) 28 | .threadPriority(Thread.MIN_PRIORITY + 3) 29 | .denyCacheImageMultipleSizesInMemory() 30 | .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) 31 | .build() 32 | ImageLoader.getInstance().init(config) 33 | } 34 | 35 | override fun loadImage(loadOption: GSYLoadOption, target: Any?, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 36 | if (target !is ImageView) { 37 | throw IllegalStateException("target must be ImageView") 38 | } 39 | if (loadOption.mUri !is String) { 40 | throw IllegalStateException("loadOption.mUri must be String") 41 | } 42 | ImageLoader.getInstance().displayImage(loadOption.mUri as String, target, object : ImageLoadingListener { 43 | override fun onLoadingComplete(imageUri: String?, view: View?, loadedImage: Bitmap?) { 44 | callback?.onSuccess(loadedImage) 45 | } 46 | 47 | override fun onLoadingStarted(imageUri: String?, view: View?) { 48 | callback?.onStart() 49 | } 50 | 51 | override fun onLoadingCancelled(imageUri: String?, view: View?) { 52 | } 53 | 54 | override fun onLoadingFailed(imageUri: String?, view: View?, failReason: FailReason?) { 55 | callback?.onFail(Exception(failReason?.toString())) 56 | } 57 | }) 58 | } 59 | 60 | override fun clearCache(type: Int) { 61 | when (type) { 62 | GSYImageConst.CLEAR_ALL_CACHE -> { 63 | ImageLoader.getInstance().clearDiskCache() 64 | ImageLoader.getInstance().clearMemoryCache() 65 | } 66 | GSYImageConst.CLEAR_MEMORY_CACHE -> 67 | ImageLoader.getInstance().clearMemoryCache() 68 | GSYImageConst.CLEAR_DISK_CACHE -> 69 | ImageLoader.getInstance().clearDiskCache() 70 | } 71 | } 72 | 73 | override fun clearCacheKey(type: Int, loadOption: GSYLoadOption) { 74 | if (loadOption.mUri !is String) { 75 | throw IllegalStateException("loadOption.mUri must be String") 76 | } 77 | val diskCache = ImageLoader.getInstance().diskCache 78 | val memoryCache = ImageLoader.getInstance().memoryCache 79 | when (type) { 80 | GSYImageConst.CLEAR_ALL_CACHE -> { 81 | memoryCache.remove(loadOption.mUri as String) 82 | diskCache.remove(loadOption.mUri as String) 83 | } 84 | GSYImageConst.CLEAR_MEMORY_CACHE -> 85 | memoryCache.remove(loadOption.mUri as String) 86 | GSYImageConst.CLEAR_DISK_CACHE -> 87 | diskCache.remove(loadOption.mUri as String) 88 | } 89 | } 90 | 91 | override fun isCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Boolean { 92 | if (loadOption.mUri !is String) { 93 | throw IllegalStateException("loadOption.mUri must be String") 94 | } 95 | return ImageLoader.getInstance().diskCache.get(loadOption.mUri as String) != null 96 | } 97 | 98 | override fun getLocalCache(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): File? { 99 | if (loadOption.mUri !is String) { 100 | throw IllegalStateException("loadOption.mUri must be String") 101 | } 102 | return ImageLoader.getInstance().diskCache.get(loadOption.mUri as String) 103 | } 104 | 105 | override fun getLocalCacheBitmap(loadOption: GSYLoadOption, extendOption: GSYImageLoader.ExtendedOptions?): Bitmap? { 106 | if (loadOption.mUri !is String) { 107 | throw IllegalStateException("loadOption.mUri must be String") 108 | } 109 | return ImageLoader.getInstance().memoryCache.get(loadOption.mUri as String) 110 | } 111 | 112 | override fun getCacheSize(): Long? { 113 | return ImageLoader.getInstance().diskCache.directory.length() 114 | } 115 | 116 | override fun downloadOnly(loadOption: GSYLoadOption, callback: GSYImageLoader.Callback?, extendOption: GSYImageLoader.ExtendedOptions?) { 117 | if (loadOption.mUri !is String) { 118 | throw IllegalStateException("loadOption.mUri must be String") 119 | } 120 | ImageLoader.getInstance().loadImage(loadOption.mUri as String, object : ImageLoadingListener { 121 | override fun onLoadingComplete(imageUri: String?, view: View?, loadedImage: Bitmap?) { 122 | callback?.onSuccess(loadedImage) 123 | } 124 | 125 | override fun onLoadingStarted(imageUri: String?, view: View?) { 126 | callback?.onStart() 127 | } 128 | 129 | override fun onLoadingCancelled(imageUri: String?, view: View?) { 130 | } 131 | 132 | override fun onLoadingFailed(imageUri: String?, view: View?, failReason: FailReason?) { 133 | callback?.onFail(Exception(failReason?.toString())) 134 | } 135 | }) 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/fresco/BrightnessFilterPostprocessor.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.fresco 2 | 3 | import android.content.Context 4 | 5 | import com.facebook.cache.common.CacheKey 6 | import com.facebook.cache.common.SimpleCacheKey 7 | 8 | import jp.co.cyberagent.android.gpuimage.GPUImageBrightnessFilter 9 | 10 | /** 11 | * https://github.com/wasabeef/fresco-processors 12 | */ 13 | class BrightnessFilterPostprocessor @JvmOverloads constructor(context: Context, private val brightness: Float = 0.0f) : GPUFilterPostprocessor(context, GPUImageBrightnessFilter()) { 14 | 15 | init { 16 | 17 | val filter = getFilter() 18 | filter.setBrightness(brightness) 19 | } 20 | 21 | override fun getPostprocessorCacheKey(): CacheKey? { 22 | return SimpleCacheKey("brightness=" + brightness) 23 | } 24 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/fresco/GPUFilterPostprocessor.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.fresco 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | 6 | import com.facebook.imagepipeline.request.BasePostprocessor 7 | 8 | import jp.co.cyberagent.android.gpuimage.GPUImage 9 | import jp.co.cyberagent.android.gpuimage.GPUImageFilter 10 | 11 | abstract class GPUFilterPostprocessor(context: Context, private val filter: GPUImageFilter) : BasePostprocessor() { 12 | 13 | private val context: Context = context.applicationContext 14 | 15 | override fun process(dest: Bitmap, source: Bitmap) { 16 | val gpuImage = GPUImage(context) 17 | gpuImage.setImage(source) 18 | gpuImage.setFilter(filter) 19 | val bitmap = gpuImage.bitmapWithFilterApplied 20 | 21 | super.process(dest, bitmap) 22 | } 23 | 24 | override fun getName(): String { 25 | return javaClass.simpleName 26 | } 27 | 28 | fun getFilter(): T { 29 | return filter as T 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/glide/BitmapTransformation.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.glide 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | 6 | import com.bumptech.glide.Glide 7 | import com.bumptech.glide.load.Transformation 8 | import com.bumptech.glide.load.engine.Resource 9 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool 10 | import com.bumptech.glide.load.resource.bitmap.BitmapResource 11 | import com.bumptech.glide.request.target.Target 12 | import com.bumptech.glide.util.Util 13 | 14 | import java.security.MessageDigest 15 | 16 | abstract class BitmapTransformation : Transformation { 17 | 18 | abstract fun key(): String 19 | 20 | override fun transform(context: Context, resource: Resource, outWidth: Int, 21 | outHeight: Int): Resource { 22 | if (!Util.isValidDimensions(outWidth, outHeight)) { 23 | throw IllegalArgumentException( 24 | "Cannot apply transformation on width: " + outWidth + " or height: " + outHeight 25 | + " less than or equal to zero and not Target.SIZE_ORIGINAL") 26 | } 27 | val bitmapPool = Glide.get(context).bitmapPool 28 | val toTransform = resource.get() 29 | val targetWidth = if (outWidth == Target.SIZE_ORIGINAL) toTransform.width else outWidth 30 | val targetHeight = if (outHeight == Target.SIZE_ORIGINAL) toTransform.height else outHeight 31 | val transformed = transform(context.applicationContext, bitmapPool, toTransform, targetWidth, targetHeight) 32 | 33 | val result: Resource? 34 | result = if (toTransform == transformed) { 35 | resource 36 | } else { 37 | BitmapResource.obtain(transformed, bitmapPool) 38 | } 39 | return result!! 40 | } 41 | 42 | protected abstract fun transform(context: Context, pool: BitmapPool, 43 | toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap 44 | 45 | override fun updateDiskCacheKey(messageDigest: MessageDigest) { 46 | messageDigest.update(key().toByteArray()) 47 | } 48 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/glide/BlurTransformation.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.glide 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.Canvas 6 | import android.graphics.Paint 7 | import android.os.Build 8 | import android.renderscript.RSRuntimeException 9 | 10 | import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool 11 | 12 | /** 13 | * https://github.com/wasabeef/glide-transformations 14 | */ 15 | class BlurTransformation @JvmOverloads constructor(private val radius: Int = MAX_RADIUS, private val sampling: Int = DEFAULT_DOWN_SAMPLING) : BitmapTransformation() { 16 | 17 | override fun transform(context: Context, pool: BitmapPool, 18 | toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap { 19 | 20 | val width = toTransform.width 21 | val height = toTransform.height 22 | val scaledWidth = width / sampling 23 | val scaledHeight = height / sampling 24 | 25 | var bitmap: Bitmap? = pool.get(scaledWidth, scaledHeight, Bitmap.Config.ARGB_8888) 26 | 27 | val canvas = Canvas(bitmap!!) 28 | canvas.scale(1 / sampling.toFloat(), 1 / sampling.toFloat()) 29 | val paint = Paint() 30 | paint.flags = Paint.FILTER_BITMAP_FLAG 31 | canvas.drawBitmap(toTransform, 0f, 0f, paint) 32 | 33 | bitmap = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { 34 | try { 35 | RSBlur.blur(context, bitmap, radius) 36 | } catch (e: RSRuntimeException) { 37 | FastBlur.blur(bitmap, radius, true) 38 | } 39 | 40 | } else { 41 | FastBlur.blur(bitmap, radius, true) 42 | } 43 | 44 | return bitmap!! 45 | } 46 | 47 | override fun key(): String { 48 | return "BlurTransformation(radius=$radius, sampling=$sampling)" 49 | } 50 | 51 | companion object { 52 | 53 | private val MAX_RADIUS = 25 54 | private val DEFAULT_DOWN_SAMPLING = 1 55 | } 56 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/glide/FastBlur.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.glide 2 | 3 | import android.graphics.Bitmap 4 | 5 | object FastBlur { 6 | 7 | fun blur(sentBitmap: Bitmap, radius: Int, canReuseInBitmap: Boolean): Bitmap? { 8 | 9 | val bitmap: Bitmap 10 | if (canReuseInBitmap) { 11 | bitmap = sentBitmap 12 | } else { 13 | bitmap = sentBitmap.copy(sentBitmap.config, true) 14 | } 15 | 16 | if (radius < 1) { 17 | return null 18 | } 19 | 20 | val w = bitmap.width 21 | val h = bitmap.height 22 | 23 | val pix = IntArray(w * h) 24 | bitmap.getPixels(pix, 0, w, 0, 0, w, h) 25 | 26 | val wm = w - 1 27 | val hm = h - 1 28 | val wh = w * h 29 | val div = radius + radius + 1 30 | 31 | val r = IntArray(wh) 32 | val g = IntArray(wh) 33 | val b = IntArray(wh) 34 | var rsum: Int 35 | var gsum: Int 36 | var bsum: Int 37 | var x: Int 38 | var y: Int 39 | var i: Int 40 | var p: Int 41 | var yp: Int 42 | var yi: Int 43 | var yw: Int 44 | val vmin = IntArray(Math.max(w, h)) 45 | 46 | var divsum = div + 1 shr 1 47 | divsum *= divsum 48 | val dv = IntArray(256 * divsum) 49 | i = 0 50 | while (i < 256 * divsum) { 51 | dv[i] = i / divsum 52 | i++ 53 | } 54 | 55 | yi = 0 56 | yw = yi 57 | 58 | val stack = Array(div) { IntArray(3) } 59 | var stackpointer: Int 60 | var stackstart: Int 61 | var sir: IntArray 62 | var rbs: Int 63 | val r1 = radius + 1 64 | var routsum: Int 65 | var goutsum: Int 66 | var boutsum: Int 67 | var rinsum: Int 68 | var ginsum: Int 69 | var binsum: Int 70 | 71 | y = 0 72 | while (y < h) { 73 | bsum = 0 74 | gsum = bsum 75 | rsum = gsum 76 | boutsum = rsum 77 | goutsum = boutsum 78 | routsum = goutsum 79 | binsum = routsum 80 | ginsum = binsum 81 | rinsum = ginsum 82 | i = -radius 83 | while (i <= radius) { 84 | p = pix[yi + Math.min(wm, Math.max(i, 0))] 85 | sir = stack[i + radius] 86 | sir[0] = p and 0xff0000 shr 16 87 | sir[1] = p and 0x00ff00 shr 8 88 | sir[2] = p and 0x0000ff 89 | rbs = r1 - Math.abs(i) 90 | rsum += sir[0] * rbs 91 | gsum += sir[1] * rbs 92 | bsum += sir[2] * rbs 93 | if (i > 0) { 94 | rinsum += sir[0] 95 | ginsum += sir[1] 96 | binsum += sir[2] 97 | } else { 98 | routsum += sir[0] 99 | goutsum += sir[1] 100 | boutsum += sir[2] 101 | } 102 | i++ 103 | } 104 | stackpointer = radius 105 | 106 | x = 0 107 | while (x < w) { 108 | 109 | r[yi] = dv[rsum] 110 | g[yi] = dv[gsum] 111 | b[yi] = dv[bsum] 112 | 113 | rsum -= routsum 114 | gsum -= goutsum 115 | bsum -= boutsum 116 | 117 | stackstart = stackpointer - radius + div 118 | sir = stack[stackstart % div] 119 | 120 | routsum -= sir[0] 121 | goutsum -= sir[1] 122 | boutsum -= sir[2] 123 | 124 | if (y == 0) { 125 | vmin[x] = Math.min(x + radius + 1, wm) 126 | } 127 | p = pix[yw + vmin[x]] 128 | 129 | sir[0] = p and 0xff0000 shr 16 130 | sir[1] = p and 0x00ff00 shr 8 131 | sir[2] = p and 0x0000ff 132 | 133 | rinsum += sir[0] 134 | ginsum += sir[1] 135 | binsum += sir[2] 136 | 137 | rsum += rinsum 138 | gsum += ginsum 139 | bsum += binsum 140 | 141 | stackpointer = (stackpointer + 1) % div 142 | sir = stack[stackpointer % div] 143 | 144 | routsum += sir[0] 145 | goutsum += sir[1] 146 | boutsum += sir[2] 147 | 148 | rinsum -= sir[0] 149 | ginsum -= sir[1] 150 | binsum -= sir[2] 151 | 152 | yi++ 153 | x++ 154 | } 155 | yw += w 156 | y++ 157 | } 158 | x = 0 159 | while (x < w) { 160 | bsum = 0 161 | gsum = bsum 162 | rsum = gsum 163 | boutsum = rsum 164 | goutsum = boutsum 165 | routsum = goutsum 166 | binsum = routsum 167 | ginsum = binsum 168 | rinsum = ginsum 169 | yp = -radius * w 170 | i = -radius 171 | while (i <= radius) { 172 | yi = Math.max(0, yp) + x 173 | 174 | sir = stack[i + radius] 175 | 176 | sir[0] = r[yi] 177 | sir[1] = g[yi] 178 | sir[2] = b[yi] 179 | 180 | rbs = r1 - Math.abs(i) 181 | 182 | rsum += r[yi] * rbs 183 | gsum += g[yi] * rbs 184 | bsum += b[yi] * rbs 185 | 186 | if (i > 0) { 187 | rinsum += sir[0] 188 | ginsum += sir[1] 189 | binsum += sir[2] 190 | } else { 191 | routsum += sir[0] 192 | goutsum += sir[1] 193 | boutsum += sir[2] 194 | } 195 | 196 | if (i < hm) { 197 | yp += w 198 | } 199 | i++ 200 | } 201 | yi = x 202 | stackpointer = radius 203 | y = 0 204 | while (y < h) { 205 | // Preserve alpha channel: ( 0xff000000 & pix[yi] ) 206 | pix[yi] = -0x1000000 and pix[yi] or (dv[rsum] shl 16) or (dv[gsum] shl 8) or dv[bsum] 207 | 208 | rsum -= routsum 209 | gsum -= goutsum 210 | bsum -= boutsum 211 | 212 | stackstart = stackpointer - radius + div 213 | sir = stack[stackstart % div] 214 | 215 | routsum -= sir[0] 216 | goutsum -= sir[1] 217 | boutsum -= sir[2] 218 | 219 | if (x == 0) { 220 | vmin[y] = Math.min(y + r1, hm) * w 221 | } 222 | p = x + vmin[y] 223 | 224 | sir[0] = r[p] 225 | sir[1] = g[p] 226 | sir[2] = b[p] 227 | 228 | rinsum += sir[0] 229 | ginsum += sir[1] 230 | binsum += sir[2] 231 | 232 | rsum += rinsum 233 | gsum += ginsum 234 | bsum += binsum 235 | 236 | stackpointer = (stackpointer + 1) % div 237 | sir = stack[stackpointer] 238 | 239 | routsum += sir[0] 240 | goutsum += sir[1] 241 | boutsum += sir[2] 242 | 243 | rinsum -= sir[0] 244 | ginsum -= sir[1] 245 | binsum -= sir[2] 246 | 247 | yi += w 248 | y++ 249 | } 250 | x++ 251 | } 252 | 253 | bitmap.setPixels(pix, 0, w, 0, 0, w, h) 254 | 255 | return bitmap 256 | } 257 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/glide/RSBlur.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.glide 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.graphics.Bitmap 6 | import android.os.Build 7 | import android.renderscript.* 8 | 9 | /** 10 | * Created by guoshuyu on 2018/1/22. 11 | */ 12 | object RSBlur { 13 | 14 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 15 | @Throws(RSRuntimeException::class) 16 | fun blur(context: Context, bitmap: Bitmap, radius: Int): Bitmap { 17 | var rs: RenderScript? = null 18 | var input: Allocation? = null 19 | var output: Allocation? = null 20 | var blur: ScriptIntrinsicBlur? = null 21 | try { 22 | rs = RenderScript.create(context) 23 | rs!!.messageHandler = RenderScript.RSMessageHandler() 24 | input = Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, 25 | Allocation.USAGE_SCRIPT) 26 | output = Allocation.createTyped(rs, input!!.type) 27 | blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)) 28 | 29 | blur!!.setInput(input) 30 | blur.setRadius(radius.toFloat()) 31 | blur.forEach(output) 32 | output!!.copyTo(bitmap) 33 | } finally { 34 | if (rs != null) { 35 | rs.destroy() 36 | } 37 | if (input != null) { 38 | input.destroy() 39 | } 40 | if (output != null) { 41 | output.destroy() 42 | } 43 | if (blur != null) { 44 | blur.destroy() 45 | } 46 | } 47 | 48 | return bitmap 49 | } 50 | } -------------------------------------------------------------------------------- /app/src/main/java/com/example/gysimageloader/process/picasso/ColorFilterTransformations.kt: -------------------------------------------------------------------------------- 1 | package com.example.gysimageloader.process.picasso 2 | 3 | import android.graphics.* 4 | import com.squareup.picasso.Transformation 5 | 6 | /** 7 | * Created by guoshuyu on 2018/1/22. 8 | * https://github.com/wasabeef/picasso-transformations 9 | */ 10 | class ColorFilterTransformations(private val mColor: Int) : Transformation { 11 | 12 | override fun transform(source: Bitmap): Bitmap { 13 | 14 | val width = source.width 15 | val height = source.height 16 | 17 | val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) 18 | 19 | val canvas = Canvas(bitmap) 20 | val paint = Paint() 21 | paint.isAntiAlias = true 22 | paint.colorFilter = PorterDuffColorFilter(mColor, PorterDuff.Mode.SRC_ATOP) 23 | canvas.drawBitmap(source, 0f, 0f, paint) 24 | source.recycle() 25 | 26 | return bitmap 27 | } 28 | 29 | override fun key(): String { 30 | return "ColorFilterTransformation(color=$mColor)" 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | 171 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 16 | 21 | 22 |