├── sample ├── sample-imageloader-for-androidstudio │ ├── .gitignore │ ├── libs │ │ └── imageloader.jar │ ├── src │ │ ├── main │ │ │ ├── res │ │ │ │ ├── drawable-hdpi │ │ │ │ │ ├── pic_dir.png │ │ │ │ │ ├── dir_choose.png │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── pictures_no.png │ │ │ │ │ ├── pictures_selected.png │ │ │ │ │ └── picture_unselected.png │ │ │ │ ├── drawable │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ └── pictures_no.png │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ ├── dimens.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── layout │ │ │ │ │ ├── activity_single_fragment.xml │ │ │ │ │ ├── activity_category.xml │ │ │ │ │ ├── item_fragment_list_imgs.xml │ │ │ │ │ ├── fragment_list_imgs.xml │ │ │ │ │ ├── list_dir.xml │ │ │ │ │ ├── item_category.xml │ │ │ │ │ ├── grid_item.xml │ │ │ │ │ ├── activity_local_main.xml │ │ │ │ │ └── list_dir_item.xml │ │ │ │ ├── anim │ │ │ │ │ ├── slide_in.xml │ │ │ │ │ └── slide_out.xml │ │ │ │ ├── values-w820dp │ │ │ │ │ └── dimens.xml │ │ │ │ └── menu │ │ │ │ │ └── menu_main.xml │ │ │ ├── java │ │ │ │ ├── com │ │ │ │ │ └── zhy │ │ │ │ │ │ └── sample │ │ │ │ │ │ └── imageloader │ │ │ │ │ │ ├── network │ │ │ │ │ │ ├── NetworkImageLoaderActivity.java │ │ │ │ │ │ ├── AbsSingleFragmentActivity.java │ │ │ │ │ │ ├── ListImgsFragment.java │ │ │ │ │ │ └── Images.java │ │ │ │ │ │ ├── BaseContentActivity.java │ │ │ │ │ │ ├── local │ │ │ │ │ │ ├── ImageFloder.java │ │ │ │ │ │ ├── ListImageDirPopupWindow.java │ │ │ │ │ │ ├── BasePopupWindowForListView.java │ │ │ │ │ │ ├── MyAdapter.java │ │ │ │ │ │ └── LocalImageloaderActivity.java │ │ │ │ │ │ └── CategoryActivity.java │ │ │ │ └── utils │ │ │ │ │ ├── CommonAdapter.java │ │ │ │ │ └── ViewHolder.java │ │ │ └── AndroidManifest.xml │ │ └── androidTest │ │ │ └── java │ │ │ └── com │ │ │ └── zhy │ │ │ └── sample │ │ │ └── imageloader │ │ │ └── ApplicationTest.java │ ├── proguard-rules.pro │ └── build.gradle └── sample-imageloader-for-eclipse │ ├── .settings │ ├── org.eclipse.core.resources.prefs │ └── org.eclipse.jdt.core.prefs │ ├── ic_launcher-web.png │ ├── libs │ ├── imageloader.jar │ └── android-support-v4.jar │ ├── res │ ├── drawable-xxhdpi │ │ ├── hy.png │ │ ├── icon.png │ │ └── ic_launcher.png │ ├── drawable-hdpi │ │ ├── pic_dir.png │ │ ├── dir_choose.png │ │ ├── ic_launcher.png │ │ ├── pictures_no.png │ │ ├── pictures_selected.png │ │ └── picture_unselected.png │ ├── drawable-mdpi │ │ └── ic_launcher.png │ ├── drawable-xhdpi │ │ └── ic_launcher.png │ ├── values-sw600dp │ │ └── dimens.xml │ ├── values │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── menu │ │ └── main.xml │ ├── layout │ │ ├── activity_single_fragment.xml │ │ ├── activity_category.xml │ │ ├── item_fragment_list_imgs.xml │ │ ├── fragment_list_imgs.xml │ │ ├── list_dir.xml │ │ ├── item_category.xml │ │ ├── grid_item.xml │ │ ├── activity_main.xml │ │ ├── activity_local_main.xml │ │ └── list_dir_item.xml │ ├── values-sw720dp-land │ │ └── dimens.xml │ ├── anim │ │ ├── slide_in.xml │ │ └── slide_out.xml │ ├── values-v11 │ │ └── styles.xml │ └── values-v14 │ │ └── styles.xml │ ├── .classpath │ ├── src │ └── com │ │ └── zhy │ │ ├── sample │ │ └── imageloader │ │ │ ├── network │ │ │ ├── NetworkImageLoaderActivity.java │ │ │ ├── AbsSingleFragmentActivity.java │ │ │ ├── ListImgsFragment.java │ │ │ └── Images.java │ │ │ ├── BaseContentActivity.java │ │ │ ├── local │ │ │ ├── ImageFloder.java │ │ │ ├── ListImageDirPopupWindow.java │ │ │ ├── MyAdapter.java │ │ │ └── LocalImageloaderActivity.java │ │ │ └── CategoryActivity.java │ │ └── utils │ │ ├── CommonAdapter.java │ │ ├── BasePopupWindowForListView.java │ │ └── ViewHolder.java │ ├── project.properties │ ├── proguard-project.txt │ ├── .project │ └── AndroidManifest.xml ├── imageloader_01.gif ├── imageloader_02.png ├── imageloader_03.png ├── jar └── imageloader.jar ├── base-imageloader ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable │ │ │ │ └── pictures_no.png │ │ │ ├── mipmap-hdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── styles.xml │ │ │ │ └── dimens.xml │ │ │ ├── layout │ │ │ │ ├── activity_single_fragment.xml │ │ │ │ ├── item_fragment_list_imgs.xml │ │ │ │ └── fragment_list_imgs.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ └── menu │ │ │ │ └── menu_main.xml │ │ ├── java │ │ │ └── com │ │ │ │ └── zhy │ │ │ │ └── base │ │ │ │ └── imageloader │ │ │ │ ├── activity │ │ │ │ ├── MainActivity.java │ │ │ │ ├── AbsSingleFragmentActivity.java │ │ │ │ ├── ListImgsFragment.java │ │ │ │ ├── HttpStack.java │ │ │ │ └── Images.java │ │ │ │ ├── CancelableRequestDelegate.java │ │ │ │ ├── L.java │ │ │ │ ├── Scheme.java │ │ │ │ ├── LIFOLinkedBlockingDeque.java │ │ │ │ ├── CacheDispatcher.java │ │ │ │ ├── ContentLengthInputStream.java │ │ │ │ ├── LocalDispatcher.java │ │ │ │ ├── diskcache │ │ │ │ └── disklrucache │ │ │ │ │ ├── Util.java │ │ │ │ │ ├── Utils.java │ │ │ │ │ └── StrictLineReader.java │ │ │ │ ├── Dispatcher.java │ │ │ │ ├── ImageRequest.java │ │ │ │ ├── NetworkDispatcher.java │ │ │ │ ├── IoUtils.java │ │ │ │ ├── ImageUtils.java │ │ │ │ ├── ImageLoader.java │ │ │ │ └── ImageDecorder.java │ │ └── AndroidManifest.xml │ └── androidTest │ │ └── java │ │ └── com │ │ └── zhy │ │ └── base │ │ └── imageloader │ │ └── ApplicationTest.java ├── proguard-rules.pro └── build.gradle ├── .gitignore └── README.md /sample/sample-imageloader-for-androidstudio/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /imageloader_01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/imageloader_01.gif -------------------------------------------------------------------------------- /imageloader_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/imageloader_02.png -------------------------------------------------------------------------------- /imageloader_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/imageloader_03.png -------------------------------------------------------------------------------- /jar/imageloader.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/jar/imageloader.jar -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/drawable/pictures_no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/base-imageloader/src/main/res/drawable/pictures_no.png -------------------------------------------------------------------------------- /base-imageloader/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/base-imageloader/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /base-imageloader/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/base-imageloader/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/ic_launcher-web.png -------------------------------------------------------------------------------- /base-imageloader/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/base-imageloader/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /base-imageloader/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/base-imageloader/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/libs/imageloader.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/libs/imageloader.jar -------------------------------------------------------------------------------- /base-imageloader/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | base-imageloader 3 | Settings 4 | 5 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/libs/imageloader.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/libs/imageloader.jar -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/libs/android-support-v4.jar -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-xxhdpi/hy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-xxhdpi/hy.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-hdpi/pic_dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-hdpi/pic_dir.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-hdpi/dir_choose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-hdpi/dir_choose.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-hdpi/pictures_no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-hdpi/pictures_no.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-hdpi/pictures_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-hdpi/pictures_selected.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/drawable-hdpi/picture_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-eclipse/res/drawable-hdpi/picture_unselected.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/pic_dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/pic_dir.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable/pictures_no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable/pictures_no.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/dir_choose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/dir_choose.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/pictures_no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/pictures_no.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/pictures_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/pictures_selected.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/picture_unselected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hongyangAndroid/base-imageloader/HEAD/sample/sample-imageloader-for-androidstudio/src/main/res/drawable-hdpi/picture_unselected.png -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | sample-imageloader 3 | 4 | Hello world! 5 | Settings 6 | 7 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 图片加载器-微信版 5 | Settings 6 | Hello world! 7 | 8 | 9 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/layout/activity_single_fragment.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/layout/item_fragment_list_imgs.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/activity_single_fragment.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/activity_category.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/activity_single_fragment.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/item_fragment_list_imgs.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/activity_category.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/item_fragment_list_imgs.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/anim/slide_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/anim/slide_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/anim/slide_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/anim/slide_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | 15 | # Gradle files 16 | .gradle/ 17 | build/ 18 | /*/build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/layout/fragment_list_imgs.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/fragment_list_imgs.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /base-imageloader/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/fragment_list_imgs.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /base-imageloader/src/androidTest/java/com/zhy/base/imageloader/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase 10 | { 11 | public ApplicationTest() 12 | { 13 | super(Application.class); 14 | } 15 | } -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 9 | 10 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/androidTest/java/com/zhy/sample/imageloader/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase 10 | { 11 | public ApplicationTest() 12 | { 13 | super(Application.class); 14 | } 15 | } -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader.activity; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | import com.zhy.base.imageloader.R; 6 | 7 | public class MainActivity extends AbsSingleFragmentActivity 8 | { 9 | @Override 10 | protected Fragment createFragment() 11 | { 12 | return new ListImgsFragment(); 13 | } 14 | 15 | @Override 16 | protected int getLayoutId() 17 | { 18 | return R.layout.activity_single_fragment; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/list_dir.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/list_dir.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/network/NetworkImageLoaderActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | import com.zhy.sample.imageloader.R; 6 | 7 | 8 | public class NetworkImageLoaderActivity extends AbsSingleFragmentActivity 9 | { 10 | @Override 11 | protected Fragment createFragment() 12 | { 13 | return new ListImgsFragment(); 14 | } 15 | 16 | @Override 17 | protected int getLayoutId() 18 | { 19 | return R.layout.activity_single_fragment; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/network/NetworkImageLoaderActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | import android.support.v4.app.Fragment; 4 | 5 | import com.zhy.sample.imageloader.R; 6 | 7 | 8 | public class NetworkImageLoaderActivity extends AbsSingleFragmentActivity 9 | { 10 | @Override 11 | protected Fragment createFragment() 12 | { 13 | return new ListImgsFragment(); 14 | } 15 | 16 | @Override 17 | protected int getLayoutId() 18 | { 19 | return R.layout.activity_single_fragment; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-17 15 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/item_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/item_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 15 | 16 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/BaseContentActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.text.TextUtils; 7 | 8 | 9 | public class BaseContentActivity extends Activity 10 | { 11 | public static final String TITLE = "title"; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) 15 | { 16 | super.onCreate(savedInstanceState); 17 | 18 | Intent intent = getIntent(); 19 | String title = intent.getStringExtra(TITLE); 20 | if (!TextUtils.isEmpty(title)) 21 | setTitle(title); 22 | } 23 | 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /base-imageloader/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/zhy/android/sdk/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /base-imageloader/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "22.0.1" 6 | 7 | defaultConfig { 8 | applicationId "com.zhy.base.imageloader" 9 | minSdkVersion 10 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.1' 25 | compile 'com.android.support:support-v4:22.2.1' 26 | } 27 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/BaseContentActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.ActionBarActivity; 6 | import android.text.TextUtils; 7 | 8 | 9 | public class BaseContentActivity extends ActionBarActivity 10 | { 11 | public static final String TITLE = "title"; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) 15 | { 16 | super.onCreate(savedInstanceState); 17 | 18 | Intent intent = getIntent(); 19 | String title = intent.getStringExtra(TITLE); 20 | if (!TextUtils.isEmpty(title)) 21 | setTitle(title); 22 | } 23 | 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/zhy/android/sdk/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 22 5 | buildToolsVersion "23.0.0 rc3" 6 | 7 | defaultConfig { 8 | applicationId "com.zhy.sample.imageloader" 9 | minSdkVersion 10 10 | targetSdkVersion 22 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | compile 'com.android.support:appcompat-v7:22.2.1' 25 | compile files('libs/imageloader.jar') 26 | compile 'com.android.support:support-v4:22.2.1' 27 | } 28 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/CancelableRequestDelegate.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | /** 8 | * Created by zhy on 15/8/12. 9 | */ 10 | public class CancelableRequestDelegate 11 | { 12 | private Map mCheckUnRealRequest = Collections 13 | .synchronizedMap(new HashMap()); 14 | 15 | 16 | public void putRequest(int hashCode, String cacheKey) 17 | { 18 | mCheckUnRealRequest.put(hashCode, cacheKey); 19 | } 20 | 21 | public String getCacheKey(int hashCode) 22 | { 23 | return mCheckUnRealRequest.get(hashCode); 24 | } 25 | 26 | public void remove(int hashCode) 27 | { 28 | mCheckUnRealRequest.remove(hashCode); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | sample-imageloader-for-eclipse 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /base-imageloader/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 10 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 24 | 25 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/grid_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 24 | 25 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/grid_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # base-imageloader 2 | Android本地、网络图片加载库。 3 | 4 | 5 | ## 使用 6 | 7 | 下载[jar](jar/imageloader.jar)包,复制到项目的libs下,然后添加依赖。 8 | 9 | 任何需要的地方调用以下代码 10 | 11 | ```java 12 | ImageLoader.with(context).load(url, imageview); 13 | ``` 14 | 注意权限: 15 | 16 | ```xml 17 | 18 | 19 | 20 | ``` 21 | 22 | ## 效果图 23 | 24 | ### 关于Sample 25 | 26 | * Android Studio 用户,以module方式导入[sample/sample-imageloader-for-androidstudio](sample/sample-imageloader-for-androidstudio) 。 27 | * Eclipse用户,以项目的方式,导入[sample/sample-imageloader-for-eclipse](sample/sample-imageloader-for-eclipse) 。 28 | 29 | ### 加载网络图片 30 | 31 | 32 | 33 | ### 加载本地图片 34 | 35 | 36 | 37 | 38 | 39 | ## 特性 40 | 41 | * 支持LIFO,FIFO 加载图片策略 42 | * 支持内存缓存、硬盘缓存 43 | * 支持网络图片加载 44 | * 支持本地图片加载 45 | * 支持file、drawable、assets、content等Schema图片的加载 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/activity/AbsSingleFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v7.app.AppCompatActivity; 7 | 8 | import com.zhy.base.imageloader.R; 9 | 10 | public abstract class AbsSingleFragmentActivity extends AppCompatActivity 11 | { 12 | @Override 13 | protected void onCreate(Bundle savedInstanceState) 14 | { 15 | super.onCreate(savedInstanceState); 16 | setContentView(getLayoutId()); 17 | 18 | FragmentManager fm = getSupportFragmentManager(); 19 | Fragment fragment = fm.findFragmentById(R.id.id_fragmentContainer); 20 | 21 | if (fragment == null) 22 | { 23 | fragment = createFragment(); 24 | fm.beginTransaction().add(R.id.id_fragmentContainer, fragment) 25 | .commit(); 26 | } 27 | 28 | } 29 | 30 | protected abstract Fragment createFragment(); 31 | 32 | protected abstract int getLayoutId(); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 12 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/network/AbsSingleFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentActivity; 6 | import android.support.v4.app.FragmentManager; 7 | 8 | import com.zhy.sample.imageloader.R; 9 | 10 | 11 | public abstract class AbsSingleFragmentActivity extends FragmentActivity 12 | { 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) 15 | { 16 | super.onCreate(savedInstanceState); 17 | setContentView(getLayoutId()); 18 | 19 | FragmentManager fm = getSupportFragmentManager(); 20 | Fragment fragment = fm.findFragmentById(R.id.id_fragmentContainer); 21 | 22 | if (fragment == null) 23 | { 24 | fragment = createFragment(); 25 | fm.beginTransaction().add(R.id.id_fragmentContainer, fragment) 26 | .commit(); 27 | } 28 | 29 | } 30 | 31 | protected abstract Fragment createFragment(); 32 | 33 | protected abstract int getLayoutId(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/network/AbsSingleFragmentActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | import android.os.Bundle; 4 | import android.support.v4.app.Fragment; 5 | import android.support.v4.app.FragmentManager; 6 | import android.support.v7.app.AppCompatActivity; 7 | 8 | import com.zhy.sample.imageloader.R; 9 | 10 | 11 | public abstract class AbsSingleFragmentActivity extends AppCompatActivity 12 | { 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) 15 | { 16 | super.onCreate(savedInstanceState); 17 | setContentView(getLayoutId()); 18 | 19 | FragmentManager fm = getSupportFragmentManager(); 20 | Fragment fragment = fm.findFragmentById(R.id.id_fragmentContainer); 21 | 22 | if (fragment == null) 23 | { 24 | fragment = createFragment(); 25 | fm.beginTransaction().add(R.id.id_fragmentContainer, fragment) 26 | .commit(); 27 | } 28 | 29 | } 30 | 31 | protected abstract Fragment createFragment(); 32 | 33 | protected abstract int getLayoutId(); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/local/ImageFloder.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | public class ImageFloder 4 | { 5 | /** 6 | * 图片的文件夹路径 7 | */ 8 | private String dir; 9 | 10 | /** 11 | * 第一张图片的路径 12 | */ 13 | private String firstImagePath; 14 | 15 | /** 16 | * 文件夹的名称 17 | */ 18 | private String name; 19 | 20 | /** 21 | * 图片的数量 22 | */ 23 | private int count; 24 | 25 | public String getDir() 26 | { 27 | return dir; 28 | } 29 | 30 | public void setDir(String dir) 31 | { 32 | this.dir = dir; 33 | int lastIndexOf = this.dir.lastIndexOf("/"); 34 | this.name = this.dir.substring(lastIndexOf); 35 | } 36 | 37 | public String getFirstImagePath() 38 | { 39 | return firstImagePath; 40 | } 41 | 42 | public void setFirstImagePath(String firstImagePath) 43 | { 44 | this.firstImagePath = firstImagePath; 45 | } 46 | 47 | public String getName() 48 | { 49 | return name; 50 | } 51 | public int getCount() 52 | { 53 | return count; 54 | } 55 | 56 | public void setCount(int count) 57 | { 58 | this.count = count; 59 | } 60 | 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/local/ImageFloder.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | public class ImageFloder 4 | { 5 | /** 6 | * 图片的文件夹路径 7 | */ 8 | private String dir; 9 | 10 | /** 11 | * 第一张图片的路径 12 | */ 13 | private String firstImagePath; 14 | 15 | /** 16 | * 文件夹的名称 17 | */ 18 | private String name; 19 | 20 | /** 21 | * 图片的数量 22 | */ 23 | private int count; 24 | 25 | public String getDir() 26 | { 27 | return dir; 28 | } 29 | 30 | public void setDir(String dir) 31 | { 32 | this.dir = dir; 33 | int lastIndexOf = this.dir.lastIndexOf("/"); 34 | this.name = this.dir.substring(lastIndexOf); 35 | } 36 | 37 | public String getFirstImagePath() 38 | { 39 | return firstImagePath; 40 | } 41 | 42 | public void setFirstImagePath(String firstImagePath) 43 | { 44 | this.firstImagePath = firstImagePath; 45 | } 46 | 47 | public String getName() 48 | { 49 | return name; 50 | } 51 | public int getCount() 52 | { 53 | return count; 54 | } 55 | 56 | public void setCount(int count) 57 | { 58 | this.count = count; 59 | } 60 | 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/L.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Log统一管理类 7 | */ 8 | public class L 9 | { 10 | 11 | private L() 12 | { 13 | /* cannot be instantiated */ 14 | throw new UnsupportedOperationException("cannot be instantiated"); 15 | } 16 | 17 | public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化 18 | private static final String TAG = "zhy"; 19 | 20 | // 下面四个是默认tag的函数 21 | public static void i(String msg) 22 | { 23 | if (isDebug) 24 | Log.i(TAG, msg); 25 | } 26 | 27 | public static void d(String msg) 28 | { 29 | if (isDebug) 30 | Log.d(TAG, msg); 31 | } 32 | 33 | public static void w(String msg) 34 | { 35 | if (isDebug) 36 | Log.w(TAG, msg); 37 | } 38 | 39 | public static void e(String msg) 40 | { 41 | if (isDebug) 42 | Log.e(TAG, msg); 43 | } 44 | 45 | public static void v(String msg) 46 | { 47 | if (isDebug) 48 | Log.v(TAG, msg); 49 | } 50 | 51 | // 下面是传入自定义tag的函数 52 | public static void i(String tag, String msg) 53 | { 54 | if (isDebug) 55 | Log.i(tag, msg); 56 | } 57 | 58 | public static void d(String tag, String msg) 59 | { 60 | if (isDebug) 61 | Log.i(tag, msg); 62 | } 63 | 64 | public static void e(String tag, String msg) 65 | { 66 | if (isDebug) 67 | Log.i(tag, msg); 68 | } 69 | 70 | public static void w(String tag, String msg) 71 | { 72 | if (isDebug) 73 | Log.w(tag, msg); 74 | } 75 | 76 | 77 | public static void v(String tag, String msg) 78 | { 79 | if (isDebug) 80 | Log.i(tag, msg); 81 | } 82 | } -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/utils/CommonAdapter.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | 9 | import java.util.List; 10 | 11 | public abstract class CommonAdapter extends BaseAdapter 12 | { 13 | protected LayoutInflater mInflater; 14 | protected Context mContext; 15 | protected List mDatas; 16 | protected final int mItemLayoutId; 17 | 18 | public CommonAdapter(Context context, List mDatas, int itemLayoutId) 19 | { 20 | this.mContext = context; 21 | this.mInflater = LayoutInflater.from(mContext); 22 | this.mDatas = mDatas; 23 | this.mItemLayoutId = itemLayoutId; 24 | } 25 | 26 | @Override 27 | public int getCount() 28 | { 29 | return mDatas.size(); 30 | } 31 | 32 | @Override 33 | public T getItem(int position) 34 | { 35 | return mDatas.get(position); 36 | } 37 | 38 | @Override 39 | public long getItemId(int position) 40 | { 41 | return position; 42 | } 43 | 44 | @Override 45 | public View getView(int position, View convertView, ViewGroup parent) 46 | { 47 | final ViewHolder viewHolder = getViewHolder(position, convertView, 48 | parent); 49 | convert(viewHolder, getItem(position)); 50 | return viewHolder.getConvertView(); 51 | 52 | } 53 | 54 | public abstract void convert(ViewHolder helper, T item); 55 | 56 | private ViewHolder getViewHolder(int position, View convertView, 57 | ViewGroup parent) 58 | { 59 | return ViewHolder.get(mContext, convertView, parent, mItemLayoutId, 60 | position); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/utils/CommonAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zhy.utils; 2 | 3 | import java.util.List; 4 | 5 | import android.content.Context; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.BaseAdapter; 10 | 11 | public abstract class CommonAdapter extends BaseAdapter 12 | { 13 | protected LayoutInflater mInflater; 14 | protected Context mContext; 15 | protected List mDatas; 16 | protected final int mItemLayoutId; 17 | 18 | public CommonAdapter(Context context, List mDatas, int itemLayoutId) 19 | { 20 | this.mContext = context; 21 | this.mInflater = LayoutInflater.from(mContext); 22 | this.mDatas = mDatas; 23 | this.mItemLayoutId = itemLayoutId; 24 | } 25 | 26 | @Override 27 | public int getCount() 28 | { 29 | return mDatas.size(); 30 | } 31 | 32 | @Override 33 | public T getItem(int position) 34 | { 35 | return mDatas.get(position); 36 | } 37 | 38 | @Override 39 | public long getItemId(int position) 40 | { 41 | return position; 42 | } 43 | 44 | @Override 45 | public View getView(int position, View convertView, ViewGroup parent) 46 | { 47 | final ViewHolder viewHolder = getViewHolder(position, convertView, 48 | parent); 49 | convert(viewHolder, getItem(position)); 50 | return viewHolder.getConvertView(); 51 | 52 | } 53 | 54 | public abstract void convert(ViewHolder helper, T item); 55 | 56 | private ViewHolder getViewHolder(int position, View convertView, 57 | ViewGroup parent) 58 | { 59 | return ViewHolder.get(mContext, convertView, parent, mItemLayoutId, 60 | position); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/Scheme.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import java.util.Locale; 4 | 5 | public enum Scheme 6 | { 7 | HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN(""); 8 | 9 | private String scheme; 10 | private String uriPrefix; 11 | 12 | Scheme(String scheme) 13 | { 14 | this.scheme = scheme; 15 | uriPrefix = scheme + "://"; 16 | } 17 | 18 | /** 19 | * Defines scheme of incoming URI 20 | * 21 | * @param uri URI for scheme detection 22 | * @return Scheme of incoming URI 23 | */ 24 | public static Scheme ofUri(String uri) 25 | { 26 | if (uri != null) 27 | { 28 | for (Scheme s : values()) 29 | { 30 | if (s.belongsTo(uri)) 31 | { 32 | return s; 33 | } 34 | } 35 | } 36 | return UNKNOWN; 37 | } 38 | 39 | public boolean belongsTo(String uri) 40 | { 41 | return uri.toLowerCase(Locale.US).startsWith(uriPrefix); 42 | } 43 | 44 | /** 45 | * Appends scheme to incoming path 46 | */ 47 | public String wrap(String path) 48 | { 49 | return uriPrefix + path; 50 | } 51 | 52 | /** 53 | * Removed scheme part ("scheme://") from incoming URI 54 | */ 55 | public String crop(String uri) 56 | { 57 | if (!belongsTo(uri)) 58 | { 59 | throw new IllegalArgumentException(String.format("URI [%1$s] doesn't have expected scheme [%2$s]", uri, scheme)); 60 | } 61 | return uri.substring(uriPrefix.length()); 62 | } 63 | } -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/LIFOLinkedBlockingDeque.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import java.util.NoSuchElementException; 4 | import java.util.concurrent.LinkedBlockingDeque; 5 | 6 | /** 7 | * {@link LinkedBlockingDeque} using LIFO algorithm 8 | * 9 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 10 | * @since 1.6.3 11 | */ 12 | public class LIFOLinkedBlockingDeque extends LinkedBlockingDeque 13 | { 14 | 15 | private static final long serialVersionUID = -4114786347960826192L; 16 | 17 | /** 18 | * Inserts the specified element at the front of this deque if it is possible to do so immediately without violating 19 | * capacity restrictions, returning true upon success and false if no space is currently 20 | * available. When using a capacity-restricted deque, this method is generally preferable to the {@link #addFirst 21 | * addFirst} method, which can fail to insert an element only by throwing an exception. 22 | * 23 | * @param e 24 | * the element to add 25 | * @throws ClassCastException 26 | * {@inheritDoc} 27 | * @throws NullPointerException 28 | * if the specified element is null 29 | * @throws IllegalArgumentException 30 | * {@inheritDoc} 31 | */ 32 | @Override 33 | public boolean offer(T e) { 34 | return super.offerFirst(e); 35 | } 36 | 37 | /** 38 | * Retrieves and removes the first element of this deque. This method differs from {@link #pollFirst pollFirst} only 39 | * in that it throws an exception if this deque is empty. 40 | * 41 | * @return the head of this deque 42 | * @throws NoSuchElementException 43 | * if this deque is empty 44 | */ 45 | @Override 46 | public T remove() { 47 | return super.removeFirst(); 48 | } 49 | } -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/CacheDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.os.Handler; 6 | 7 | import com.zhy.base.imageloader.diskcache.disklrucache.DiskLruCacheHelper; 8 | 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.util.concurrent.BlockingQueue; 12 | 13 | /** 14 | * Created by zhy on 15/7/31. 15 | */ 16 | public class CacheDispatcher extends Dispatcher 17 | { 18 | 19 | private DiskLruCacheHelper mDiskLruCacheHelper; 20 | private ImageDecorder mImageDecorder; 21 | 22 | public CacheDispatcher(Context context, Handler uiHandler, BlockingQueue cacheQueue, DiskLruCacheHelper diskLruCacheHelper) 23 | { 24 | super(context, cacheQueue, uiHandler, 25 | ImageLoader.MSG_CACHE_HINT, 26 | ImageLoader.MSG_CACHE_UN_HINT); 27 | mDiskLruCacheHelper = diskLruCacheHelper; 28 | mImageDecorder = new ImageDecorder(context); 29 | } 30 | 31 | 32 | @Override 33 | protected void dealRequest(ImageRequest request) 34 | { 35 | String cacheKey = request.getCacheKey(); 36 | InputStream imageStream = mDiskLruCacheHelper.get(cacheKey); 37 | Bitmap bitmap = null; 38 | try 39 | { 40 | bitmap = mImageDecorder.decodeByStream(imageStream, buildDecodeParams(request)); 41 | } catch (IOException e) 42 | { 43 | e.printStackTrace(); 44 | L.w("cache dispatcher :" + request.getUrl() +" decodeByStream failed , something wrong happened in disklrucache . " ); 45 | } 46 | request.setBitmap(bitmap); 47 | if (bitmap == null) sendErrorMsg(request); 48 | sendSuccessMsg(request); 49 | } 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 18 | 19 | 20 | 27 | 28 | 38 | 39 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/activity_local_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 18 | 19 | 20 | 27 | 28 | 38 | 39 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/activity_local_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 18 | 19 | 20 | 27 | 28 | 38 | 39 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/res/layout/list_dir_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 20 | 21 | 28 | 29 | 35 | 36 | 44 | 45 | 46 | 53 | 54 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/res/layout/list_dir_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 20 | 21 | 28 | 29 | 35 | 36 | 44 | 45 | 46 | 53 | 54 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/local/ListImageDirPopupWindow.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import android.view.View; 4 | import android.widget.AdapterView; 5 | import android.widget.AdapterView.OnItemClickListener; 6 | import android.widget.ListView; 7 | 8 | import com.zhy.sample.imageloader.R; 9 | 10 | import java.util.List; 11 | 12 | import utils.CommonAdapter; 13 | import utils.ViewHolder; 14 | 15 | public class ListImageDirPopupWindow extends BasePopupWindowForListView 16 | { 17 | private ListView mListDir; 18 | 19 | public ListImageDirPopupWindow(int width, int height, 20 | List datas, View convertView) 21 | { 22 | super(convertView, width, height, true, datas); 23 | } 24 | 25 | @Override 26 | public void initViews() 27 | { 28 | mListDir = (ListView) findViewById(R.id.id_list_dir); 29 | mListDir.setAdapter(new CommonAdapter(context, mDatas, 30 | R.layout.list_dir_item) 31 | { 32 | @Override 33 | public void convert(ViewHolder helper, ImageFloder item) 34 | { 35 | helper.setText(R.id.id_dir_item_name, item.getName()); 36 | helper.setImageByUrl(R.id.id_dir_item_image, 37 | item.getFirstImagePath()); 38 | helper.setText(R.id.id_dir_item_count, item.getCount() + "张"); 39 | } 40 | }); 41 | } 42 | 43 | public interface OnImageDirSelected 44 | { 45 | void selected(ImageFloder floder); 46 | } 47 | 48 | private OnImageDirSelected mImageDirSelected; 49 | 50 | public void setOnImageDirSelected(OnImageDirSelected mImageDirSelected) 51 | { 52 | this.mImageDirSelected = mImageDirSelected; 53 | } 54 | 55 | @Override 56 | public void initEvents() 57 | { 58 | mListDir.setOnItemClickListener(new OnItemClickListener() 59 | { 60 | @Override 61 | public void onItemClick(AdapterView parent, View view, 62 | int position, long id) 63 | { 64 | 65 | if (mImageDirSelected != null) 66 | { 67 | mImageDirSelected.selected(mDatas.get(position)); 68 | } 69 | } 70 | }); 71 | } 72 | 73 | @Override 74 | public void init() 75 | { 76 | // TODO Auto-generated method stub 77 | 78 | } 79 | 80 | @Override 81 | protected void beforeInitWeNeedSomeParams(Object... params) 82 | { 83 | // TODO Auto-generated method stub 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/ContentLengthInputStream.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2013-2014 Sergey Tarasevich 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package com.zhy.base.imageloader; 17 | 18 | import java.io.IOException; 19 | import java.io.InputStream; 20 | 21 | /** 22 | * Decorator for {@link java.io.InputStream InputStream}. Provides possibility to return defined stream length by 23 | * {@link #available()} method. 24 | * 25 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com), Mariotaku 26 | * @since 1.9.1 27 | */ 28 | public class ContentLengthInputStream extends InputStream { 29 | 30 | private final InputStream stream; 31 | private final int length; 32 | 33 | public ContentLengthInputStream(InputStream stream, int length) { 34 | this.stream = stream; 35 | this.length = length; 36 | } 37 | 38 | @Override 39 | public int available() { 40 | return length; 41 | } 42 | 43 | @Override 44 | public void close() throws IOException { 45 | stream.close(); 46 | } 47 | 48 | @Override 49 | public void mark(int readLimit) { 50 | stream.mark(readLimit); 51 | } 52 | 53 | @Override 54 | public int read() throws IOException { 55 | return stream.read(); 56 | } 57 | 58 | @Override 59 | public int read(byte[] buffer) throws IOException { 60 | return stream.read(buffer); 61 | } 62 | 63 | @Override 64 | public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 65 | return stream.read(buffer, byteOffset, byteCount); 66 | } 67 | 68 | @Override 69 | public void reset() throws IOException { 70 | stream.reset(); 71 | } 72 | 73 | @Override 74 | public long skip(long byteCount) throws IOException { 75 | return stream.skip(byteCount); 76 | } 77 | 78 | @Override 79 | public boolean markSupported() { 80 | return stream.markSupported(); 81 | } 82 | } -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/local/ListImageDirPopupWindow.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import java.util.List; 4 | 5 | import android.view.View; 6 | import android.widget.AdapterView; 7 | import android.widget.AdapterView.OnItemClickListener; 8 | import android.widget.ListView; 9 | 10 | import com.zhy.sample.imageloader.R; 11 | import com.zhy.sample.imageloader.R.id; 12 | import com.zhy.sample.imageloader.R.layout; 13 | import com.zhy.utils.BasePopupWindowForListView; 14 | import com.zhy.utils.CommonAdapter; 15 | import com.zhy.utils.ViewHolder; 16 | 17 | public class ListImageDirPopupWindow extends BasePopupWindowForListView 18 | { 19 | private ListView mListDir; 20 | 21 | public ListImageDirPopupWindow(int width, int height, 22 | List datas, View convertView) 23 | { 24 | super(convertView, width, height, true, datas); 25 | } 26 | 27 | @Override 28 | public void initViews() 29 | { 30 | mListDir = (ListView) findViewById(R.id.id_list_dir); 31 | mListDir.setAdapter(new CommonAdapter(context, mDatas, 32 | R.layout.list_dir_item) 33 | { 34 | @Override 35 | public void convert(ViewHolder helper, ImageFloder item) 36 | { 37 | helper.setText(R.id.id_dir_item_name, item.getName()); 38 | helper.setImageByUrl(R.id.id_dir_item_image, 39 | item.getFirstImagePath()); 40 | helper.setText(R.id.id_dir_item_count, item.getCount() + "张"); 41 | } 42 | }); 43 | } 44 | 45 | public interface OnImageDirSelected 46 | { 47 | void selected(ImageFloder floder); 48 | } 49 | 50 | private OnImageDirSelected mImageDirSelected; 51 | 52 | public void setOnImageDirSelected(OnImageDirSelected mImageDirSelected) 53 | { 54 | this.mImageDirSelected = mImageDirSelected; 55 | } 56 | 57 | @Override 58 | public void initEvents() 59 | { 60 | mListDir.setOnItemClickListener(new OnItemClickListener() 61 | { 62 | @Override 63 | public void onItemClick(AdapterView parent, View view, 64 | int position, long id) 65 | { 66 | 67 | if (mImageDirSelected != null) 68 | { 69 | mImageDirSelected.selected(mDatas.get(position)); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | @Override 76 | public void init() 77 | { 78 | // TODO Auto-generated method stub 79 | 80 | } 81 | 82 | @Override 83 | protected void beforeInitWeNeedSomeParams(Object... params) 84 | { 85 | // TODO Auto-generated method stub 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/utils/BasePopupWindowForListView.java: -------------------------------------------------------------------------------- 1 | package com.zhy.utils; 2 | 3 | import java.util.List; 4 | 5 | import android.content.Context; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.view.View.OnTouchListener; 10 | import android.widget.PopupWindow; 11 | 12 | public abstract class BasePopupWindowForListView extends PopupWindow 13 | { 14 | /** 15 | * 布局文件的最外层View 16 | */ 17 | protected View mContentView; 18 | protected Context context; 19 | /** 20 | * ListView的数据集 21 | */ 22 | protected List mDatas; 23 | 24 | public BasePopupWindowForListView(View contentView, int width, int height, 25 | boolean focusable) 26 | { 27 | this(contentView, width, height, focusable, null); 28 | } 29 | 30 | public BasePopupWindowForListView(View contentView, int width, int height, 31 | boolean focusable, List mDatas) 32 | { 33 | this(contentView, width, height, focusable, mDatas, new Object[0]); 34 | 35 | } 36 | 37 | public BasePopupWindowForListView(View contentView, int width, int height, 38 | boolean focusable, List mDatas, Object... params) 39 | { 40 | super(contentView, width, height, focusable); 41 | this.mContentView = contentView; 42 | context = contentView.getContext(); 43 | if (mDatas != null) 44 | this.mDatas = mDatas; 45 | 46 | if (params != null && params.length > 0) 47 | { 48 | beforeInitWeNeedSomeParams(params); 49 | } 50 | 51 | setBackgroundDrawable(new BitmapDrawable()); 52 | setTouchable(true); 53 | setOutsideTouchable(true); 54 | setTouchInterceptor(new OnTouchListener() 55 | { 56 | @Override 57 | public boolean onTouch(View v, MotionEvent event) 58 | { 59 | if (event.getAction() == MotionEvent.ACTION_OUTSIDE) 60 | { 61 | dismiss(); 62 | return true; 63 | } 64 | return false; 65 | } 66 | }); 67 | initViews(); 68 | initEvents(); 69 | init(); 70 | } 71 | 72 | protected abstract void beforeInitWeNeedSomeParams(Object... params); 73 | 74 | public abstract void initViews(); 75 | 76 | public abstract void initEvents(); 77 | 78 | public abstract void init(); 79 | 80 | public View findViewById(int id) 81 | { 82 | return mContentView.findViewById(id); 83 | } 84 | 85 | protected static int dpToPx(Context context, int dp) 86 | { 87 | return (int) (context.getResources().getDisplayMetrics().density * dp + 0.5f); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/LocalDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.os.Handler; 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import java.util.concurrent.BlockingQueue; 10 | 11 | /** 12 | * Created by zhy on 15/7/31. 13 | */ 14 | public class LocalDispatcher extends Dispatcher 15 | { 16 | 17 | private ImageDecorder mImageDecorder; 18 | 19 | public LocalDispatcher(Context context, Handler uiHandler, 20 | BlockingQueue cacheQueue) 21 | { 22 | super(context, cacheQueue, uiHandler, 23 | ImageLoader.MSG_LOCAL_GET_SUCCESS, 24 | ImageLoader.MSG_LOCAL_GET_ERROR); 25 | mImageDecorder = new ImageDecorder(context); 26 | } 27 | 28 | 29 | @Override 30 | protected void dealRequest(ImageRequest request) 31 | { 32 | Bitmap bitmap = null; 33 | String imageUrl = request.getUrl(); 34 | Scheme scheme = Scheme.ofUri(imageUrl); 35 | // 如果schema属于unknown,检测是否属于文件 36 | if (scheme == Scheme.UNKNOWN) 37 | { 38 | bitmap = tryToGetBitmapFromSDCard(request); 39 | } else 40 | { 41 | try 42 | { 43 | bitmap = mImageDecorder.decode(buildDecodeParams(request)); 44 | } catch (IOException e) 45 | { 46 | e.printStackTrace(); 47 | L.w("local dispatcher :" + imageUrl + " can not decode to a bitmap."); 48 | } 49 | } 50 | request.setBitmap(bitmap); 51 | if (bitmap == null) 52 | { 53 | sendErrorMsg(request); 54 | } 55 | sendSuccessMsg(request); 56 | 57 | } 58 | 59 | private Bitmap tryToGetBitmapFromSDCard(ImageRequest request) 60 | { 61 | Bitmap bitmap = null; 62 | String imageUrl = request.getUrl(); 63 | File f = new File(imageUrl); 64 | if (f.exists() && f.length() > 0) 65 | { 66 | // 尝试以文件形式读取 67 | try 68 | { 69 | bitmap = mImageDecorder 70 | .decode(buildFileDecodeParams(request)); 71 | } catch (IOException e) 72 | { 73 | e.printStackTrace(); 74 | L.w("local dispatcher :" + imageUrl + " is a right path on sdcard , but maybe not a picture."); 75 | } 76 | } 77 | return bitmap; 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/local/BasePopupWindowForListView.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import java.util.List; 4 | 5 | import android.content.Context; 6 | import android.graphics.drawable.BitmapDrawable; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | import android.view.View.OnTouchListener; 10 | import android.widget.PopupWindow; 11 | 12 | public abstract class BasePopupWindowForListView extends PopupWindow 13 | { 14 | /** 15 | * 布局文件的最外层View 16 | */ 17 | protected View mContentView; 18 | protected Context context; 19 | /** 20 | * ListView的数据集 21 | */ 22 | protected List mDatas; 23 | 24 | public BasePopupWindowForListView(View contentView, int width, int height, 25 | boolean focusable) 26 | { 27 | this(contentView, width, height, focusable, null); 28 | } 29 | 30 | public BasePopupWindowForListView(View contentView, int width, int height, 31 | boolean focusable, List mDatas) 32 | { 33 | this(contentView, width, height, focusable, mDatas, new Object[0]); 34 | 35 | } 36 | 37 | public BasePopupWindowForListView(View contentView, int width, int height, 38 | boolean focusable, List mDatas, Object... params) 39 | { 40 | super(contentView, width, height, focusable); 41 | this.mContentView = contentView; 42 | context = contentView.getContext(); 43 | if (mDatas != null) 44 | this.mDatas = mDatas; 45 | 46 | if (params != null && params.length > 0) 47 | { 48 | beforeInitWeNeedSomeParams(params); 49 | } 50 | 51 | setBackgroundDrawable(new BitmapDrawable()); 52 | setTouchable(true); 53 | setOutsideTouchable(true); 54 | setTouchInterceptor(new OnTouchListener() 55 | { 56 | @Override 57 | public boolean onTouch(View v, MotionEvent event) 58 | { 59 | if (event.getAction() == MotionEvent.ACTION_OUTSIDE) 60 | { 61 | dismiss(); 62 | return true; 63 | } 64 | return false; 65 | } 66 | }); 67 | initViews(); 68 | initEvents(); 69 | init(); 70 | } 71 | 72 | protected abstract void beforeInitWeNeedSomeParams(Object... params); 73 | 74 | public abstract void initViews(); 75 | 76 | public abstract void initEvents(); 77 | 78 | public abstract void init(); 79 | 80 | public View findViewById(int id) 81 | { 82 | return mContentView.findViewById(id); 83 | } 84 | 85 | protected static int dpToPx(Context context, int dp) 86 | { 87 | return (int) (context.getResources().getDisplayMetrics().density * dp + 0.5f); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/local/MyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.view.View; 6 | import android.view.View.OnClickListener; 7 | import android.widget.ImageView; 8 | 9 | import com.zhy.sample.imageloader.R; 10 | 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | 14 | import utils.CommonAdapter; 15 | import utils.ViewHolder; 16 | 17 | 18 | public class MyAdapter extends CommonAdapter 19 | { 20 | 21 | /** 22 | * 用户选择的图片,存储为图片的完整路径 23 | */ 24 | public static List mSelectedImage = new LinkedList(); 25 | 26 | /** 27 | * 文件夹路径 28 | */ 29 | private String mDirPath; 30 | 31 | public MyAdapter(Context context, List mDatas, int itemLayoutId, 32 | String dirPath) 33 | { 34 | super(context, mDatas, itemLayoutId); 35 | this.mDirPath = dirPath; 36 | } 37 | 38 | @Override 39 | public void convert(final ViewHolder helper, final String item) 40 | { 41 | //设置no_pic 42 | helper.setImageResource(R.id.id_item_image, R.drawable.pictures_no); 43 | //设置no_selected 44 | helper.setImageResource(R.id.id_item_select, 45 | R.drawable.picture_unselected); 46 | //设置图片 47 | helper.setImageByUrl(R.id.id_item_image, mDirPath + "/" + item); 48 | 49 | final ImageView mImageView = helper.getView(R.id.id_item_image); 50 | final ImageView mSelect = helper.getView(R.id.id_item_select); 51 | 52 | mImageView.setColorFilter(null); 53 | //设置ImageView的点击事件 54 | mImageView.setOnClickListener(new OnClickListener() 55 | { 56 | //选择,则将图片变暗,反之则反之 57 | @Override 58 | public void onClick(View v) 59 | { 60 | 61 | // 已经选择过该图片 62 | if (mSelectedImage.contains(mDirPath + "/" + item)) 63 | { 64 | mSelectedImage.remove(mDirPath + "/" + item); 65 | mSelect.setImageResource(R.drawable.picture_unselected); 66 | mImageView.setColorFilter(null); 67 | } else 68 | // 未选择该图片 69 | { 70 | mSelectedImage.add(mDirPath + "/" + item); 71 | mSelect.setImageResource(R.drawable.pictures_selected); 72 | mImageView.setColorFilter(Color.parseColor("#77000000")); 73 | } 74 | 75 | } 76 | }); 77 | 78 | /** 79 | * 已经选择过的图片,显示出选择过的效果 80 | */ 81 | if (mSelectedImage.contains(mDirPath + "/" + item)) 82 | { 83 | mSelect.setImageResource(R.drawable.pictures_selected); 84 | mImageView.setColorFilter(Color.parseColor("#77000000")); 85 | } 86 | 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/local/MyAdapter.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | 6 | import android.content.Context; 7 | import android.graphics.Color; 8 | import android.view.View; 9 | import android.view.View.OnClickListener; 10 | import android.widget.ImageView; 11 | 12 | import com.zhy.sample.imageloader.R; 13 | import com.zhy.sample.imageloader.R.drawable; 14 | import com.zhy.sample.imageloader.R.id; 15 | import com.zhy.utils.CommonAdapter; 16 | 17 | public class MyAdapter extends CommonAdapter 18 | { 19 | 20 | /** 21 | * 用户选择的图片,存储为图片的完整路径 22 | */ 23 | public static List mSelectedImage = new LinkedList(); 24 | 25 | /** 26 | * 文件夹路径 27 | */ 28 | private String mDirPath; 29 | 30 | public MyAdapter(Context context, List mDatas, int itemLayoutId, 31 | String dirPath) 32 | { 33 | super(context, mDatas, itemLayoutId); 34 | this.mDirPath = dirPath; 35 | } 36 | 37 | @Override 38 | public void convert(final com.zhy.utils.ViewHolder helper, final String item) 39 | { 40 | //设置no_pic 41 | helper.setImageResource(R.id.id_item_image, R.drawable.pictures_no); 42 | //设置no_selected 43 | helper.setImageResource(R.id.id_item_select, 44 | R.drawable.picture_unselected); 45 | //设置图片 46 | helper.setImageByUrl(R.id.id_item_image, mDirPath + "/" + item); 47 | 48 | final ImageView mImageView = helper.getView(R.id.id_item_image); 49 | final ImageView mSelect = helper.getView(R.id.id_item_select); 50 | 51 | mImageView.setColorFilter(null); 52 | //设置ImageView的点击事件 53 | mImageView.setOnClickListener(new OnClickListener() 54 | { 55 | //选择,则将图片变暗,反之则反之 56 | @Override 57 | public void onClick(View v) 58 | { 59 | 60 | // 已经选择过该图片 61 | if (mSelectedImage.contains(mDirPath + "/" + item)) 62 | { 63 | mSelectedImage.remove(mDirPath + "/" + item); 64 | mSelect.setImageResource(R.drawable.picture_unselected); 65 | mImageView.setColorFilter(null); 66 | } else 67 | // 未选择该图片 68 | { 69 | mSelectedImage.add(mDirPath + "/" + item); 70 | mSelect.setImageResource(R.drawable.pictures_selected); 71 | mImageView.setColorFilter(Color.parseColor("#77000000")); 72 | } 73 | 74 | } 75 | }); 76 | 77 | /** 78 | * 已经选择过的图片,显示出选择过的效果 79 | */ 80 | if (mSelectedImage.contains(mDirPath + "/" + item)) 81 | { 82 | mSelect.setImageResource(R.drawable.pictures_selected); 83 | mImageView.setColorFilter(Color.parseColor("#77000000")); 84 | } 85 | 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/CategoryActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader; 2 | 3 | import com.zhy.sample.imageloader.local.LocalImageloaderActivity; 4 | import com.zhy.sample.imageloader.network.NetworkImageLoaderActivity; 5 | 6 | import android.app.Activity; 7 | import android.content.Intent; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.AdapterView; 13 | import android.widget.ArrayAdapter; 14 | import android.widget.ListView; 15 | import android.widget.TextView; 16 | 17 | 18 | public class CategoryActivity extends Activity 19 | { 20 | private ListView mListView; 21 | 22 | private LayoutInflater mInflater; 23 | 24 | 25 | private Class[] CLAZZES = new Class[] 26 | { 27 | LocalImageloaderActivity.class, 28 | NetworkImageLoaderActivity.class 29 | }; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) 33 | { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_category); 36 | 37 | mInflater = LayoutInflater.from(this); 38 | 39 | mListView = (ListView) findViewById(R.id.id_listview); 40 | 41 | mListView.setAdapter(new ArrayAdapter(this, -1, CLAZZES) 42 | { 43 | @Override 44 | public View getView(int position, View convertView, ViewGroup parent) 45 | { 46 | String title = getItem(position).getSimpleName(); 47 | if (convertView == null) 48 | { 49 | convertView = mInflater.inflate(R.layout.item_category, parent, false); 50 | } 51 | TextView tv = (TextView) convertView.findViewById(R.id.id_title); 52 | tv.setText(title); 53 | return convertView; 54 | } 55 | } 56 | 57 | ); 58 | 59 | mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() 60 | { 61 | @Override 62 | public void onItemClick(AdapterView parent, View view, int position, long id) 63 | { 64 | Intent intent = new Intent(CategoryActivity.this, CLAZZES[position]); 65 | intent.putExtra(BaseContentActivity.TITLE, CLAZZES[position].getSimpleName()); 66 | startActivity(intent); 67 | } 68 | }); 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/CategoryActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.ActionBarActivity; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.AdapterView; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.ListView; 12 | import android.widget.TextView; 13 | 14 | import com.zhy.sample.imageloader.local.LocalImageloaderActivity; 15 | import com.zhy.sample.imageloader.network.NetworkImageLoaderActivity; 16 | 17 | 18 | public class CategoryActivity extends ActionBarActivity 19 | { 20 | private ListView mListView; 21 | 22 | private LayoutInflater mInflater; 23 | 24 | 25 | private Class[] CLAZZES = new Class[] 26 | { 27 | NetworkImageLoaderActivity.class, 28 | LocalImageloaderActivity.class 29 | 30 | }; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) 34 | { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_category); 37 | 38 | mInflater = LayoutInflater.from(this); 39 | 40 | mListView = (ListView) findViewById(R.id.id_listview); 41 | 42 | mListView.setAdapter(new ArrayAdapter(this, -1, CLAZZES) 43 | { 44 | @Override 45 | public View getView(int position, View convertView, ViewGroup parent) 46 | { 47 | String title = getItem(position).getSimpleName(); 48 | if (convertView == null) 49 | { 50 | convertView = mInflater.inflate(R.layout.item_category, parent, false); 51 | } 52 | TextView tv = (TextView) convertView.findViewById(R.id.id_title); 53 | tv.setText(title); 54 | return convertView; 55 | } 56 | } 57 | 58 | ); 59 | 60 | mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() 61 | { 62 | @Override 63 | public void onItemClick(AdapterView parent, View view, int position, long id) 64 | { 65 | Intent intent = new Intent(CategoryActivity.this, CLAZZES[position]); 66 | intent.putExtra(BaseContentActivity.TITLE, CLAZZES[position].getSimpleName()); 67 | startActivity(intent); 68 | } 69 | }); 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/activity/ListImgsFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader.activity; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.GridView; 12 | import android.widget.ImageView; 13 | 14 | import com.zhy.base.imageloader.ImageLoader; 15 | import com.zhy.base.imageloader.R; 16 | 17 | /** 18 | * http://blog.csdn.net/lmj623565791/article/details/41874561 19 | * 20 | * @author zhy 21 | */ 22 | public class ListImgsFragment extends Fragment 23 | { 24 | private GridView mGridView; 25 | private String[] mUrlStrs = Images.imageThumbUrls; 26 | private ImageLoader mImageLoader; 27 | 28 | @Override 29 | public void onCreate(Bundle savedInstanceState) 30 | { 31 | super.onCreate(savedInstanceState); 32 | } 33 | 34 | @Override 35 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 36 | Bundle savedInstanceState) 37 | { 38 | View view = inflater.inflate(R.layout.fragment_list_imgs, container, 39 | false); 40 | mGridView = (GridView) view.findViewById(R.id.id_gridview); 41 | setUpAdapter(); 42 | return view; 43 | } 44 | 45 | private void setUpAdapter() 46 | { 47 | if (getActivity() == null || mGridView == null) 48 | return; 49 | 50 | if (mUrlStrs != null) 51 | { 52 | mGridView.setAdapter(new ListImgItemAdaper(getActivity(), 0, 53 | mUrlStrs)); 54 | } else 55 | { 56 | mGridView.setAdapter(null); 57 | } 58 | 59 | } 60 | 61 | private class ListImgItemAdaper extends ArrayAdapter 62 | { 63 | 64 | public ListImgItemAdaper(Context context, int resource, String[] datas) 65 | { 66 | super(getActivity(), 0, datas); 67 | Log.e("TAG", "ListImgItemAdaper"); 68 | } 69 | 70 | @Override 71 | public View getView(int position, View convertView, ViewGroup parent) 72 | { 73 | if (convertView == null) 74 | { 75 | convertView = getActivity().getLayoutInflater().inflate( 76 | R.layout.item_fragment_list_imgs, parent, false); 77 | } 78 | ImageView imageview = (ImageView) convertView 79 | .findViewById(R.id.id_img); 80 | imageview.setImageResource(R.drawable.pictures_no); 81 | 82 | 83 | ImageLoader.with(getContext()).load(getItem(position), imageview); 84 | return convertView; 85 | } 86 | 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/network/ListImgsFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.GridView; 12 | import android.widget.ImageView; 13 | 14 | import com.zhy.base.imageloader.ImageLoader; 15 | import com.zhy.sample.imageloader.R; 16 | 17 | 18 | /** 19 | * http://blog.csdn.net/lmj623565791/article/details/41874561 20 | * 21 | * @author zhy 22 | */ 23 | public class ListImgsFragment extends Fragment 24 | { 25 | private GridView mGridView; 26 | private String[] mUrlStrs = Images.imageThumbUrls; 27 | private ImageLoader mImageLoader; 28 | 29 | @Override 30 | public void onCreate(Bundle savedInstanceState) 31 | { 32 | super.onCreate(savedInstanceState); 33 | } 34 | 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 37 | Bundle savedInstanceState) 38 | { 39 | View view = inflater.inflate(R.layout.fragment_list_imgs, container, 40 | false); 41 | mGridView = (GridView) view.findViewById(R.id.id_gridview); 42 | setUpAdapter(); 43 | return view; 44 | } 45 | 46 | private void setUpAdapter() 47 | { 48 | if (getActivity() == null || mGridView == null) 49 | return; 50 | 51 | if (mUrlStrs != null) 52 | { 53 | mGridView.setAdapter(new ListImgItemAdaper(getActivity(), 0, 54 | mUrlStrs)); 55 | } else 56 | { 57 | mGridView.setAdapter(null); 58 | } 59 | 60 | } 61 | 62 | private class ListImgItemAdaper extends ArrayAdapter 63 | { 64 | 65 | public ListImgItemAdaper(Context context, int resource, String[] datas) 66 | { 67 | super(getActivity(), 0, datas); 68 | Log.e("TAG", "ListImgItemAdaper"); 69 | } 70 | 71 | @Override 72 | public View getView(int position, View convertView, ViewGroup parent) 73 | { 74 | if (convertView == null) 75 | { 76 | convertView = getActivity().getLayoutInflater().inflate( 77 | R.layout.item_fragment_list_imgs, parent, false); 78 | } 79 | ImageView imageview = (ImageView) convertView 80 | .findViewById(R.id.id_img); 81 | imageview.setImageResource(R.drawable.pictures_no); 82 | 83 | 84 | ImageLoader.with(getContext()).load(getItem(position), imageview); 85 | return convertView; 86 | } 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/network/ListImgsFragment.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.util.Log; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ArrayAdapter; 11 | import android.widget.GridView; 12 | import android.widget.ImageView; 13 | 14 | import com.zhy.base.imageloader.ImageLoader; 15 | import com.zhy.sample.imageloader.R; 16 | 17 | 18 | /** 19 | * http://blog.csdn.net/lmj623565791/article/details/41874561 20 | * 21 | * @author zhy 22 | */ 23 | public class ListImgsFragment extends Fragment 24 | { 25 | private GridView mGridView; 26 | private String[] mUrlStrs = Images.imageThumbUrls; 27 | private ImageLoader mImageLoader; 28 | 29 | @Override 30 | public void onCreate(Bundle savedInstanceState) 31 | { 32 | super.onCreate(savedInstanceState); 33 | } 34 | 35 | @Override 36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 37 | Bundle savedInstanceState) 38 | { 39 | View view = inflater.inflate(R.layout.fragment_list_imgs, container, 40 | false); 41 | mGridView = (GridView) view.findViewById(R.id.id_gridview); 42 | setUpAdapter(); 43 | return view; 44 | } 45 | 46 | private void setUpAdapter() 47 | { 48 | if (getActivity() == null || mGridView == null) 49 | return; 50 | 51 | if (mUrlStrs != null) 52 | { 53 | mGridView.setAdapter(new ListImgItemAdaper(getActivity(), 0, 54 | mUrlStrs)); 55 | } else 56 | { 57 | mGridView.setAdapter(null); 58 | } 59 | 60 | } 61 | 62 | private class ListImgItemAdaper extends ArrayAdapter 63 | { 64 | 65 | public ListImgItemAdaper(Context context, int resource, String[] datas) 66 | { 67 | super(getActivity(), 0, datas); 68 | Log.e("TAG", "ListImgItemAdaper"); 69 | } 70 | 71 | @Override 72 | public View getView(int position, View convertView, ViewGroup parent) 73 | { 74 | if (convertView == null) 75 | { 76 | convertView = getActivity().getLayoutInflater().inflate( 77 | R.layout.item_fragment_list_imgs, parent, false); 78 | } 79 | ImageView imageview = (ImageView) convertView 80 | .findViewById(R.id.id_img); 81 | imageview.setImageResource(R.drawable.pictures_no); 82 | 83 | 84 | ImageLoader.with(getContext()).load(getItem(position), imageview); 85 | return convertView; 86 | } 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/diskcache/disklrucache/Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.zhy.base.imageloader.diskcache.disklrucache; 18 | 19 | import java.io.Closeable; 20 | import java.io.File; 21 | import java.io.IOException; 22 | import java.io.Reader; 23 | import java.io.StringWriter; 24 | import java.nio.charset.Charset; 25 | 26 | /** 27 | * Junk drawer of utility methods. 28 | */ 29 | final class Util 30 | { 31 | static final Charset US_ASCII = Charset.forName("US-ASCII"); 32 | static final Charset UTF_8 = Charset.forName("UTF-8"); 33 | 34 | private Util() 35 | { 36 | } 37 | 38 | static String readFully(Reader reader) throws IOException 39 | { 40 | try 41 | { 42 | StringWriter writer = new StringWriter(); 43 | char[] buffer = new char[1024]; 44 | int count; 45 | while ((count = reader.read(buffer)) != -1) 46 | { 47 | writer.write(buffer, 0, count); 48 | } 49 | return writer.toString(); 50 | } finally 51 | { 52 | reader.close(); 53 | } 54 | } 55 | 56 | /** 57 | * Deletes the contents of {@code dir}. Throws an IOException if any file 58 | * could not be deleted, or if {@code dir} is not a readable directory. 59 | */ 60 | static void deleteContents(File dir) throws IOException 61 | { 62 | File[] files = dir.listFiles(); 63 | if (files == null) 64 | { 65 | throw new IOException("not a readable directory: " + dir); 66 | } 67 | for (File file : files) 68 | { 69 | if (file.isDirectory()) 70 | { 71 | deleteContents(file); 72 | } 73 | if (!file.delete()) 74 | { 75 | throw new IOException("failed to delete file: " + file); 76 | } 77 | } 78 | } 79 | 80 | static void closeQuietly(/*Auto*/Closeable closeable) 81 | { 82 | if (closeable != null) 83 | { 84 | try 85 | { 86 | closeable.close(); 87 | } catch (RuntimeException rethrown) 88 | { 89 | throw rethrown; 90 | } catch (Exception ignored) 91 | { 92 | } 93 | } 94 | } 95 | 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/activity/HttpStack.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader.activity; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | 6 | 7 | import com.zhy.base.imageloader.ContentLengthInputStream; 8 | import com.zhy.base.imageloader.IoUtils; 9 | 10 | import java.io.BufferedInputStream; 11 | import java.io.IOException; 12 | import java.io.InputStream; 13 | import java.net.HttpURLConnection; 14 | import java.net.URL; 15 | 16 | /** 17 | * Created by zhy on 15/8/11. 18 | */ 19 | public class HttpStack 20 | { 21 | 22 | /** 23 | * {@value} 24 | */ 25 | public static final int DEFAULT_HTTP_CONNECT_TIMEOUT = 5 * 1000; // milliseconds 26 | /** 27 | * {@value} 28 | */ 29 | public static final int DEFAULT_HTTP_READ_TIMEOUT = 20 * 1000; // milliseconds 30 | 31 | /** 32 | * {@value} 33 | */ 34 | protected static final int BUFFER_SIZE = 32 * 1024; // 32 Kb 35 | /** 36 | * {@value} 37 | */ 38 | protected static final String ALLOWED_URI_CHARS = "@#&=*+-_.,:!?()/~'%"; 39 | 40 | 41 | protected final Context context; 42 | protected final int connectTimeout; 43 | protected final int readTimeout; 44 | 45 | public HttpStack(Context context) 46 | { 47 | this(context, DEFAULT_HTTP_CONNECT_TIMEOUT, DEFAULT_HTTP_READ_TIMEOUT); 48 | } 49 | 50 | public HttpStack(Context context, int connectTimeout, int readTimeout) 51 | { 52 | this.context = context.getApplicationContext(); 53 | this.connectTimeout = connectTimeout; 54 | this.readTimeout = readTimeout; 55 | } 56 | 57 | protected static final int MAX_REDIRECT_COUNT = 5; 58 | 59 | protected InputStream getStreamFromNetwork(String imageUri) throws IOException 60 | { 61 | HttpURLConnection conn = createConnection(imageUri); 62 | 63 | int redirectCount = 0; 64 | while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) 65 | { 66 | conn = createConnection(conn.getHeaderField("Location")); 67 | redirectCount++; 68 | } 69 | 70 | InputStream imageStream; 71 | try 72 | { 73 | imageStream = conn.getInputStream(); 74 | } catch (IOException e) 75 | { 76 | // Read all data to allow reuse connection (http://bit.ly/1ad35PY) 77 | IoUtils.readAndCloseStream(conn.getErrorStream()); 78 | throw e; 79 | } 80 | //conn.getResponseCode() == 200; 81 | if (!shouldBeProcessed(conn)) 82 | { 83 | IoUtils.closeSilently(imageStream); 84 | throw new IOException("Image request failed with response code " + conn.getResponseCode()); 85 | } 86 | 87 | return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength()); 88 | } 89 | 90 | protected HttpURLConnection createConnection(String url) throws IOException 91 | { 92 | String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS); 93 | HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection(); 94 | conn.setConnectTimeout(connectTimeout); 95 | conn.setReadTimeout(readTimeout); 96 | return conn; 97 | } 98 | 99 | protected boolean shouldBeProcessed(HttpURLConnection conn) throws IOException 100 | { 101 | return conn.getResponseCode() == 200; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/utils/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import com.zhy.base.imageloader.ImageLoader; 4 | 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.util.SparseArray; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | public class ViewHolder { 15 | private static final String ImageView = null; 16 | private final SparseArray mViews; 17 | private int mPosition; 18 | private View mConvertView; 19 | private Context mContext; 20 | 21 | private ViewHolder(Context context, ViewGroup parent, int layoutId, 22 | int position) { 23 | mContext = context; 24 | this.mPosition = position; 25 | this.mViews = new SparseArray(); 26 | mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, 27 | false); 28 | // setTag 29 | mConvertView.setTag(this); 30 | } 31 | 32 | /** 33 | * 拿到一个ViewHolder对象 34 | * 35 | * @param context 36 | * @param convertView 37 | * @param parent 38 | * @param layoutId 39 | * @param position 40 | * @return 41 | */ 42 | public static ViewHolder get(Context context, View convertView, 43 | ViewGroup parent, int layoutId, int position) { 44 | ViewHolder holder = null; 45 | if (convertView == null) { 46 | holder = new ViewHolder(context, parent, layoutId, position); 47 | } else { 48 | holder = (ViewHolder) convertView.getTag(); 49 | holder.mPosition = position; 50 | } 51 | return holder; 52 | } 53 | 54 | public View getConvertView() { 55 | return mConvertView; 56 | } 57 | 58 | /** 59 | * 通过控件的Id获取对于的控件,如果没有则加入views 60 | * 61 | * @param viewId 62 | * @return 63 | */ 64 | public T getView(int viewId) { 65 | View view = mViews.get(viewId); 66 | if (view == null) { 67 | view = mConvertView.findViewById(viewId); 68 | mViews.put(viewId, view); 69 | } 70 | return (T) view; 71 | } 72 | 73 | /** 74 | * 为TextView设置字符串 75 | * 76 | * @param viewId 77 | * @param text 78 | * @return 79 | */ 80 | public ViewHolder setText(int viewId, String text) { 81 | TextView view = getView(viewId); 82 | view.setText(text); 83 | return this; 84 | } 85 | 86 | /** 87 | * 为ImageView设置图片 88 | * 89 | * @param viewId 90 | * @param drawableId 91 | * @return 92 | */ 93 | public ViewHolder setImageResource(int viewId, int drawableId) { 94 | ImageView view = getView(viewId); 95 | view.setImageResource(drawableId); 96 | 97 | return this; 98 | } 99 | 100 | /** 101 | * 为ImageView设置图片 102 | * 103 | * @param viewId 104 | * @param drawableId 105 | * @return 106 | */ 107 | public ViewHolder setImageBitmap(int viewId, Bitmap bm) { 108 | ImageView view = getView(viewId); 109 | view.setImageBitmap(bm); 110 | return this; 111 | } 112 | 113 | /** 114 | * 为ImageView设置图片 115 | * 116 | * @param viewId 117 | * @param drawableId 118 | * @return 119 | */ 120 | public ViewHolder setImageByUrl(int viewId, String url) { 121 | ImageView view = (ImageView) getView(viewId); 122 | ImageLoader.with(view.getContext()).load(url, 123 | view); 124 | // Picasso.with(view.getContext()).load(url).into(view); 125 | return this; 126 | } 127 | 128 | public int getPosition() { 129 | return mPosition; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/utils/ViewHolder.java: -------------------------------------------------------------------------------- 1 | package com.zhy.utils; 2 | 3 | import com.zhy.base.imageloader.ImageLoader; 4 | 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.util.SparseArray; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | public class ViewHolder { 15 | private static final String ImageView = null; 16 | private final SparseArray mViews; 17 | private int mPosition; 18 | private View mConvertView; 19 | private Context mContext; 20 | 21 | private ViewHolder(Context context, ViewGroup parent, int layoutId, 22 | int position) { 23 | mContext = context; 24 | this.mPosition = position; 25 | this.mViews = new SparseArray(); 26 | mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, 27 | false); 28 | // setTag 29 | mConvertView.setTag(this); 30 | } 31 | 32 | /** 33 | * 拿到一个ViewHolder对象 34 | * 35 | * @param context 36 | * @param convertView 37 | * @param parent 38 | * @param layoutId 39 | * @param position 40 | * @return 41 | */ 42 | public static ViewHolder get(Context context, View convertView, 43 | ViewGroup parent, int layoutId, int position) { 44 | ViewHolder holder = null; 45 | if (convertView == null) { 46 | holder = new ViewHolder(context, parent, layoutId, position); 47 | } else { 48 | holder = (ViewHolder) convertView.getTag(); 49 | holder.mPosition = position; 50 | } 51 | return holder; 52 | } 53 | 54 | public View getConvertView() { 55 | return mConvertView; 56 | } 57 | 58 | /** 59 | * 通过控件的Id获取对于的控件,如果没有则加入views 60 | * 61 | * @param viewId 62 | * @return 63 | */ 64 | public T getView(int viewId) { 65 | View view = mViews.get(viewId); 66 | if (view == null) { 67 | view = mConvertView.findViewById(viewId); 68 | mViews.put(viewId, view); 69 | } 70 | return (T) view; 71 | } 72 | 73 | /** 74 | * 为TextView设置字符串 75 | * 76 | * @param viewId 77 | * @param text 78 | * @return 79 | */ 80 | public ViewHolder setText(int viewId, String text) { 81 | TextView view = getView(viewId); 82 | view.setText(text); 83 | return this; 84 | } 85 | 86 | /** 87 | * 为ImageView设置图片 88 | * 89 | * @param viewId 90 | * @param drawableId 91 | * @return 92 | */ 93 | public ViewHolder setImageResource(int viewId, int drawableId) { 94 | ImageView view = getView(viewId); 95 | view.setImageResource(drawableId); 96 | 97 | return this; 98 | } 99 | 100 | /** 101 | * 为ImageView设置图片 102 | * 103 | * @param viewId 104 | * @param drawableId 105 | * @return 106 | */ 107 | public ViewHolder setImageBitmap(int viewId, Bitmap bm) { 108 | ImageView view = getView(viewId); 109 | view.setImageBitmap(bm); 110 | return this; 111 | } 112 | 113 | /** 114 | * 为ImageView设置图片 115 | * 116 | * @param viewId 117 | * @param drawableId 118 | * @return 119 | */ 120 | public ViewHolder setImageByUrl(int viewId, String url) { 121 | ImageView view = (ImageView) getView(viewId); 122 | ImageLoader.with(view.getContext()).load(url, 123 | view); 124 | // Picasso.with(view.getContext()).load(url).into(view); 125 | return this; 126 | } 127 | 128 | public int getPosition() { 129 | return mPosition; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/Dispatcher.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.os.Process; 7 | import android.widget.ImageView; 8 | 9 | import java.util.concurrent.BlockingQueue; 10 | 11 | /** 12 | * Created by zhy on 15/7/31. 13 | */ 14 | public abstract class Dispatcher extends Thread 15 | { 16 | protected Context mContext; 17 | protected BlockingQueue mQueue; 18 | protected volatile boolean mQuit = false; 19 | protected Handler mUiHandler; 20 | 21 | protected int mMsgSuccessWhat; 22 | protected int mMsgFailWhat; 23 | 24 | public Dispatcher(Context context, BlockingQueue queue, Handler uiHandler, int msgSuccessWhat, int msgFailWhat) 25 | { 26 | mContext = context; 27 | mQueue = queue; 28 | mUiHandler = uiHandler; 29 | 30 | mMsgSuccessWhat = msgSuccessWhat; 31 | mMsgFailWhat = msgFailWhat; 32 | 33 | } 34 | 35 | public void quit() 36 | { 37 | mQuit = true; 38 | interrupt(); 39 | } 40 | 41 | @Override 42 | public void run() 43 | { 44 | 45 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 46 | while (true) 47 | { 48 | try 49 | { 50 | ImageRequest request = mQueue.take(); 51 | if (request.checkTaskNotActual()) 52 | continue; 53 | 54 | dealRequest(request); 55 | 56 | } catch (InterruptedException e) 57 | { 58 | // 如果要求退出则退出,否则遇到异常继续 59 | if (mQuit) 60 | return; 61 | else 62 | continue; 63 | } 64 | } 65 | } 66 | 67 | protected void sendErrorMsg(ImageRequest request) 68 | { 69 | sendErrorMsg(request, mMsgFailWhat); 70 | } 71 | 72 | protected void sendSuccessMsg(ImageRequest request) 73 | { 74 | sendSuccessMsg(request, mMsgSuccessWhat); 75 | } 76 | 77 | protected abstract void dealRequest(ImageRequest request); 78 | 79 | protected void sendSuccessMsg(ImageRequest request, int what) 80 | { 81 | Message msg = Message.obtain(null, what); 82 | msg.obj = request; 83 | mUiHandler.sendMessage(msg); 84 | } 85 | 86 | protected void sendErrorMsg(ImageRequest request, int what) 87 | { 88 | Message msg = Message.obtain(null, what); 89 | msg.obj = request; 90 | mUiHandler.sendMessage(msg); 91 | } 92 | 93 | 94 | /** 95 | * 根据ImageRequest构造decode需要的参数 96 | * 97 | * @param request 98 | * @return 99 | */ 100 | protected ImageDecorder.ImageDecorderParams buildDecodeParams( 101 | ImageRequest request) 102 | { 103 | ImageDecorder.ImageDecorderParams params = new ImageDecorder.ImageDecorderParams(); 104 | params.imageView = (ImageView) request.getTarget(); 105 | params.expectSize = request.getExpectSize(); 106 | params.url = request.getUrl(); 107 | return params; 108 | } 109 | 110 | protected ImageDecorder.ImageDecorderParams buildFileDecodeParams( 111 | ImageRequest request) 112 | { 113 | ImageDecorder.ImageDecorderParams params = new ImageDecorder.ImageDecorderParams(); 114 | params.imageView = (ImageView) request.getTarget(); 115 | params.expectSize = request.getExpectSize(); 116 | params.url = Scheme.FILE.wrap(request.getUrl()); 117 | return params; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/ImageRequest.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.graphics.Bitmap; 4 | import android.net.Uri; 5 | import android.view.View; 6 | import android.widget.ImageView; 7 | 8 | import java.lang.ref.WeakReference; 9 | 10 | /** 11 | * Created by zhy on 15/7/31. 12 | */ 13 | public class ImageRequest 14 | { 15 | private ImageLoader mImageLoader; 16 | /** 17 | * 软引用图片对象 18 | */ 19 | private WeakReference mTarget; 20 | 21 | private Uri mUri; 22 | 23 | private String mCacheKey; 24 | 25 | private Bitmap mBitmap; 26 | 27 | private int mDefaultResId; 28 | 29 | private int mErrorResId; 30 | 31 | public int mExpectWidth; 32 | 33 | public int mExpectHeight; 34 | 35 | 36 | public ImageRequest(ImageLoader imageLoader, String url, Object imageView, int errorResId, int defaultResId) 37 | { 38 | mImageLoader = imageLoader; 39 | mUri = Uri.parse(url); 40 | mTarget = new WeakReference(imageView); 41 | mErrorResId = errorResId; 42 | mDefaultResId = defaultResId; 43 | 44 | if (imageView instanceof View) 45 | { 46 | ImageUtils.ImageSize viewSize = ImageUtils.getImageViewSize((View) imageView); 47 | mExpectWidth = viewSize.width; 48 | mExpectHeight = viewSize.height; 49 | mCacheKey = mUri.toString() + "_w" + mExpectWidth + "_h" + mExpectHeight; 50 | } else 51 | { 52 | throw new RuntimeException("暂不支持view以外的控件!"); 53 | } 54 | 55 | } 56 | 57 | /** 58 | * 检测当前的任务是否有必要去执行 59 | * 60 | * @return 61 | */ 62 | public boolean checkTaskNotActual() 63 | { 64 | return checkViewCollected() || checkViewReused(); 65 | 66 | } 67 | 68 | /** 69 | * 检测当前的ImageView是否已经绑定了别的url 70 | */ 71 | private boolean checkViewReused() 72 | { 73 | String cacheKey = mImageLoader.getCancelableRequestDelegate().getCacheKey(getTarget().hashCode()); 74 | return !mCacheKey.equals(cacheKey); 75 | } 76 | 77 | /** 78 | * 检测当前view是否已经被回收 79 | */ 80 | private boolean checkViewCollected() 81 | { 82 | return mTarget.get() == null; 83 | } 84 | 85 | 86 | public void setBitmap(Bitmap bitmap) 87 | { 88 | mBitmap = bitmap; 89 | } 90 | 91 | 92 | public Bitmap getBitmap() 93 | { 94 | return mBitmap; 95 | } 96 | 97 | 98 | public Object getTarget() 99 | { 100 | return mTarget.get(); 101 | } 102 | 103 | 104 | public Uri getUri() 105 | { 106 | return mUri; 107 | } 108 | 109 | 110 | public ImageUtils.ImageSize getExpectSize() 111 | { 112 | return new ImageUtils.ImageSize(mExpectWidth, mExpectHeight); 113 | } 114 | 115 | 116 | public String getCacheKey() 117 | { 118 | return mCacheKey; 119 | } 120 | 121 | public String getUrl() 122 | { 123 | return mUri.toString(); 124 | } 125 | 126 | public boolean setResBitmap() 127 | { 128 | if (checkTaskNotActual()) return false; 129 | Bitmap bm = mBitmap; 130 | ImageView imageView = (ImageView) getTarget(); 131 | if (imageView == null) return false; 132 | if (bm == null) return false; 133 | imageView.setImageBitmap(bm); 134 | mImageLoader.getCancelableRequestDelegate().remove(getTarget().hashCode()); 135 | return true; 136 | } 137 | 138 | public void setErrorImageRes() 139 | { 140 | ImageView imageView = (ImageView) mTarget.get(); 141 | if (mTarget == null || imageView == null) return; 142 | if (mErrorResId == 0) return; 143 | imageView.setImageResource(mErrorResId); 144 | } 145 | 146 | 147 | } 148 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/diskcache/disklrucache/Utils.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader.diskcache.disklrucache; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.graphics.Canvas; 9 | import android.graphics.PixelFormat; 10 | import android.graphics.drawable.BitmapDrawable; 11 | import android.graphics.drawable.Drawable; 12 | 13 | import java.io.ByteArrayOutputStream; 14 | import java.security.MessageDigest; 15 | import java.security.NoSuchAlgorithmException; 16 | 17 | public class Utils 18 | { 19 | public static int getAppVersion(Context context) 20 | { 21 | try 22 | { 23 | PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); 24 | return info.versionCode; 25 | } catch (PackageManager.NameNotFoundException e) 26 | { 27 | e.printStackTrace(); 28 | } 29 | return 1; 30 | } 31 | 32 | 33 | public static String hashKeyForDisk(String key) 34 | { 35 | String cacheKey; 36 | try 37 | { 38 | final MessageDigest mDigest = MessageDigest.getInstance("MD5"); 39 | mDigest.update(key.getBytes()); 40 | cacheKey = bytesToHexString(mDigest.digest()); 41 | } catch (NoSuchAlgorithmException e) 42 | { 43 | cacheKey = String.valueOf(key.hashCode()); 44 | } 45 | return cacheKey; 46 | } 47 | 48 | public static String bytesToHexString(byte[] bytes) 49 | { 50 | StringBuilder sb = new StringBuilder(); 51 | for (int i = 0; i < bytes.length; i++) 52 | { 53 | String hex = Integer.toHexString(0xFF & bytes[i]); 54 | if (hex.length() == 1) 55 | { 56 | sb.append('0'); 57 | } 58 | sb.append(hex); 59 | } 60 | return sb.toString(); 61 | } 62 | 63 | public static byte[] bitmap2Bytes(Bitmap bm) 64 | { 65 | if (bm == null) 66 | { 67 | return null; 68 | } 69 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 70 | bm.compress(Bitmap.CompressFormat.PNG, 100, baos); 71 | return baos.toByteArray(); 72 | } 73 | 74 | public static Bitmap bytes2Bitmap(byte[] bytes) 75 | { 76 | return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 77 | } 78 | 79 | 80 | /** 81 | * Drawable → Bitmap 82 | */ 83 | public static Bitmap drawable2Bitmap(Drawable drawable) 84 | { 85 | if (drawable == null) 86 | { 87 | return null; 88 | } 89 | // 取 drawable 的长宽 90 | int w = drawable.getIntrinsicWidth(); 91 | int h = drawable.getIntrinsicHeight(); 92 | // 取 drawable 的颜色格式 93 | Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 94 | // 建立对应 bitmap 95 | Bitmap bitmap = Bitmap.createBitmap(w, h, config); 96 | // 建立对应 bitmap 的画布 97 | Canvas canvas = new Canvas(bitmap); 98 | drawable.setBounds(0, 0, w, h); 99 | // 把 drawable 内容画到画布中 100 | drawable.draw(canvas); 101 | return bitmap; 102 | } 103 | 104 | /* 105 | * Bitmap → Drawable 106 | */ 107 | @SuppressWarnings("deprecation") 108 | public static Drawable bitmap2Drawable(Bitmap bm) 109 | { 110 | if (bm == null) 111 | { 112 | return null; 113 | } 114 | BitmapDrawable bd = new BitmapDrawable(bm); 115 | bd.setTargetDensity(bm.getDensity()); 116 | return new BitmapDrawable(bm); 117 | } 118 | } -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/NetworkDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.os.Handler; 6 | 7 | import com.zhy.base.imageloader.diskcache.disklrucache.DiskLruCache; 8 | import com.zhy.base.imageloader.diskcache.disklrucache.DiskLruCacheHelper; 9 | 10 | import java.io.IOException; 11 | import java.io.InputStream; 12 | import java.io.OutputStream; 13 | import java.util.concurrent.BlockingQueue; 14 | import java.util.concurrent.ExecutorService; 15 | import java.util.concurrent.ThreadPoolExecutor; 16 | import java.util.concurrent.TimeUnit; 17 | 18 | /** 19 | * Created by zhy on 15/7/31. 20 | */ 21 | public class NetworkDispatcher extends Dispatcher 22 | { 23 | 24 | /** 25 | * 线程池 26 | */ 27 | private ExecutorService mThreadPool; 28 | private static final int DEAFULT_THREAD_COUNT = 3; 29 | private ImageDecorder mImageDecorder; 30 | //TODO 抽象 31 | private DiskLruCacheHelper mDiskLruCache; 32 | 33 | public NetworkDispatcher(Context context, Handler uiHandler, BlockingQueue nextworkQueue, DiskLruCacheHelper diskLruCache) 34 | { 35 | super(context, nextworkQueue, uiHandler, 36 | ImageLoader.MSG_HTTP_GET_SUCCESS, 37 | ImageLoader.MSG_HTTP_GET_ERROR); 38 | mUiHandler = uiHandler; 39 | mImageDecorder = new ImageDecorder(context); 40 | mDiskLruCache = diskLruCache; 41 | // 创建线程池 42 | //mThreadPool = Executors.newFixedThreadPool(DEAFULT_THREAD_COUNT); 43 | mThreadPool = new ThreadPoolExecutor( 44 | DEAFULT_THREAD_COUNT, 45 | DEAFULT_THREAD_COUNT, 46 | 0, 47 | TimeUnit.MILLISECONDS, 48 | new LIFOLinkedBlockingDeque()); 49 | } 50 | 51 | 52 | private Runnable buildTask(final ImageRequest request) 53 | { 54 | return new Runnable() 55 | { 56 | @Override 57 | public void run() 58 | { 59 | String imageUrl = request.getUrl(); 60 | try 61 | { 62 | InputStream imageStream = mImageDecorder.getImageStream(imageUrl); 63 | //存储到硬盘缓存 64 | buildCacheToDisk(request.getCacheKey(), imageStream); 65 | //网络加载 66 | Bitmap bitmap = mImageDecorder.decodeByStream(imageStream, buildDecodeParams(request)); 67 | request.setBitmap(bitmap); 68 | sendSuccessMsg(request); 69 | } catch (IOException e) 70 | { 71 | e.printStackTrace(); 72 | L.w("network dispatcher : " + imageUrl + " decodeByStream failed , check network state and url ."); 73 | sendErrorMsg(request); 74 | } 75 | } 76 | }; 77 | } 78 | 79 | private void buildCacheToDisk(String cacheKey, InputStream imageStream) 80 | { 81 | OutputStream outputStream = null; 82 | try 83 | { 84 | DiskLruCache.Editor editor = mDiskLruCache.editor(cacheKey); 85 | if (editor == null) return; 86 | outputStream = editor.newOutputStream(0); 87 | byte[] buf = new byte[2048]; 88 | int len = 0; 89 | while ((len = imageStream.read(buf)) != -1) 90 | { 91 | outputStream.write(buf, 0, len); 92 | } 93 | outputStream.flush(); 94 | editor.commit(); 95 | } catch (IOException e) 96 | { 97 | e.printStackTrace(); 98 | L.w("network dispatcher : buildCacheToDisk failed , check log ."); 99 | } finally 100 | { 101 | if (outputStream != null) 102 | { 103 | try 104 | { 105 | outputStream.close(); 106 | } catch (IOException e) 107 | { 108 | e.printStackTrace(); 109 | } 110 | } 111 | } 112 | } 113 | 114 | 115 | @Override 116 | protected void dealRequest(ImageRequest request) 117 | { 118 | mThreadPool.execute(buildTask(request)); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/IoUtils.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright 2011-2014 Sergey Tarasevich 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *******************************************************************************/ 16 | package com.zhy.base.imageloader; 17 | 18 | import java.io.Closeable; 19 | import java.io.IOException; 20 | import java.io.InputStream; 21 | import java.io.OutputStream; 22 | 23 | /** 24 | * Provides I/O operations 25 | * 26 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 27 | * @since 1.0.0 28 | */ 29 | public final class IoUtils { 30 | 31 | /** {@value} */ 32 | public static final int DEFAULT_BUFFER_SIZE = 32 * 1024; // 32 KB 33 | /** {@value} */ 34 | public static final int DEFAULT_IMAGE_TOTAL_SIZE = 500 * 1024; // 500 Kb 35 | /** {@value} */ 36 | public static final int CONTINUE_LOADING_PERCENTAGE = 75; 37 | 38 | private IoUtils() { 39 | } 40 | 41 | /** 42 | * Copies stream, fires progress events by listener, can be interrupted by listener. Uses buffer size = 43 | * {@value #DEFAULT_BUFFER_SIZE} bytes. 44 | * 45 | * @param is Input stream 46 | * @param os Output stream 47 | * @param listener null-ok; Listener of copying progress and controller of copying interrupting 48 | * @return true - if stream copied successfully; false - if copying was interrupted by listener 49 | * @throws IOException 50 | */ 51 | public static boolean copyStream(InputStream is, OutputStream os, CopyListener listener) throws IOException { 52 | return copyStream(is, os, listener, DEFAULT_BUFFER_SIZE); 53 | } 54 | 55 | /** 56 | * Copies stream, fires progress events by listener, can be interrupted by listener. 57 | * 58 | * @param is Input stream 59 | * @param os Output stream 60 | * @param listener null-ok; Listener of copying progress and controller of copying interrupting 61 | * @param bufferSize Buffer size for copying, also represents a step for firing progress listener callback, i.e. 62 | * progress event will be fired after every copied bufferSize bytes 63 | * @return true - if stream copied successfully; false - if copying was interrupted by listener 64 | * @throws IOException 65 | */ 66 | public static boolean copyStream(InputStream is, OutputStream os, CopyListener listener, int bufferSize) 67 | throws IOException { 68 | int current = 0; 69 | int total = is.available(); 70 | if (total <= 0) { 71 | total = DEFAULT_IMAGE_TOTAL_SIZE; 72 | } 73 | 74 | final byte[] bytes = new byte[bufferSize]; 75 | int count; 76 | if (shouldStopLoading(listener, current, total)) return false; 77 | while ((count = is.read(bytes, 0, bufferSize)) != -1) { 78 | os.write(bytes, 0, count); 79 | current += count; 80 | if (shouldStopLoading(listener, current, total)) return false; 81 | } 82 | os.flush(); 83 | return true; 84 | } 85 | 86 | private static boolean shouldStopLoading(CopyListener listener, int current, int total) { 87 | if (listener != null) { 88 | boolean shouldContinue = listener.onBytesCopied(current, total); 89 | if (!shouldContinue) { 90 | if (100 * current / total < CONTINUE_LOADING_PERCENTAGE) { 91 | return true; // if loaded more than 75% then continue loading anyway 92 | } 93 | } 94 | } 95 | return false; 96 | } 97 | 98 | /** 99 | * Reads all data from stream and close it silently 100 | * 101 | * @param is Input stream 102 | */ 103 | public static void readAndCloseStream(InputStream is) { 104 | final byte[] bytes = new byte[DEFAULT_BUFFER_SIZE]; 105 | try { 106 | while (is.read(bytes, 0, DEFAULT_BUFFER_SIZE) != -1); 107 | } catch (IOException ignored) { 108 | } finally { 109 | closeSilently(is); 110 | } 111 | } 112 | 113 | public static void closeSilently(Closeable closeable) { 114 | if (closeable != null) { 115 | try { 116 | closeable.close(); 117 | } catch (Exception ignored) { 118 | } 119 | } 120 | } 121 | 122 | /** Listener and controller for copy process */ 123 | public static interface CopyListener { 124 | /** 125 | * @param current Loaded bytes 126 | * @param total Total bytes for loading 127 | * @return true - if copying should be continued; false - if copying should be interrupted 128 | */ 129 | boolean onBytesCopied(int current, int total); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/activity/Images.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader.activity; 2 | 3 | public class Images 4 | { 5 | 6 | public final static String[] imageThumbUrls = new String[] { 7 | "http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg", 8 | "http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg", 9 | "http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg", 10 | "http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg", 11 | "http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg", 12 | "http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg", 13 | "http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg", 14 | "http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg", 15 | "http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg", 16 | "http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg", 17 | "http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg", 18 | "http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg", 19 | "http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg", 20 | "http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg", 21 | "http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg", 22 | "http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg", 23 | "http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg", 24 | "http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg", 25 | "http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg", 26 | "http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg", 27 | "http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg", 28 | "http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg", 29 | "http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg", 30 | "http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg", 31 | "http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg", 32 | "http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg", 33 | "http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg", 34 | "http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg", 35 | "http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg", 36 | "http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg", 37 | "http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg", 38 | "http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg", 39 | "http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg", 40 | "http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg", 41 | "http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg", 42 | "http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg", 43 | "http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg", 44 | "http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg", 45 | "http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg", 46 | "http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg", 47 | "http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg", 48 | "http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg", 49 | "http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg", 50 | "http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg", 51 | "http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg", 52 | "http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg", 53 | "http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg", 54 | "http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg", 55 | "http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg", 56 | "http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg", 57 | "http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg", 58 | "http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg", 59 | "http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg", 60 | "http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg", 61 | "http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg", 62 | "http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg", 63 | "http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg", 64 | "http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg", 65 | "http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg", 66 | "http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg", 67 | "http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg", 68 | "http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg", 69 | "http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg", 70 | "http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg", 71 | "http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg", 72 | "http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg", 73 | "http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg", 74 | "http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg", 75 | "http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg", 76 | "http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg", 77 | "http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg", 78 | "http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg", 79 | "http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg", 80 | "http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg", 81 | "http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg", 82 | "http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg", 83 | "http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg", 84 | "http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg", 85 | "http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg", 86 | "http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg", 87 | "http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg", 88 | "http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg", 89 | "http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg", 90 | "http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg", 91 | "http://img.my.csdn.net/uploads/201407/26/1406382765_7341.jpg" }; 92 | } -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/network/Images.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | public class Images 4 | { 5 | 6 | public final static String[] imageThumbUrls = new String[] { 7 | "http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg", 8 | "http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg", 9 | "http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg", 10 | "http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg", 11 | "http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg", 12 | "http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg", 13 | "http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg", 14 | "http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg", 15 | "http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg", 16 | "http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg", 17 | "http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg", 18 | "http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg", 19 | "http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg", 20 | "http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg", 21 | "http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg", 22 | "http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg", 23 | "http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg", 24 | "http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg", 25 | "http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg", 26 | "http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg", 27 | "http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg", 28 | "http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg", 29 | "http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg", 30 | "http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg", 31 | "http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg", 32 | "http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg", 33 | "http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg", 34 | "http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg", 35 | "http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg", 36 | "http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg", 37 | "http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg", 38 | "http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg", 39 | "http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg", 40 | "http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg", 41 | "http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg", 42 | "http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg", 43 | "http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg", 44 | "http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg", 45 | "http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg", 46 | "http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg", 47 | "http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg", 48 | "http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg", 49 | "http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg", 50 | "http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg", 51 | "http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg", 52 | "http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg", 53 | "http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg", 54 | "http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg", 55 | "http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg", 56 | "http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg", 57 | "http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg", 58 | "http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg", 59 | "http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg", 60 | "http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg", 61 | "http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg", 62 | "http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg", 63 | "http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg", 64 | "http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg", 65 | "http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg", 66 | "http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg", 67 | "http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg", 68 | "http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg", 69 | "http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg", 70 | "http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg", 71 | "http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg", 72 | "http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg", 73 | "http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg", 74 | "http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg", 75 | "http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg", 76 | "http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg", 77 | "http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg", 78 | "http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg", 79 | "http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg", 80 | "http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg", 81 | "http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg", 82 | "http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg", 83 | "http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg", 84 | "http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg", 85 | "http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg", 86 | "http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg", 87 | "http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg", 88 | "http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg", 89 | "http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg", 90 | "http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg", 91 | "http://img.my.csdn.net/uploads/201407/26/1406382765_7341.jpg" }; 92 | } -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/network/Images.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.network; 2 | 3 | public class Images 4 | { 5 | 6 | public final static String[] imageThumbUrls = new String[] { 7 | "http://img.my.csdn.net/uploads/201407/26/1406383299_1976.jpg", 8 | "http://img.my.csdn.net/uploads/201407/26/1406383291_6518.jpg", 9 | "http://img.my.csdn.net/uploads/201407/26/1406383291_8239.jpg", 10 | "http://img.my.csdn.net/uploads/201407/26/1406383290_9329.jpg", 11 | "http://img.my.csdn.net/uploads/201407/26/1406383290_1042.jpg", 12 | "http://img.my.csdn.net/uploads/201407/26/1406383275_3977.jpg", 13 | "http://img.my.csdn.net/uploads/201407/26/1406383265_8550.jpg", 14 | "http://img.my.csdn.net/uploads/201407/26/1406383264_3954.jpg", 15 | "http://img.my.csdn.net/uploads/201407/26/1406383264_4787.jpg", 16 | "http://img.my.csdn.net/uploads/201407/26/1406383264_8243.jpg", 17 | "http://img.my.csdn.net/uploads/201407/26/1406383248_3693.jpg", 18 | "http://img.my.csdn.net/uploads/201407/26/1406383243_5120.jpg", 19 | "http://img.my.csdn.net/uploads/201407/26/1406383242_3127.jpg", 20 | "http://img.my.csdn.net/uploads/201407/26/1406383242_9576.jpg", 21 | "http://img.my.csdn.net/uploads/201407/26/1406383242_1721.jpg", 22 | "http://img.my.csdn.net/uploads/201407/26/1406383219_5806.jpg", 23 | "http://img.my.csdn.net/uploads/201407/26/1406383214_7794.jpg", 24 | "http://img.my.csdn.net/uploads/201407/26/1406383213_4418.jpg", 25 | "http://img.my.csdn.net/uploads/201407/26/1406383213_3557.jpg", 26 | "http://img.my.csdn.net/uploads/201407/26/1406383210_8779.jpg", 27 | "http://img.my.csdn.net/uploads/201407/26/1406383172_4577.jpg", 28 | "http://img.my.csdn.net/uploads/201407/26/1406383166_3407.jpg", 29 | "http://img.my.csdn.net/uploads/201407/26/1406383166_2224.jpg", 30 | "http://img.my.csdn.net/uploads/201407/26/1406383166_7301.jpg", 31 | "http://img.my.csdn.net/uploads/201407/26/1406383165_7197.jpg", 32 | "http://img.my.csdn.net/uploads/201407/26/1406383150_8410.jpg", 33 | "http://img.my.csdn.net/uploads/201407/26/1406383131_3736.jpg", 34 | "http://img.my.csdn.net/uploads/201407/26/1406383130_5094.jpg", 35 | "http://img.my.csdn.net/uploads/201407/26/1406383130_7393.jpg", 36 | "http://img.my.csdn.net/uploads/201407/26/1406383129_8813.jpg", 37 | "http://img.my.csdn.net/uploads/201407/26/1406383100_3554.jpg", 38 | "http://img.my.csdn.net/uploads/201407/26/1406383093_7894.jpg", 39 | "http://img.my.csdn.net/uploads/201407/26/1406383092_2432.jpg", 40 | "http://img.my.csdn.net/uploads/201407/26/1406383092_3071.jpg", 41 | "http://img.my.csdn.net/uploads/201407/26/1406383091_3119.jpg", 42 | "http://img.my.csdn.net/uploads/201407/26/1406383059_6589.jpg", 43 | "http://img.my.csdn.net/uploads/201407/26/1406383059_8814.jpg", 44 | "http://img.my.csdn.net/uploads/201407/26/1406383059_2237.jpg", 45 | "http://img.my.csdn.net/uploads/201407/26/1406383058_4330.jpg", 46 | "http://img.my.csdn.net/uploads/201407/26/1406383038_3602.jpg", 47 | "http://img.my.csdn.net/uploads/201407/26/1406382942_3079.jpg", 48 | "http://img.my.csdn.net/uploads/201407/26/1406382942_8125.jpg", 49 | "http://img.my.csdn.net/uploads/201407/26/1406382942_4881.jpg", 50 | "http://img.my.csdn.net/uploads/201407/26/1406382941_4559.jpg", 51 | "http://img.my.csdn.net/uploads/201407/26/1406382941_3845.jpg", 52 | "http://img.my.csdn.net/uploads/201407/26/1406382924_8955.jpg", 53 | "http://img.my.csdn.net/uploads/201407/26/1406382923_2141.jpg", 54 | "http://img.my.csdn.net/uploads/201407/26/1406382923_8437.jpg", 55 | "http://img.my.csdn.net/uploads/201407/26/1406382922_6166.jpg", 56 | "http://img.my.csdn.net/uploads/201407/26/1406382922_4843.jpg", 57 | "http://img.my.csdn.net/uploads/201407/26/1406382905_5804.jpg", 58 | "http://img.my.csdn.net/uploads/201407/26/1406382904_3362.jpg", 59 | "http://img.my.csdn.net/uploads/201407/26/1406382904_2312.jpg", 60 | "http://img.my.csdn.net/uploads/201407/26/1406382904_4960.jpg", 61 | "http://img.my.csdn.net/uploads/201407/26/1406382900_2418.jpg", 62 | "http://img.my.csdn.net/uploads/201407/26/1406382881_4490.jpg", 63 | "http://img.my.csdn.net/uploads/201407/26/1406382881_5935.jpg", 64 | "http://img.my.csdn.net/uploads/201407/26/1406382880_3865.jpg", 65 | "http://img.my.csdn.net/uploads/201407/26/1406382880_4662.jpg", 66 | "http://img.my.csdn.net/uploads/201407/26/1406382879_2553.jpg", 67 | "http://img.my.csdn.net/uploads/201407/26/1406382862_5375.jpg", 68 | "http://img.my.csdn.net/uploads/201407/26/1406382862_1748.jpg", 69 | "http://img.my.csdn.net/uploads/201407/26/1406382861_7618.jpg", 70 | "http://img.my.csdn.net/uploads/201407/26/1406382861_8606.jpg", 71 | "http://img.my.csdn.net/uploads/201407/26/1406382861_8949.jpg", 72 | "http://img.my.csdn.net/uploads/201407/26/1406382841_9821.jpg", 73 | "http://img.my.csdn.net/uploads/201407/26/1406382840_6603.jpg", 74 | "http://img.my.csdn.net/uploads/201407/26/1406382840_2405.jpg", 75 | "http://img.my.csdn.net/uploads/201407/26/1406382840_6354.jpg", 76 | "http://img.my.csdn.net/uploads/201407/26/1406382839_5779.jpg", 77 | "http://img.my.csdn.net/uploads/201407/26/1406382810_7578.jpg", 78 | "http://img.my.csdn.net/uploads/201407/26/1406382810_2436.jpg", 79 | "http://img.my.csdn.net/uploads/201407/26/1406382809_3883.jpg", 80 | "http://img.my.csdn.net/uploads/201407/26/1406382809_6269.jpg", 81 | "http://img.my.csdn.net/uploads/201407/26/1406382808_4179.jpg", 82 | "http://img.my.csdn.net/uploads/201407/26/1406382790_8326.jpg", 83 | "http://img.my.csdn.net/uploads/201407/26/1406382789_7174.jpg", 84 | "http://img.my.csdn.net/uploads/201407/26/1406382789_5170.jpg", 85 | "http://img.my.csdn.net/uploads/201407/26/1406382789_4118.jpg", 86 | "http://img.my.csdn.net/uploads/201407/26/1406382788_9532.jpg", 87 | "http://img.my.csdn.net/uploads/201407/26/1406382767_3184.jpg", 88 | "http://img.my.csdn.net/uploads/201407/26/1406382767_4772.jpg", 89 | "http://img.my.csdn.net/uploads/201407/26/1406382766_4924.jpg", 90 | "http://img.my.csdn.net/uploads/201407/26/1406382766_5762.jpg", 91 | "http://img.my.csdn.net/uploads/201407/26/1406382765_7341.jpg" }; 92 | } -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/ImageUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.graphics.BitmapFactory; 4 | import android.util.DisplayMetrics; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | 9 | import java.io.InputStream; 10 | import java.lang.reflect.Field; 11 | 12 | /** 13 | * Created by zhy on 15/8/11. 14 | */ 15 | public class ImageUtils 16 | { 17 | /** 18 | * 根据InputStream获取图片实际的宽度和高度 19 | * 20 | * @param imageStream 21 | * @return 22 | */ 23 | public static ImageSize getImageSize(InputStream imageStream) 24 | { 25 | BitmapFactory.Options options = new BitmapFactory.Options(); 26 | options.inJustDecodeBounds = true; 27 | BitmapFactory.decodeStream(imageStream, null, options); 28 | 29 | return new ImageSize(options.outWidth, options.outHeight); 30 | } 31 | 32 | public static class ImageSize 33 | { 34 | int width; 35 | int height; 36 | 37 | public ImageSize() 38 | { 39 | } 40 | 41 | public ImageSize(int width, int height) 42 | { 43 | this.width = width; 44 | this.height = height; 45 | } 46 | 47 | @Override 48 | public String toString() 49 | { 50 | return "ImageSize{" + 51 | "width=" + width + 52 | ", height=" + height + 53 | '}'; 54 | } 55 | } 56 | 57 | public static int calculateInSampleSize(ImageSize srcSize, ImageSize targetSize) 58 | { 59 | // 源图片的宽度 60 | int width = srcSize.width; 61 | int height = srcSize.height; 62 | int inSampleSize = 1; 63 | 64 | int reqWidth = targetSize.width; 65 | int reqHeight = targetSize.height; 66 | 67 | if (width > reqWidth && height > reqHeight) 68 | { 69 | // 计算出实际宽度和目标宽度的比率 70 | int widthRatio = Math.round((float) width / (float) reqWidth); 71 | int heightRatio = Math.round((float) height / (float) reqHeight); 72 | inSampleSize = Math.max(widthRatio, heightRatio); 73 | } 74 | return inSampleSize; 75 | } 76 | 77 | /** 78 | * 计算合适的inSampleSize 79 | */ 80 | public static int computeImageSampleSize(ImageSize srcSize, ImageSize targetSize, ImageView imageView) 81 | { 82 | final int srcWidth = srcSize.width; 83 | final int srcHeight = srcSize.height; 84 | final int targetWidth = targetSize.width; 85 | final int targetHeight = targetSize.height; 86 | 87 | int scale = 1; 88 | 89 | if (imageView == null) 90 | { 91 | scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max 92 | } else 93 | { 94 | switch (imageView.getScaleType()) 95 | { 96 | case FIT_CENTER: 97 | case FIT_XY: 98 | case FIT_START: 99 | case FIT_END: 100 | case CENTER_INSIDE: 101 | scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max 102 | break; 103 | case CENTER: 104 | case CENTER_CROP: 105 | case MATRIX: 106 | scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // min 107 | break; 108 | default: 109 | scale = Math.max(srcWidth / targetWidth, srcHeight / targetHeight); // max 110 | break; 111 | } 112 | } 113 | 114 | if (scale < 1) 115 | { 116 | scale = 1; 117 | } 118 | 119 | return scale; 120 | } 121 | 122 | /** 123 | * 根据ImageView获适当的压缩的宽和高 124 | * 125 | * @param view 126 | * @return 127 | */ 128 | public static ImageSize getImageViewSize(View view) 129 | { 130 | 131 | ImageSize imageSize = new ImageSize(); 132 | 133 | imageSize.width = getExpectWidth(view); 134 | imageSize.height = getExpectHeight(view); 135 | 136 | return imageSize; 137 | } 138 | 139 | /** 140 | * 根据view获得期望的高度 141 | * 142 | * @param view 143 | * @return 144 | */ 145 | private static int getExpectHeight(View view) 146 | { 147 | 148 | int height = 0; 149 | if (view == null) return 0; 150 | 151 | final ViewGroup.LayoutParams params = view.getLayoutParams(); 152 | //如果是WRAP_CONTENT,此时图片还没加载,getWidth根本无效 153 | if (params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) 154 | { 155 | height = view.getWidth(); // 获得实际的宽度 156 | } 157 | if (height <= 0 && params != null) 158 | { 159 | height = params.height; // 获得布局文件中的声明的宽度 160 | } 161 | 162 | if (height <= 0) 163 | { 164 | height = getImageViewFieldValue(view, "mMaxHeight");// 获得设置的最大的宽度 165 | } 166 | 167 | //如果宽度还是没有获取到,憋大招,使用屏幕的宽度 168 | if (height <= 0) 169 | { 170 | DisplayMetrics displayMetrics = view.getContext().getResources() 171 | .getDisplayMetrics(); 172 | height = displayMetrics.heightPixels; 173 | } 174 | 175 | return height; 176 | } 177 | 178 | /** 179 | * 根据view获得期望的宽度 180 | * 181 | * @param view 182 | * @return 183 | */ 184 | private static int getExpectWidth(View view) 185 | { 186 | int width = 0; 187 | if (view == null) return 0; 188 | 189 | final ViewGroup.LayoutParams params = view.getLayoutParams(); 190 | //如果是WRAP_CONTENT,此时图片还没加载,getWidth根本无效 191 | if (params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) 192 | { 193 | width = view.getWidth(); // 获得实际的宽度 194 | } 195 | if (width <= 0 && params != null) 196 | { 197 | width = params.width; // 获得布局文件中的声明的宽度 198 | } 199 | 200 | if (width <= 0) 201 | 202 | { 203 | width = getImageViewFieldValue(view, "mMaxWidth");// 获得设置的最大的宽度 204 | } 205 | //如果宽度还是没有获取到,憋大招,使用屏幕的宽度 206 | if (width <= 0) 207 | 208 | { 209 | DisplayMetrics displayMetrics = view.getContext().getResources() 210 | .getDisplayMetrics(); 211 | width = displayMetrics.widthPixels; 212 | } 213 | 214 | return width; 215 | } 216 | 217 | /** 218 | * 通过反射获取imageview的某个属性值 219 | * 220 | * @param object 221 | * @param fieldName 222 | * @return 223 | */ 224 | private static int getImageViewFieldValue(Object object, String fieldName) 225 | { 226 | int value = 0; 227 | try 228 | { 229 | Field field = ImageView.class.getDeclaredField(fieldName); 230 | field.setAccessible(true); 231 | int fieldValue = field.getInt(object); 232 | if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) 233 | { 234 | value = fieldValue; 235 | } 236 | } catch (Exception e) 237 | { 238 | } 239 | return value; 240 | 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/diskcache/disklrucache/StrictLineReader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2012 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.zhy.base.imageloader.diskcache.disklrucache; 18 | 19 | import java.io.ByteArrayOutputStream; 20 | import java.io.Closeable; 21 | import java.io.EOFException; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.io.UnsupportedEncodingException; 25 | import java.nio.charset.Charset; 26 | 27 | /** 28 | * Buffers input from an {@link InputStream} for reading lines. 29 | * 30 | *

