Skip to content

Commit 23c55d8

Browse files
committed
Support EasyImageGetter for http/assets img loader with tag img
1 parent a5d494c commit 23c55d8

9 files changed

Lines changed: 202 additions & 0 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
88
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
99
<uses-permission android:name="android.permission.CAMERA"/>
10+
<uses-permission android:name="android.permission.INTERNET"/>
1011

1112
<application
1213
android:name=".App"
@@ -35,6 +36,7 @@
3536
<activity android:name=".activities.EasySharedPreferencesActivity" />
3637
<activity android:name=".activities.EasyPhotoActivity"/>
3738
<activity android:name=".activities.mvp.login.LoginActivity" />
39+
<activity android:name=".activities.EasyImageGetterActivity" />
3840
</application>
3941

4042
</manifest>
73 KB
Loading

app/src/main/java/com/haoge/sample/easyandroid/DemosActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class DemosActivity : ListActivity() {
3131
Item("测试EasyBundle", EasyBundleActivity::class.java),
3232
Item("测试EasySharedPreferences", EasySharedPreferencesActivity::class.java),
3333
Item("测试EasyPhoto", EasyPhotoActivity::class.java),
34+
Item("测试EasyImageGetter", EasyImageGetterActivity::class.java),
3435
Item("测试MVPDemo", LoginActivity::class.java)
3536
)
3637

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.haoge.sample.easyandroid.activities
2+
3+
import android.os.Bundle
4+
import android.widget.TextView
5+
import com.haoge.easyandroid.easy.EasyImageGetter
6+
import com.haoge.sample.easyandroid.BaseActivity
7+
import com.haoge.sample.easyandroid.R
8+
9+
/**
10+
* @author haoge on 2018/9/26
11+
*/
12+
class EasyImageGetterActivity: BaseActivity() {
13+
14+
private val htmlLoader = EasyImageGetter.create()
15+
.setPlaceHolder(R.drawable.placeholder)
16+
.setError(R.drawable.error)
17+
private val result by lazy { findViewById<TextView>(R.id.result) }
18+
private val html = """
19+
<h5>asset图片加载示例</h5>
20+
<img src="file:///android_asset/imagegetter/cat.png">
21+
<h5>http图片加载示例</h5>
22+
<img src="http://www.w3school.com.cn/i/eg_tulip.jpg">
23+
<h5>http gif图片加载示例</h5>
24+
<img src="http://n.sinaimg.cn/tech/transform/525/w300h225/20180927/erEP-hiixpuq0285361.gif">
25+
26+
""".trimIndent()
27+
28+
override fun initPage(savedInstanceState: Bundle?) {
29+
htmlLoader.loadHtml(html, result)
30+
}
31+
32+
override fun getLayoutId() = R.layout.activity_image_getter
33+
}
15.4 KB
Loading
9.05 KB
Loading
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:orientation="vertical" android:layout_width="match_parent"
4+
android:layout_height="match_parent">
5+
6+
<TextView
7+
android:id="@+id/result"
8+
android:layout_width="match_parent"
9+
android:layout_height="match_parent" />
10+
11+
</LinearLayout>

utils/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ dependencies {
2828

2929
compileOnly 'com.alibaba:fastjson:1.2.47'
3030
compileOnly 'com.google.code.gson:gson:2.8.5'
31+
compileOnly 'com.github.bumptech.glide:glide:4.8.0'
3132
}
3233

