在写到注册功能时,需要从后台获取图形验证码图片并进行展示,但这个很简单的问题却难了我一周。
从后台拿到的是二进制图片流。因为不懂原理,所以去网上虾78百度了很多二进制转图片的方法。
像这个:
fun image2byte(path: String?, inStream: InputStream?): ByteArray? {
var data: ByteArray? = null
try {
val imageFile = path?.let { File(it) }
val output = ByteArrayOutputStream()
val buf = ByteArray(1024)
var numBytesRead = 0
while (inStream?.read(buf).also {
if (it != null) {
numBytesRead = it
}
} != -1) {
output.write(buf, 0, numBytesRead)
}
data = output.toByteArray()
output.close()
inStream?.close()
} catch (ex1: FileNotFoundException) {
ex1.printStackTrace()
} catch (ex1: IOException) {
ex1.printStackTrace()
}
return data
}
这个:
//根据指定的二进制流字符串保存文件并返回保存路径
fun saveFileByBinary(str: String?, attName: String, context: Context?): String? {
/***加载附件*/ //获取存储卡路径、构成保存文件的目标路径
var dirName = "" //SD卡具有读写权限、指定附件存储路径为SD卡上指定的文件夹
dirName = Environment.getExternalStorageDirectory().toString() + "/MyDownload/"
val f = File(dirName)
if (!f.exists()) { //判断文件夹是否存在
f.mkdir() //如果不存在、则创建一个新的文件夹
} //准备拼接新的文件名
var fileName = ""
fileName = attName
fileName = dirName + fileName
val file = File(fileName)
if (file.exists()) { //如果目标文件已经存在
file.delete() //则删除旧文件
}
val byteFile: ByteArray? = null
try {
val `is`: InputStream = ByteArrayInputStream(byteFile)
val os = FileOutputStream(file)
val b = ByteArray(1024)
var len = 0 //开始读取
while (`is`.read(b).also { len = it } != -1) {
os.write(b, 0, len)
} //完毕关闭所有连接
`is`.close()
os.close()
} catch (e: FileNotFoundException) {
e.printStackTrace()
} catch (e: IOException) {
e.printStackTrace()
}
return fileName
}
还有这个:
/**
* @param args
* 二进制数据流反编译示例
*/
@Throws(Exception::class)
@JvmStatic
fun main(args: Array<String>) {
// new一个URL对象
val url = URL(
"http://www.cxhke.com:88/upload/20123200000074522010/1509697245327.jpg"
)
// 打开链接
val conn = url.openConnection() as HttpURLConnection
// 设置请求方式为"GET"
conn.requestMethod = "GET"
// 超时响应时间为5秒
conn.connectTimeout = 5 * 1000
// 通过输入流获取图片数据
val inStream = conn.inputStream
// 得到图片的二进制数据,以二进制封装得到数据,具有通用性
val data = readInputStream(inStream)
// new一个文件对象用来保存图片,默认保存当前工程根目录
val imageFile = File("D:\\BeautyGirl123.png")
// 创建输出流
val outStream = FileOutputStream(imageFile)
// 写入数据
outStream.write(data)
// 关闭输出流
outStream.close()
}
@Throws(Exception::class)
fun readInputStream(inStream: InputStream): ByteArray {
val outStream = ByteArrayOutputStream()
// 创建一个Buffer字符串
val buffer = ByteArray(1024)
// 每次读取的字符串长度,如果为-1,代表全部读取完毕
var len = 0
// 使用一个输入流从buffer里把数据读取出来
while (inStream.read(buffer).also { len = it } != -1) {
// 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer, 0, len)
}
// 关闭输入流
inStream.close()
// 把outStream里的数据写入内存
return outStream.toByteArray()
}
但是这些都不是我需要的。
基于图片有多种格式,所以我们需要弄清楚我们要通过何种方式转换成图片。在这里用得是bitmap格式。bitmap和byte[]之间有一个转化方法。我的了解方式源自:这里。
在过往我们都会在界面中展示图片,常用的方法要么是App内的图片直接读取,要么是图片的字符串地址、用loadImage方法读取(Glide工具我也就放在这里算通过地址加载图片)。但这里应该用bitmap方法,先将字节流转化为字节数组byte[],再将字节数组转换为bitmap格式。这个时候就可以直接将bitmap格式的图片直接展示在控件上了。
这是我的最终实现:
val ivImage = dialog!!.findViewById<ImageView>(R.id.iv_image)
val tvAgain = dialog!!.findViewById<TextView>(R.id.tv_again)
tvAgain.clickWithTrigger {
val params = CaptchaParams("")
ApiManger.getApiService().getcaptcha(params).compose(RxUtil.normalSchedulers())
.subscribe(object : Observer<ResponseBody> {
override fun onCompleted() {
ToastUtils.showShort("获取成功")
}
override fun onError(e: Throwable?) {
ToastUtils.showShort("onError")
}
override fun onNext(t: ResponseBody?) {
val source= t?.bytes()
LogX.i(TAG, "二进制数组为${source}")
val bitmap: Bitmap = BitmapFactory.decodeByteArray(source, 0, source!!.size)
ivImage.setImageBitmap(bitmap)
}
})
}
仅仅三行代码,就解决了这个为难了我一周的问题。
o(╥﹏╥)o