This class is used for buffered reading of lines. For purposes of this class, a line ends 31 | * with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated 32 | * line at end of input is invalid and will be ignored, the caller may use {@code 33 | * hasUnterminatedLine()} to detect it after catching the {@code EOFException}. 34 | * 35 | *

This class is intended for reading input that strictly consists of lines, such as line-based 36 | * cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction 37 | * with {@link java.io.InputStreamReader} provides similar functionality, this class uses different 38 | * end-of-input reporting and a more restrictive definition of a line. 39 | * 40 | *

This class supports only charsets that encode '\r' and '\n' as a single byte with value 13 41 | * and 10, respectively, and the representation of no other character contains these values. 42 | * We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1. 43 | * The default charset is US_ASCII. 44 | */ 45 | class StrictLineReader implements Closeable { 46 | private static final byte CR = (byte) '\r'; 47 | private static final byte LF = (byte) '\n'; 48 | 49 | private final InputStream in; 50 | private final Charset charset; 51 | 52 | /* 53 | * Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end 54 | * and the data in the range [pos, end) is buffered for reading. At end of input, if there is 55 | * an unterminated line, we set end == -1, otherwise end == pos. If the underlying 56 | * {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1. 57 | */ 58 | private byte[] buf; 59 | private int pos; 60 | private int end; 61 | 62 | /** 63 | * Constructs a new {@code LineReader} with the specified charset and the default capacity. 64 | * 65 | * @param in the {@code InputStream} to read data from. 66 | * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are 67 | * supported. 68 | * @throws NullPointerException if {@code in} or {@code charset} is null. 69 | * @throws IllegalArgumentException if the specified charset is not supported. 70 | */ 71 | public StrictLineReader(InputStream in, Charset charset) { 72 | this(in, 8192, charset); 73 | } 74 | 75 | /** 76 | * Constructs a new {@code LineReader} with the specified capacity and charset. 77 | * 78 | * @param in the {@code InputStream} to read data from. 79 | * @param capacity the capacity of the buffer. 80 | * @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are 81 | * supported. 82 | * @throws NullPointerException if {@code in} or {@code charset} is null. 83 | * @throws IllegalArgumentException if {@code capacity} is negative or zero 84 | * or the specified charset is not supported. 85 | */ 86 | public StrictLineReader(InputStream in, int capacity, Charset charset) { 87 | if (in == null || charset == null) { 88 | throw new NullPointerException(); 89 | } 90 | if (capacity < 0) { 91 | throw new IllegalArgumentException("capacity <= 0"); 92 | } 93 | if (!(charset.equals(Util.US_ASCII))) { 94 | throw new IllegalArgumentException("Unsupported encoding"); 95 | } 96 | 97 | this.in = in; 98 | this.charset = charset; 99 | buf = new byte[capacity]; 100 | } 101 | 102 | /** 103 | * Closes the reader by closing the underlying {@code InputStream} and 104 | * marking this reader as closed. 105 | * 106 | * @throws IOException for errors when closing the underlying {@code InputStream}. 107 | */ 108 | public void close() throws IOException { 109 | synchronized (in) { 110 | if (buf != null) { 111 | buf = null; 112 | in.close(); 113 | } 114 | } 115 | } 116 | 117 | /** 118 | * Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"}, 119 | * this end of line marker is not included in the result. 120 | * 121 | * @return the next line from the input. 122 | * @throws IOException for underlying {@code InputStream} errors. 123 | * @throws EOFException for the end of source stream. 124 | */ 125 | public String readLine() throws IOException { 126 | synchronized (in) { 127 | if (buf == null) { 128 | throw new IOException("LineReader is closed"); 129 | } 130 | 131 | // Read more data if we are at the end of the buffered data. 132 | // Though it's an error to read after an exception, we will let {@code fillBuf()} 133 | // throw again if that happens; thus we need to handle end == -1 as well as end == pos. 134 | if (pos >= end) { 135 | fillBuf(); 136 | } 137 | // Try to find LF in the buffered data and return the line if successful. 138 | for (int i = pos; i != end; ++i) { 139 | if (buf[i] == LF) { 140 | int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i; 141 | String res = new String(buf, pos, lineEnd - pos, charset.name()); 142 | pos = i + 1; 143 | return res; 144 | } 145 | } 146 | 147 | // Let's anticipate up to 80 characters on top of those already read. 148 | ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) { 149 | @Override 150 | public String toString() { 151 | int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count; 152 | try { 153 | return new String(buf, 0, length, charset.name()); 154 | } catch (UnsupportedEncodingException e) { 155 | throw new AssertionError(e); // Since we control the charset this will never happen. 156 | } 157 | } 158 | }; 159 | 160 | while (true) { 161 | out.write(buf, pos, end - pos); 162 | // Mark unterminated line in case fillBuf throws EOFException or IOException. 163 | end = -1; 164 | fillBuf(); 165 | // Try to find LF in the buffered data and return the line if successful. 166 | for (int i = pos; i != end; ++i) { 167 | if (buf[i] == LF) { 168 | if (i != pos) { 169 | out.write(buf, pos, i - pos); 170 | } 171 | pos = i + 1; 172 | return out.toString(); 173 | } 174 | } 175 | } 176 | } 177 | } 178 | 179 | public boolean hasUnterminatedLine() { 180 | return end == -1; 181 | } 182 | 183 | /** 184 | * Reads new input data into the buffer. Call only with pos == end or end == -1, 185 | * depending on the desired outcome if the function throws. 186 | */ 187 | private void fillBuf() throws IOException { 188 | int result = in.read(buf, 0, buf.length); 189 | if (result == -1) { 190 | throw new EOFException(); 191 | } 192 | pos = 0; 193 | end = result; 194 | } 195 | } 196 | 197 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-androidstudio/src/main/java/com/zhy/sample/imageloader/local/LocalImageloaderActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import android.app.Activity; 4 | import android.app.ProgressDialog; 5 | import android.content.ContentResolver; 6 | import android.database.Cursor; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.os.Environment; 10 | import android.os.Handler; 11 | import android.provider.MediaStore; 12 | import android.util.DisplayMetrics; 13 | import android.util.Log; 14 | import android.view.LayoutInflater; 15 | import android.view.View; 16 | import android.view.View.OnClickListener; 17 | import android.view.ViewGroup.LayoutParams; 18 | import android.view.WindowManager; 19 | import android.widget.GridView; 20 | import android.widget.PopupWindow.OnDismissListener; 21 | import android.widget.RelativeLayout; 22 | import android.widget.TextView; 23 | import android.widget.Toast; 24 | 25 | import com.zhy.sample.imageloader.R; 26 | 27 | import java.io.File; 28 | import java.io.FilenameFilter; 29 | import java.util.ArrayList; 30 | import java.util.Arrays; 31 | import java.util.HashSet; 32 | import java.util.List; 33 | 34 | public class LocalImageloaderActivity extends Activity implements ListImageDirPopupWindow.OnImageDirSelected 35 | { 36 | private ProgressDialog mProgressDialog; 37 | 38 | /** 39 | * 存储文件夹中的图片数量 40 | */ 41 | private int mPicsSize; 42 | /** 43 | * 图片数量最多的文件夹 44 | */ 45 | private File mImgDir; 46 | /** 47 | * 所有的图片 48 | */ 49 | private List mImgs; 50 | 51 | private GridView mGirdView; 52 | private MyAdapter mAdapter; 53 | /** 54 | * 临时的辅助类,用于防止同一个文件夹的多次扫描 55 | */ 56 | private HashSet mDirPaths = new HashSet(); 57 | 58 | /** 59 | * 扫描拿到所有的图片文件夹 60 | */ 61 | private List mImageFloders = new ArrayList(); 62 | 63 | private RelativeLayout mBottomLy; 64 | 65 | private TextView mChooseDir; 66 | private TextView mImageCount; 67 | int totalCount = 0; 68 | 69 | private int mScreenHeight; 70 | 71 | private ListImageDirPopupWindow mListImageDirPopupWindow; 72 | 73 | private Handler mHandler = new Handler() 74 | { 75 | public void handleMessage(android.os.Message msg) 76 | { 77 | mProgressDialog.dismiss(); 78 | // 为View绑定数据 79 | data2View(); 80 | // 初始化展示文件夹的popupWindw 81 | initListDirPopupWindw(); 82 | } 83 | }; 84 | 85 | /** 86 | * 为View绑定数据 87 | */ 88 | private void data2View() 89 | { 90 | if (mImgDir == null) 91 | { 92 | Toast.makeText(getApplicationContext(), "擦,一张图片没扫描到", 93 | Toast.LENGTH_SHORT).show(); 94 | return; 95 | } 96 | 97 | mImgs = Arrays.asList(mImgDir.list(new FilenameFilter() { 98 | 99 | @Override 100 | public boolean accept(File dir, String filename) { 101 | if (filename.endsWith(".jpg") 102 | || filename.endsWith(".png") 103 | || filename.endsWith(".jpeg")) 104 | return true; 105 | return false; 106 | } 107 | })); 108 | /** 109 | * 可以看到文件夹的路径和图片的路径分开保存,极大的减少了内存的消耗; 110 | */ 111 | mAdapter = new MyAdapter(getApplicationContext(), mImgs, 112 | R.layout.grid_item, mImgDir.getAbsolutePath()); 113 | mGirdView.setAdapter(mAdapter); 114 | mImageCount.setText(totalCount + "张"); 115 | }; 116 | 117 | /** 118 | * 初始化展示文件夹的popupWindw 119 | */ 120 | private void initListDirPopupWindw() 121 | { 122 | mListImageDirPopupWindow = new ListImageDirPopupWindow( 123 | LayoutParams.MATCH_PARENT, (int) (mScreenHeight * 0.7), 124 | mImageFloders, LayoutInflater.from(getApplicationContext()) 125 | .inflate(R.layout.list_dir, null)); 126 | 127 | mListImageDirPopupWindow.setOnDismissListener(new OnDismissListener() 128 | { 129 | 130 | @Override 131 | public void onDismiss() 132 | { 133 | // 设置背景颜色变暗 134 | WindowManager.LayoutParams lp = getWindow().getAttributes(); 135 | lp.alpha = 1.0f; 136 | getWindow().setAttributes(lp); 137 | } 138 | }); 139 | // 设置选择文件夹的回调 140 | mListImageDirPopupWindow.setOnImageDirSelected(this); 141 | } 142 | 143 | @Override 144 | protected void onCreate(Bundle savedInstanceState) 145 | { 146 | super.onCreate(savedInstanceState); 147 | setContentView(R.layout.activity_local_main); 148 | 149 | DisplayMetrics outMetrics = new DisplayMetrics(); 150 | getWindowManager().getDefaultDisplay().getMetrics(outMetrics); 151 | mScreenHeight = outMetrics.heightPixels; 152 | 153 | initView(); 154 | getImages(); 155 | initEvent(); 156 | 157 | } 158 | 159 | /** 160 | * 利用ContentProvider扫描手机中的图片,此方法在运行在子线程中 完成图片的扫描,最终获得jpg最多的那个文件夹 161 | */ 162 | private void getImages() 163 | { 164 | if (!Environment.getExternalStorageState().equals( 165 | Environment.MEDIA_MOUNTED)) 166 | { 167 | Toast.makeText(this, "暂无外部存储", Toast.LENGTH_SHORT).show(); 168 | return; 169 | } 170 | // 显示进度条 171 | mProgressDialog = ProgressDialog.show(this, null, "正在加载..."); 172 | 173 | new Thread(new Runnable() 174 | { 175 | @Override 176 | public void run() 177 | { 178 | 179 | String firstImage = null; 180 | 181 | Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 182 | ContentResolver mContentResolver = LocalImageloaderActivity.this 183 | .getContentResolver(); 184 | 185 | // 只查询jpeg和png的图片 186 | Cursor mCursor = mContentResolver.query(mImageUri, null, 187 | MediaStore.Images.Media.MIME_TYPE + "=? or " 188 | + MediaStore.Images.Media.MIME_TYPE + "=?", 189 | new String[] { "image/jpeg", "image/png" }, 190 | MediaStore.Images.Media.DATE_MODIFIED); 191 | 192 | Log.e("TAG", mCursor.getCount() + ""); 193 | while (mCursor.moveToNext()) 194 | { 195 | // 获取图片的路径 196 | String path = mCursor.getString(mCursor 197 | .getColumnIndex(MediaStore.Images.Media.DATA)); 198 | 199 | //Log.e("TAG", path); 200 | // 拿到第一张图片的路径 201 | if (firstImage == null) 202 | firstImage = path; 203 | // 获取该图片的父路径名 204 | File parentFile = new File(path).getParentFile(); 205 | if (parentFile == null) 206 | continue; 207 | String dirPath = parentFile.getAbsolutePath(); 208 | ImageFloder imageFloder = null; 209 | // 利用一个HashSet防止多次扫描同一个文件夹(不加这个判断,图片多起来还是相当恐怖的~~) 210 | if (mDirPaths.contains(dirPath)) 211 | { 212 | continue; 213 | } else 214 | { 215 | mDirPaths.add(dirPath); 216 | // 初始化imageFloder 217 | imageFloder = new ImageFloder(); 218 | imageFloder.setDir(dirPath); 219 | imageFloder.setFirstImagePath(path); 220 | } 221 | 222 | int picSize = parentFile.list(new FilenameFilter() 223 | { 224 | @Override 225 | public boolean accept(File dir, String filename) 226 | { 227 | if (filename.endsWith(".jpg") 228 | || filename.endsWith(".png") 229 | || filename.endsWith(".jpeg")) 230 | return true; 231 | return false; 232 | } 233 | }).length; 234 | totalCount += picSize; 235 | 236 | imageFloder.setCount(picSize); 237 | mImageFloders.add(imageFloder); 238 | 239 | if (picSize > mPicsSize) 240 | { 241 | mPicsSize = picSize; 242 | mImgDir = parentFile; 243 | } 244 | } 245 | mCursor.close(); 246 | 247 | // 扫描完成,辅助的HashSet也就可以释放内存了 248 | mDirPaths = null; 249 | 250 | // 通知Handler扫描图片完成 251 | mHandler.sendEmptyMessage(0x110); 252 | 253 | } 254 | }).start(); 255 | 256 | } 257 | 258 | /** 259 | * 初始化View 260 | */ 261 | private void initView() 262 | { 263 | mGirdView = (GridView) findViewById(R.id.id_gridView); 264 | mChooseDir = (TextView) findViewById(R.id.id_choose_dir); 265 | mImageCount = (TextView) findViewById(R.id.id_total_count); 266 | 267 | mBottomLy = (RelativeLayout) findViewById(R.id.id_bottom_ly); 268 | 269 | } 270 | 271 | private void initEvent() 272 | { 273 | /** 274 | * 为底部的布局设置点击事件,弹出popupWindow 275 | */ 276 | mBottomLy.setOnClickListener(new OnClickListener() 277 | { 278 | @Override 279 | public void onClick(View v) 280 | { 281 | mListImageDirPopupWindow 282 | .setAnimationStyle(R.style.anim_popup_dir); 283 | mListImageDirPopupWindow.showAsDropDown(mBottomLy, 0, 0); 284 | 285 | // 设置背景颜色变暗 286 | WindowManager.LayoutParams lp = getWindow().getAttributes(); 287 | lp.alpha = .3f; 288 | getWindow().setAttributes(lp); 289 | } 290 | }); 291 | } 292 | 293 | @Override 294 | public void selected(ImageFloder floder) 295 | { 296 | 297 | mImgDir = new File(floder.getDir()); 298 | mImgs = Arrays.asList(mImgDir.list(new FilenameFilter() 299 | { 300 | @Override 301 | public boolean accept(File dir, String filename) 302 | { 303 | if (filename.endsWith(".jpg") || filename.endsWith(".png") 304 | || filename.endsWith(".jpeg")) 305 | return true; 306 | return false; 307 | } 308 | })); 309 | /** 310 | * 可以看到文件夹的路径和图片的路径分开保存,极大的减少了内存的消耗; 311 | */ 312 | mAdapter = new MyAdapter(getApplicationContext(), mImgs, 313 | R.layout.grid_item, mImgDir.getAbsolutePath()); 314 | mGirdView.setAdapter(mAdapter); 315 | // mAdapter.notifyDataSetChanged(); 316 | mImageCount.setText(floder.getCount() + "张"); 317 | mChooseDir.setText(floder.getName()); 318 | mListImageDirPopupWindow.dismiss(); 319 | 320 | } 321 | 322 | } 323 | -------------------------------------------------------------------------------- /sample/sample-imageloader-for-eclipse/src/com/zhy/sample/imageloader/local/LocalImageloaderActivity.java: -------------------------------------------------------------------------------- 1 | package com.zhy.sample.imageloader.local; 2 | 3 | import java.io.File; 4 | import java.io.FilenameFilter; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.HashSet; 8 | import java.util.List; 9 | 10 | import android.app.Activity; 11 | import android.app.ProgressDialog; 12 | import android.content.ContentResolver; 13 | import android.database.Cursor; 14 | import android.net.Uri; 15 | import android.os.Bundle; 16 | import android.os.Environment; 17 | import android.os.Handler; 18 | import android.provider.MediaStore; 19 | import android.util.DisplayMetrics; 20 | import android.util.Log; 21 | import android.view.LayoutInflater; 22 | import android.view.View; 23 | import android.view.View.OnClickListener; 24 | import android.view.ViewGroup.LayoutParams; 25 | import android.view.WindowManager; 26 | import android.widget.GridView; 27 | import android.widget.PopupWindow.OnDismissListener; 28 | import android.widget.RelativeLayout; 29 | import android.widget.TextView; 30 | import android.widget.Toast; 31 | 32 | import com.zhy.sample.imageloader.R; 33 | import com.zhy.sample.imageloader.R.id; 34 | import com.zhy.sample.imageloader.R.layout; 35 | import com.zhy.sample.imageloader.R.style; 36 | import com.zhy.sample.imageloader.local.ListImageDirPopupWindow.OnImageDirSelected; 37 | 38 | public class LocalImageloaderActivity extends Activity implements OnImageDirSelected 39 | { 40 | private ProgressDialog mProgressDialog; 41 | 42 | /** 43 | * 存储文件夹中的图片数量 44 | */ 45 | private int mPicsSize; 46 | /** 47 | * 图片数量最多的文件夹 48 | */ 49 | private File mImgDir; 50 | /** 51 | * 所有的图片 52 | */ 53 | private List mImgs; 54 | 55 | private GridView mGirdView; 56 | private MyAdapter mAdapter; 57 | /** 58 | * 临时的辅助类,用于防止同一个文件夹的多次扫描 59 | */ 60 | private HashSet mDirPaths = new HashSet(); 61 | 62 | /** 63 | * 扫描拿到所有的图片文件夹 64 | */ 65 | private List mImageFloders = new ArrayList(); 66 | 67 | private RelativeLayout mBottomLy; 68 | 69 | private TextView mChooseDir; 70 | private TextView mImageCount; 71 | int totalCount = 0; 72 | 73 | private int mScreenHeight; 74 | 75 | private ListImageDirPopupWindow mListImageDirPopupWindow; 76 | 77 | private Handler mHandler = new Handler() 78 | { 79 | public void handleMessage(android.os.Message msg) 80 | { 81 | mProgressDialog.dismiss(); 82 | // 为View绑定数据 83 | data2View(); 84 | // 初始化展示文件夹的popupWindw 85 | initListDirPopupWindw(); 86 | } 87 | }; 88 | 89 | /** 90 | * 为View绑定数据 91 | */ 92 | private void data2View() 93 | { 94 | if (mImgDir == null) 95 | { 96 | Toast.makeText(getApplicationContext(), "擦,一张图片没扫描到", 97 | Toast.LENGTH_SHORT).show(); 98 | return; 99 | } 100 | 101 | mImgs = Arrays.asList(mImgDir.list(new FilenameFilter() { 102 | 103 | @Override 104 | public boolean accept(File dir, String filename) { 105 | if (filename.endsWith(".jpg") 106 | || filename.endsWith(".png") 107 | || filename.endsWith(".jpeg")) 108 | return true; 109 | return false; 110 | } 111 | })); 112 | /** 113 | * 可以看到文件夹的路径和图片的路径分开保存,极大的减少了内存的消耗; 114 | */ 115 | mAdapter = new MyAdapter(getApplicationContext(), mImgs, 116 | R.layout.grid_item, mImgDir.getAbsolutePath()); 117 | mGirdView.setAdapter(mAdapter); 118 | mImageCount.setText(totalCount + "张"); 119 | }; 120 | 121 | /** 122 | * 初始化展示文件夹的popupWindw 123 | */ 124 | private void initListDirPopupWindw() 125 | { 126 | mListImageDirPopupWindow = new ListImageDirPopupWindow( 127 | LayoutParams.MATCH_PARENT, (int) (mScreenHeight * 0.7), 128 | mImageFloders, LayoutInflater.from(getApplicationContext()) 129 | .inflate(R.layout.list_dir, null)); 130 | 131 | mListImageDirPopupWindow.setOnDismissListener(new OnDismissListener() 132 | { 133 | 134 | @Override 135 | public void onDismiss() 136 | { 137 | // 设置背景颜色变暗 138 | WindowManager.LayoutParams lp = getWindow().getAttributes(); 139 | lp.alpha = 1.0f; 140 | getWindow().setAttributes(lp); 141 | } 142 | }); 143 | // 设置选择文件夹的回调 144 | mListImageDirPopupWindow.setOnImageDirSelected(this); 145 | } 146 | 147 | @Override 148 | protected void onCreate(Bundle savedInstanceState) 149 | { 150 | super.onCreate(savedInstanceState); 151 | setContentView(R.layout.activity_main); 152 | 153 | DisplayMetrics outMetrics = new DisplayMetrics(); 154 | getWindowManager().getDefaultDisplay().getMetrics(outMetrics); 155 | mScreenHeight = outMetrics.heightPixels; 156 | 157 | initView(); 158 | getImages(); 159 | initEvent(); 160 | 161 | } 162 | 163 | /** 164 | * 利用ContentProvider扫描手机中的图片,此方法在运行在子线程中 完成图片的扫描,最终获得jpg最多的那个文件夹 165 | */ 166 | private void getImages() 167 | { 168 | if (!Environment.getExternalStorageState().equals( 169 | Environment.MEDIA_MOUNTED)) 170 | { 171 | Toast.makeText(this, "暂无外部存储", Toast.LENGTH_SHORT).show(); 172 | return; 173 | } 174 | // 显示进度条 175 | mProgressDialog = ProgressDialog.show(this, null, "正在加载..."); 176 | 177 | new Thread(new Runnable() 178 | { 179 | @Override 180 | public void run() 181 | { 182 | 183 | String firstImage = null; 184 | 185 | Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 186 | ContentResolver mContentResolver = LocalImageloaderActivity.this 187 | .getContentResolver(); 188 | 189 | // 只查询jpeg和png的图片 190 | Cursor mCursor = mContentResolver.query(mImageUri, null, 191 | MediaStore.Images.Media.MIME_TYPE + "=? or " 192 | + MediaStore.Images.Media.MIME_TYPE + "=?", 193 | new String[] { "image/jpeg", "image/png" }, 194 | MediaStore.Images.Media.DATE_MODIFIED); 195 | 196 | Log.e("TAG", mCursor.getCount() + ""); 197 | while (mCursor.moveToNext()) 198 | { 199 | // 获取图片的路径 200 | String path = mCursor.getString(mCursor 201 | .getColumnIndex(MediaStore.Images.Media.DATA)); 202 | 203 | //Log.e("TAG", path); 204 | // 拿到第一张图片的路径 205 | if (firstImage == null) 206 | firstImage = path; 207 | // 获取该图片的父路径名 208 | File parentFile = new File(path).getParentFile(); 209 | if (parentFile == null) 210 | continue; 211 | String dirPath = parentFile.getAbsolutePath(); 212 | ImageFloder imageFloder = null; 213 | // 利用一个HashSet防止多次扫描同一个文件夹(不加这个判断,图片多起来还是相当恐怖的~~) 214 | if (mDirPaths.contains(dirPath)) 215 | { 216 | continue; 217 | } else 218 | { 219 | mDirPaths.add(dirPath); 220 | // 初始化imageFloder 221 | imageFloder = new ImageFloder(); 222 | imageFloder.setDir(dirPath); 223 | imageFloder.setFirstImagePath(path); 224 | } 225 | 226 | int picSize = parentFile.list(new FilenameFilter() 227 | { 228 | @Override 229 | public boolean accept(File dir, String filename) 230 | { 231 | if (filename.endsWith(".jpg") 232 | || filename.endsWith(".png") 233 | || filename.endsWith(".jpeg")) 234 | return true; 235 | return false; 236 | } 237 | }).length; 238 | totalCount += picSize; 239 | 240 | imageFloder.setCount(picSize); 241 | mImageFloders.add(imageFloder); 242 | 243 | if (picSize > mPicsSize) 244 | { 245 | mPicsSize = picSize; 246 | mImgDir = parentFile; 247 | } 248 | } 249 | mCursor.close(); 250 | 251 | // 扫描完成,辅助的HashSet也就可以释放内存了 252 | mDirPaths = null; 253 | 254 | // 通知Handler扫描图片完成 255 | mHandler.sendEmptyMessage(0x110); 256 | 257 | } 258 | }).start(); 259 | 260 | } 261 | 262 | /** 263 | * 初始化View 264 | */ 265 | private void initView() 266 | { 267 | mGirdView = (GridView) findViewById(R.id.id_gridView); 268 | mChooseDir = (TextView) findViewById(R.id.id_choose_dir); 269 | mImageCount = (TextView) findViewById(R.id.id_total_count); 270 | 271 | mBottomLy = (RelativeLayout) findViewById(R.id.id_bottom_ly); 272 | 273 | } 274 | 275 | private void initEvent() 276 | { 277 | /** 278 | * 为底部的布局设置点击事件,弹出popupWindow 279 | */ 280 | mBottomLy.setOnClickListener(new OnClickListener() 281 | { 282 | @Override 283 | public void onClick(View v) 284 | { 285 | mListImageDirPopupWindow 286 | .setAnimationStyle(R.style.anim_popup_dir); 287 | mListImageDirPopupWindow.showAsDropDown(mBottomLy, 0, 0); 288 | 289 | // 设置背景颜色变暗 290 | WindowManager.LayoutParams lp = getWindow().getAttributes(); 291 | lp.alpha = .3f; 292 | getWindow().setAttributes(lp); 293 | } 294 | }); 295 | } 296 | 297 | @Override 298 | public void selected(ImageFloder floder) 299 | { 300 | 301 | mImgDir = new File(floder.getDir()); 302 | mImgs = Arrays.asList(mImgDir.list(new FilenameFilter() 303 | { 304 | @Override 305 | public boolean accept(File dir, String filename) 306 | { 307 | if (filename.endsWith(".jpg") || filename.endsWith(".png") 308 | || filename.endsWith(".jpeg")) 309 | return true; 310 | return false; 311 | } 312 | })); 313 | /** 314 | * 可以看到文件夹的路径和图片的路径分开保存,极大的减少了内存的消耗; 315 | */ 316 | mAdapter = new MyAdapter(getApplicationContext(), mImgs, 317 | R.layout.grid_item, mImgDir.getAbsolutePath()); 318 | mGirdView.setAdapter(mAdapter); 319 | // mAdapter.notifyDataSetChanged(); 320 | mImageCount.setText(floder.getCount() + "张"); 321 | mChooseDir.setText(floder.getName()); 322 | mListImageDirPopupWindow.dismiss(); 323 | 324 | } 325 | 326 | } 327 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/ImageLoader.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.net.Uri; 6 | import android.os.Handler; 7 | import android.os.Message; 8 | import android.support.v4.util.LruCache; 9 | import android.widget.ImageView; 10 | 11 | import com.zhy.base.imageloader.diskcache.disklrucache.DiskLruCacheHelper; 12 | 13 | import java.io.IOException; 14 | import java.util.concurrent.BlockingQueue; 15 | import java.util.concurrent.ExecutorService; 16 | import java.util.concurrent.Executors; 17 | import java.util.concurrent.LinkedBlockingQueue; 18 | 19 | /** 20 | * 图片加载类 21 | * 22 | * @author zhy 23 | */ 24 | public class ImageLoader 25 | { 26 | public static final int MSG_CACHE_HINT = 0x110; 27 | public static final int MSG_CACHE_UN_HINT = MSG_CACHE_HINT + 1; 28 | public static final int MSG_HTTP_GET_ERROR = MSG_CACHE_UN_HINT + 1; 29 | public static final int MSG_HTTP_GET_SUCCESS = MSG_HTTP_GET_ERROR + 1; 30 | public static final int MSG_LOCAL_GET_SUCCESS = MSG_HTTP_GET_SUCCESS + 1; 31 | public static final int MSG_LOCAL_GET_ERROR = MSG_LOCAL_GET_SUCCESS + 1; 32 | private static final String SCHEME_HTTP = "http"; 33 | private static final String SCHEME_HTTPS = "https"; 34 | 35 | private static ImageLoader mInstance; 36 | private Context mContext; 37 | 38 | 39 | private ExecutorService mTaskDistribute = Executors.newFixedThreadPool(1); 40 | 41 | /** 42 | * 图片缓存的核心对象 43 | */ 44 | private LruCache mLruCache; 45 | public static final String TAG = "ImageLoader"; 46 | 47 | private LocalDispatcher mLocalDispatcher; 48 | private volatile BlockingQueue mLocalQueue; 49 | 50 | private CacheDispatcher mCacheDispatcher; 51 | private volatile BlockingQueue mCacheQueue; 52 | 53 | private NetworkDispatcher mNetworkDispatcher; 54 | private volatile BlockingQueue mNetworkQueue; 55 | 56 | private DiskLruCacheHelper mDiskLruCacheHelper; 57 | 58 | 59 | private CancelableRequestDelegate mCancelableRequestDelegate = new CancelableRequestDelegate(); 60 | 61 | 62 | private int mErrorResId, mDefaultResId; 63 | private boolean mDiskCacheEnabled; 64 | private Type mType; 65 | 66 | private Handler HANDLER = new Handler() 67 | { 68 | @Override 69 | public void handleMessage(Message msg) 70 | { 71 | ImageRequest req = (ImageRequest) msg.obj; 72 | switch (msg.what) 73 | { 74 | case MSG_CACHE_UN_HINT: 75 | mNetworkQueue.add(req); 76 | break; 77 | case MSG_LOCAL_GET_ERROR: 78 | case MSG_HTTP_GET_ERROR: 79 | req.setErrorImageRes(); 80 | break; 81 | case MSG_CACHE_HINT: 82 | case MSG_LOCAL_GET_SUCCESS: 83 | if (req.setResBitmap()) 84 | { 85 | mLruCache.put(req.getCacheKey(), req.getBitmap()); 86 | } 87 | break; 88 | case MSG_HTTP_GET_SUCCESS: 89 | if (req.setResBitmap()) 90 | { 91 | mLruCache.put(req.getCacheKey(), req.getBitmap()); 92 | } 93 | break; 94 | } 95 | } 96 | }; 97 | 98 | 99 | public CancelableRequestDelegate getCancelableRequestDelegate() 100 | { 101 | return mCancelableRequestDelegate; 102 | } 103 | 104 | 105 | private ImageLoader(Context context, LruCache lrucahce, int errorResId, int defaultResId, boolean diskCacheEnabled, Type type) 106 | { 107 | mContext = context; 108 | mLruCache = lrucahce; 109 | mErrorResId = errorResId; 110 | mDefaultResId = defaultResId; 111 | mDiskCacheEnabled = diskCacheEnabled; 112 | mType = type; 113 | 114 | try 115 | { 116 | if (mDiskCacheEnabled) 117 | mDiskLruCacheHelper = new DiskLruCacheHelper(context, 50 * 1024 * 1024); 118 | } catch (IOException e) 119 | { 120 | e.printStackTrace(); 121 | } 122 | 123 | 124 | //初始化CacheDispatcher 125 | if(mType==Type.LIFO) 126 | { 127 | mCacheQueue = new LIFOLinkedBlockingDeque(); 128 | }else { 129 | mCacheQueue = new LinkedBlockingQueue(); 130 | } 131 | mCacheDispatcher = new CacheDispatcher(context, HANDLER, mCacheQueue, mDiskLruCacheHelper); 132 | //初始化NetworkDispatcher 133 | mNetworkQueue = new LinkedBlockingQueue(); 134 | mNetworkDispatcher = new NetworkDispatcher(context, HANDLER, mNetworkQueue, mDiskLruCacheHelper); 135 | 136 | //初始化LocalDispatcher 137 | //初始化CacheDispatcher 138 | if(mType==Type.LIFO) 139 | { 140 | mLocalQueue = new LIFOLinkedBlockingDeque(); 141 | }else { 142 | mLocalQueue = new LinkedBlockingQueue(); 143 | } 144 | mLocalDispatcher = new LocalDispatcher(context, HANDLER, mLocalQueue); 145 | 146 | mLocalDispatcher.start(); 147 | mCacheDispatcher.start(); 148 | mNetworkDispatcher.start(); 149 | 150 | } 151 | 152 | public static ImageLoader with(Context context) 153 | { 154 | if (mInstance == null) 155 | { 156 | synchronized (ImageLoader.class) 157 | { 158 | if (mInstance == null) 159 | { 160 | mInstance = new Builder(context).build(); 161 | } 162 | } 163 | } 164 | return mInstance; 165 | } 166 | 167 | 168 | public static class Builder 169 | { 170 | private Context context; 171 | /** 172 | * 内存缓存的大小,默认为app最大内存的1/8 173 | */ 174 | private int mMaxMemCacheSize; 175 | /** 176 | * 发生错误时显示的图片 177 | */ 178 | private int mErrorResId; 179 | /** 180 | * 默认显示的图片 181 | */ 182 | private int mDefaultResId; 183 | 184 | /** 185 | * 是否开启硬盘缓存 186 | */ 187 | private boolean mDiskCacheEnable = true; 188 | 189 | 190 | private Type mType = Type.LIFO; 191 | 192 | public Builder(Context context) 193 | { 194 | if (context == null) 195 | { 196 | throw new IllegalArgumentException("Context must not be null."); 197 | } 198 | this.context = context.getApplicationContext(); 199 | } 200 | 201 | public ImageLoader build() 202 | { 203 | Context context = this.context; 204 | LruCache defaultLruCache = createDefaultLruCache(); 205 | 206 | return new ImageLoader(context, defaultLruCache, mErrorResId, mDefaultResId, mDiskCacheEnable, mType); 207 | } 208 | 209 | public Builder memCacheSize(int memCacheSize) 210 | { 211 | mMaxMemCacheSize = memCacheSize; 212 | return this; 213 | } 214 | 215 | public Builder errorResId(int errorResId) 216 | { 217 | mErrorResId = errorResId; 218 | return this; 219 | } 220 | 221 | public Builder defaultResId(int defaultResId) 222 | { 223 | mDefaultResId = defaultResId; 224 | return this; 225 | } 226 | 227 | public Builder diskCacheEnbled(boolean cacheEnable) 228 | { 229 | mDiskCacheEnable = cacheEnable; 230 | return this; 231 | } 232 | 233 | public Builder loadType(Type type) 234 | { 235 | mType = type; 236 | return this; 237 | } 238 | 239 | 240 | private LruCache createDefaultLruCache() 241 | { 242 | int memCacheSize = mMaxMemCacheSize; 243 | int maxMemory = (int) Runtime.getRuntime().maxMemory(); 244 | memCacheSize = memCacheSize <= 0 ? maxMemory / 8 : memCacheSize; 245 | return new LruCache(memCacheSize) 246 | { 247 | @Override 248 | protected int sizeOf(String key, Bitmap value) 249 | { 250 | return value.getRowBytes() * value.getHeight(); 251 | } 252 | }; 253 | } 254 | } 255 | 256 | public static enum Type 257 | { 258 | FIFO, LIFO; 259 | } 260 | 261 | 262 | /** 263 | * 根据path为imageview设置图片 264 | * 265 | * @param path 266 | * @param imageView 267 | */ 268 | public void load(final String path, final ImageView imageView) 269 | { 270 | setDefaultImageRes(imageView); 271 | final ImageRequest req = buildImageRequest(path, imageView); 272 | final String cacheKey = req.getCacheKey(); 273 | //记录最新的imageview -> cacheKey 274 | mCancelableRequestDelegate.putRequest(imageView.hashCode(), cacheKey); 275 | Bitmap bitmap = mLruCache.get(cacheKey); 276 | if (bitmap != null) 277 | { 278 | imageView.setImageBitmap(bitmap); 279 | return; 280 | } 281 | 282 | //TODO 考虑改变分发策略,判断磁盘文件存在的方式分配任务 283 | mTaskDistribute.execute(new Runnable() 284 | { 285 | @Override 286 | public void run() 287 | { 288 | Uri uri = req.getUri(); 289 | String scheme = uri.getScheme(); 290 | if (SCHEME_HTTP.equals(scheme) || SCHEME_HTTPS.equals(scheme)) 291 | { 292 | mCacheQueue.offer(req); 293 | return; 294 | } 295 | mLocalQueue.offer(req); 296 | } 297 | }); 298 | 299 | 300 | } 301 | 302 | private void setDefaultImageRes(ImageView imageView) 303 | { 304 | if (mDefaultResId != 0) 305 | { 306 | imageView.setImageResource(mDefaultResId); 307 | } 308 | } 309 | 310 | private ImageRequest buildImageRequest(String path, ImageView imageView) 311 | { 312 | ImageRequest req = new ImageRequest(this, path, imageView, mErrorResId, mDefaultResId); 313 | return req; 314 | } 315 | 316 | 317 | } 318 | -------------------------------------------------------------------------------- /base-imageloader/src/main/java/com/zhy/base/imageloader/ImageDecorder.java: -------------------------------------------------------------------------------- 1 | package com.zhy.base.imageloader; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.ContentResolver; 5 | import android.content.Context; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.media.ThumbnailUtils; 9 | import android.net.Uri; 10 | import android.os.Build; 11 | import android.provider.ContactsContract; 12 | import android.provider.MediaStore; 13 | import android.webkit.MimeTypeMap; 14 | import android.widget.ImageView; 15 | 16 | import java.io.BufferedInputStream; 17 | import java.io.ByteArrayInputStream; 18 | import java.io.ByteArrayOutputStream; 19 | import java.io.File; 20 | import java.io.FileInputStream; 21 | import java.io.FileNotFoundException; 22 | import java.io.IOException; 23 | import java.io.InputStream; 24 | import java.net.HttpURLConnection; 25 | import java.net.URL; 26 | 27 | /** 28 | * Created by zhy on 15/8/11. 29 | */ 30 | public class ImageDecorder 31 | { 32 | public static class ImageDecorderParams 33 | { 34 | String url; 35 | ImageUtils.ImageSize actualSize; 36 | ImageUtils.ImageSize expectSize; 37 | ImageView imageView; 38 | } 39 | 40 | /** 41 | * {@value} 42 | */ 43 | public static final int DEFAULT_HTTP_CONNECT_TIMEOUT = 5 * 1000; // milliseconds 44 | /** 45 | * {@value} 46 | */ 47 | public static final int DEFAULT_HTTP_READ_TIMEOUT = 20 * 1000; // milliseconds 48 | 49 | /** 50 | * {@value} 51 | */ 52 | protected static final int BUFFER_SIZE = 32 * 1024; // 32 Kb 53 | /** 54 | * {@value} 55 | */ 56 | protected static final String ALLOWED_URI_CHARS = "@#&=*+-_.,:!?()/~'%"; 57 | 58 | protected static final int MAX_REDIRECT_COUNT = 5; 59 | 60 | protected static final String CONTENT_CONTACTS_URI_PREFIX = "content://com.android.contacts/"; 61 | 62 | private static final String ERROR_UNSUPPORTED_SCHEME = "Imageloader doesn't support scheme(protocol) by default [%s]. " + "You should implement this support yourself (ImageDecorder.getStreamFromOtherSource(...))"; 63 | 64 | protected final Context context; 65 | protected final int connectTimeout; 66 | protected final int readTimeout; 67 | 68 | public ImageDecorder(Context context) 69 | { 70 | this(context, DEFAULT_HTTP_CONNECT_TIMEOUT, DEFAULT_HTTP_READ_TIMEOUT); 71 | } 72 | 73 | public ImageDecorder(Context context, int connectTimeout, int readTimeout) 74 | { 75 | this.context = context.getApplicationContext(); 76 | this.connectTimeout = connectTimeout; 77 | this.readTimeout = readTimeout; 78 | } 79 | 80 | public Bitmap decodeByStream(InputStream imageStream, ImageDecorderParams params) throws IOException 81 | { 82 | if (imageStream == null) 83 | { 84 | return null; 85 | } 86 | //根据imageStream获得实际的宽高 87 | params.actualSize = ImageUtils.getImageSize(imageStream); 88 | //重置流,企图压缩 89 | imageStream = resetStream(imageStream, params.url); 90 | Bitmap bitmap = decodeBitmap(imageStream, params); 91 | 92 | 93 | return bitmap; 94 | } 95 | 96 | public Bitmap decode(ImageDecorderParams params) throws IOException 97 | { 98 | String imageUrl = params.url; 99 | InputStream imageStream = getImageStream(imageUrl); 100 | return decodeByStream(imageStream, params); 101 | 102 | } 103 | 104 | protected InputStream resetStream(InputStream imageStream, String url) throws IOException 105 | { 106 | if (imageStream.markSupported()) 107 | { 108 | try 109 | { 110 | imageStream.reset(); 111 | return imageStream; 112 | } catch (IOException ignored) 113 | { 114 | } 115 | } 116 | IoUtils.closeSilently(imageStream); 117 | return getImageStream(url); 118 | } 119 | 120 | private Bitmap decodeBitmap(InputStream imageStream, ImageDecorderParams params) 121 | { 122 | Bitmap bitmap = null; 123 | try 124 | { 125 | BitmapFactory.Options options = new BitmapFactory.Options(); 126 | options.inJustDecodeBounds = false; 127 | options.inSampleSize = ImageUtils.calculateInSampleSize(params.actualSize, params.expectSize); 128 | L.e("inSampleSize =" + options.inSampleSize + " ," + params.actualSize + " , " + params.expectSize + " , url = " + params.url); 129 | bitmap = BitmapFactory.decodeStream(imageStream, null, options); 130 | } finally 131 | { 132 | IoUtils.closeSilently(imageStream); 133 | } 134 | return bitmap; 135 | } 136 | 137 | 138 | public InputStream getImageStream(String imageUri) throws IOException 139 | { 140 | switch (Scheme.ofUri(imageUri)) 141 | { 142 | case HTTP: 143 | case HTTPS: 144 | return getStreamFromNetwork(imageUri); 145 | case FILE: 146 | return getStreamFromFile(imageUri); 147 | case CONTENT: 148 | return getStreamFromContent(imageUri); 149 | case ASSETS: 150 | return getStreamFromAssets(imageUri); 151 | case DRAWABLE: 152 | return getStreamFromDrawable(imageUri); 153 | case UNKNOWN: 154 | default: 155 | return getStreamFromOtherSource(imageUri); 156 | } 157 | } 158 | 159 | //Http/Https 160 | protected InputStream getStreamFromNetwork(String imageUri) throws IOException 161 | { 162 | HttpURLConnection conn = createConnection(imageUri); 163 | 164 | int redirectCount = 0; 165 | while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) 166 | { 167 | conn = createConnection(conn.getHeaderField("Location")); 168 | redirectCount++; 169 | } 170 | 171 | InputStream imageStream; 172 | try 173 | { 174 | imageStream = conn.getInputStream(); 175 | } catch (IOException e) 176 | { 177 | // Read all data to allow reuse connection (http://bit.ly/1ad35PY) 178 | IoUtils.readAndCloseStream(conn.getErrorStream()); 179 | throw e; 180 | } 181 | if (!shouldBeProcessed(conn)) 182 | { 183 | IoUtils.closeSilently(imageStream); 184 | throw new IOException("Image request failed with response code " + conn.getResponseCode()); 185 | } 186 | 187 | return new ContentLengthInputStream(new BufferedInputStream(imageStream, BUFFER_SIZE), conn.getContentLength()); 188 | } 189 | 190 | 191 | protected HttpURLConnection createConnection(String url) throws IOException 192 | { 193 | String encodedUrl = Uri.encode(url, ALLOWED_URI_CHARS); 194 | HttpURLConnection conn = (HttpURLConnection) new URL(encodedUrl).openConnection(); 195 | conn.setConnectTimeout(connectTimeout); 196 | conn.setReadTimeout(readTimeout); 197 | return conn; 198 | } 199 | 200 | protected boolean shouldBeProcessed(HttpURLConnection conn) throws IOException 201 | { 202 | return conn.getResponseCode() == 200; 203 | } 204 | 205 | //Schema.File 206 | protected InputStream getStreamFromFile(String imageUri) throws IOException 207 | { 208 | String filePath = Scheme.FILE.crop(imageUri); 209 | if (isVideoFileUri(imageUri)) 210 | { 211 | return getVideoThumbnailStream(filePath); 212 | } else 213 | { 214 | BufferedInputStream imageStream = new BufferedInputStream(new FileInputStream(filePath), BUFFER_SIZE); 215 | return new ContentLengthInputStream(imageStream, (int) new File(filePath).length()); 216 | } 217 | } 218 | 219 | private boolean isVideoFileUri(String uri) 220 | { 221 | String extension = MimeTypeMap.getFileExtensionFromUrl(uri); 222 | String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 223 | return mimeType != null && mimeType.startsWith("video/"); 224 | } 225 | 226 | 227 | @TargetApi(Build.VERSION_CODES.FROYO) 228 | private InputStream getVideoThumbnailStream(String filePath) 229 | { 230 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) 231 | { 232 | Bitmap bitmap = ThumbnailUtils 233 | .createVideoThumbnail(filePath, MediaStore.Images.Thumbnails.FULL_SCREEN_KIND); 234 | if (bitmap != null) 235 | { 236 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 237 | bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); 238 | return new ByteArrayInputStream(bos.toByteArray()); 239 | } 240 | } 241 | return null; 242 | } 243 | 244 | //---Schema.CONTENT 245 | 246 | protected InputStream getStreamFromContent(String imageUri) throws FileNotFoundException 247 | { 248 | ContentResolver res = context.getContentResolver(); 249 | 250 | Uri uri = Uri.parse(imageUri); 251 | if (isVideoContentUri(uri)) 252 | { // video thumbnail 253 | Long origId = Long.valueOf(uri.getLastPathSegment()); 254 | Bitmap bitmap = MediaStore.Video.Thumbnails 255 | .getThumbnail(res, origId, MediaStore.Images.Thumbnails.MINI_KIND, null); 256 | if (bitmap != null) 257 | { 258 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 259 | bitmap.compress(Bitmap.CompressFormat.PNG, 0, bos); 260 | return new ByteArrayInputStream(bos.toByteArray()); 261 | } 262 | } else if (imageUri.startsWith(CONTENT_CONTACTS_URI_PREFIX)) 263 | { // contacts photo 264 | return getContactPhotoStream(uri); 265 | } 266 | 267 | return res.openInputStream(uri); 268 | } 269 | 270 | private boolean isVideoContentUri(Uri uri) 271 | { 272 | String mimeType = context.getContentResolver().getType(uri); 273 | return mimeType != null && mimeType.startsWith("video/"); 274 | } 275 | 276 | 277 | @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) 278 | protected InputStream getContactPhotoStream(Uri uri) 279 | { 280 | ContentResolver res = context.getContentResolver(); 281 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) 282 | { 283 | return ContactsContract.Contacts.openContactPhotoInputStream(res, uri, true); 284 | } else 285 | { 286 | return ContactsContract.Contacts.openContactPhotoInputStream(res, uri); 287 | } 288 | } 289 | 290 | //Schema.asset 291 | protected InputStream getStreamFromAssets(String imageUri) throws IOException 292 | { 293 | String filePath = Scheme.ASSETS.crop(imageUri); 294 | return context.getAssets().open(filePath); 295 | } 296 | 297 | //Schema.drawable 298 | protected InputStream getStreamFromDrawable(String imageUri) 299 | { 300 | String drawableIdString = Scheme.DRAWABLE.crop(imageUri); 301 | int drawableId = Integer.parseInt(drawableIdString); 302 | return context.getResources().openRawResource(drawableId); 303 | } 304 | 305 | //Schema.UNKNOWN 306 | protected InputStream getStreamFromOtherSource(String imageUri) throws IOException 307 | { 308 | throw new UnsupportedOperationException(String.format(ERROR_UNSUPPORTED_SCHEME, imageUri)); 309 | } 310 | 311 | 312 | } 313 | --------------------------------------------------------------------------------