3334
apply from: '../javadoc.gradle'
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package com.haoge.easyandroid.easy
2+
3+
import android.app.Activity
4+
import android.graphics.Canvas
5+
import android.graphics.drawable.BitmapDrawable
6+
import android.graphics.drawable.Drawable
7+
import android.os.AsyncTask
8+
import android.os.Build
9+
import android.text.Html
10+
import android.widget.TextView
11+
import com.bumptech.glide.Glide
12+
import com.haoge.easyandroid.EasyAndroid
13+
import java.lang.ref.WeakReference
14+
15+
private typealias ImageGetterLoader = (String) -> Drawable?
16+
class EasyImageGetter:Html.ImageGetter {
17+
18+
private var loader:ImageGetterLoader? = null
19+
private var placeHolder:Drawable? = null
20+
private var error:Drawable? = null
21+
private var container:TextView? = null
22+
private var tagHandler:Html.TagHandler? = null
23+
24+
/** 设置图片在加载时的占位图*/
25+
@Suppress("DEPRECATION")
26+
fun setPlaceHolder(placeHolder:Int): EasyImageGetter {
27+
this.placeHolder = EasyAndroid.getApplicationContext().resources.getDrawable(placeHolder)
28+
return this
29+
}
30+
31+
/** 设置当图片加载失败时的占位图*/
32+
@Suppress("DEPRECATION")
33+
fun setError(error:Int): EasyImageGetter {
34+
this.error = EasyAndroid.getApplicationContext().resources.getDrawable(error)
35+
return this
36+
}
37+
38+
/**
39+
* 设置额外的加载器。将src数据解析为drawable进行展示。
40+
*
41+
* 在解析过程中。若有设置此加载器,则将首先通过此加载器进行drawable创建。
42+
*
43+
* 当此加载器所返回的drawable为null时。则将触发组件本身自带的加载方式(通过glide进行加载)
44+
*/
45+
fun setLoader(loader: ImageGetterLoader): EasyImageGetter {
46+
this.loader = loader
47+
return this
48+
}
49+
50+
/** 参考[Html.TagHandler]*/
51+
fun setTagHandler(handler: Html.TagHandler): EasyImageGetter {
52+
this.tagHandler = handler
53+
return this
54+
}
55+
56+
override fun getDrawable(source: String?): Drawable {
57+
val drawable = FutureDrawable(placeHolder)
58+
InternalAsyncTask(error, drawable, loader, WeakReference<TextView>(container)).execute(source)
59+
return drawable
60+
}
61+
62+
fun loadHtml(html:String, container: TextView) {
63+
this.container = container
64+
65+
val spanned = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
66+
Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY, this, tagHandler)
67+
} else {
68+
@Suppress("DEPRECATION")
69+
Html.fromHtml(html, this, tagHandler)
70+
}
71+
72+
container.text = spanned
73+
}
74+
75+
companion object {
76+
fun create():EasyImageGetter = EasyImageGetter()
77+
78+
// 判断执行环境中是否包含有glide图片解析库
79+
private val glideSupport = exist("com.bumptech.glide.Glide")
80+
private fun exist(name:String):Boolean = try{
81+
Class.forName(name)
82+
true
83+
} catch (e:Exception) {
84+
false
85+
}
86+
}
87+
88+
class InternalAsyncTask(private val error: Drawable?,
89+
private val drawable: FutureDrawable,
90+
private val loader: ImageGetterLoader?,
91+
private var container: WeakReference<TextView>): AsyncTask<String, Int, Drawable>() {
92+
93+
override fun doInBackground(vararg params: String?): Drawable? {
94+
try {
95+
if (checkContextValid().not()) return null
96+
97+
val url = params[0]?:throw RuntimeException("URL is null")
98+
// 先使用用户设置的loader进行加载
99+
val result = loader?.invoke(url)
100+
if (result != null) return result
101+
// 当用户设置的loader加载失败时(返回null), 则使用内部机制进行drawable获取
102+
if (glideSupport.not()) throw RuntimeException("Internal loader requires glide to load drawable!")
103+
val context = container.get()?.context?:throw RuntimeException("Fetch context failed from container")
104+
return Glide.with(context).load(url).submit().get()
105+
} catch (e:Exception) {
106+
e.printStackTrace()
107+
return null
108+
}
109+
}
110+
111+
override fun onPostExecute(result: Drawable?) {
112+
if (checkContextValid().not()) return
113+
val textView = container.get()?:return
114+
115+
val real = result?:error
116+
real?.let { drawable.apply(it) }
117+
textView.invalidate()
118+
textView.text = textView.text
119+
}
120+
121+
// 从绑定的TextView中获取activity实例进行生命周期判断。避免页面销毁后还占用大量资源去进行load
122+
private fun checkContextValid():Boolean {
123+
val activity = (container.get()?.context?:return false) as? Activity ?: return false
124+
return !(activity.isFinishing || (Build.VERSION.SDK_INT >= 17 && activity.isDestroyed))
125+
}
126+
}
127+
128+
// 用于进行异步加载Drawable时的占位Drawable:
129+
@Suppress("DEPRECATION")
130+
class FutureDrawable(private val placeholder:Drawable?): BitmapDrawable() {
131+
132+
private var drawable:Drawable? = null
133+
134+
private fun setBounds(drawable:Drawable) {
135+
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
136+
setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
137+
}
138+
139+
fun apply(drawable: Drawable) {
140+
this.drawable = drawable
141+
setBounds(drawable)
142+
}
143+
144+
override fun draw(canvas: Canvas?) {
145+
val real = drawable?:placeholder
146+
real?.draw(canvas)
147+
}
148+
149+
init {
150+
placeholder?.let { setBounds(it) }
151+
}
152+
}
153+
}
154+

0 commit comments

Comments
 (0)