我正在尝试在我的Android应用中使用VectorDrawables
我想从文件系统加载一个xml文件,并获得一个android.graphics.Drawable
的实例,以便在ImageView
中显示它。如果我将xml文件添加到Resources目录,它可以工作。但是当我尝试从文件系统加载它时,我总是得到一个NullPointer。
我目前正在尝试通过加载文件
Drawable.createFromPath(*Path to File*)
或VectorDrawable.createFromPath(*Path to File*)
,但我不断获得NullPointer。
文件存在且是一个有效的xml文件(见下文)。
在adb日志中,我总是得到:
SkImageDecoder::Factory returned null
当我使用mContext.getFilesDir()
时,Path看起来像
/data/data/*packagename*/files/*filename*.xml
我还尝试了一些像“下载”这样的公共文件夹。当我使用File.io Api检查文件时exists()
,canRead()
和canWrite()
更新这是取自Android Dev Pages
的XML代码 <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600" >
<group
android:name="rotationGroup"
android:pivotX="300.0"
android:pivotY="300.0"
android:rotation="45.0" >
<path
android:name="v"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
</group>
答案 0 :(得分:4)
实际上,是的,你可以,而且我已经在我自己的项目中完成了它。
正如前面的答案中所提到的,你确实需要XML drawable的编译版本,而不是你从Android Studio获得的版本。 AFAIK,VectorDrawable API尚不支持从原始XML加载。
要执行此操作,只需将图片暂时放在res
目录下,以便在构建过程中将其编译为普通资源,然后找到生成的APK并从中提取它们(您会注意到)他们不再是文本文件,而是二进制文件)。现在将它们再次放在您的资产目录下的任何位置,并使用与此类似的代码将它们作为drawables加载:
XmlResourceParser parser = context.getAssets()
.openXmlResourceParser("assets/folder/image.xml");
drawable = VectorDrawableCompat.createFromXml(context.getResources(), parser);
注意&#39; assets /&#39;路径的一部分。这是必须的,afaik。
答案 1 :(得分:3)
不幸的是,没有。除非您以编译资源的方式以某种方式编译XML源文件。 VectorDrawable
目前假定已编译的图像源。
否则你可能写了这样的东西:
VectorDrawable d = new VectorDrawable();
try( InputStream in = new FileInputStream( *Path to File* ); )
{
XmlPullParser p = Xml.newPullParser();
p.setInput( in, /*encoding, self detect*/null );
d.inflate( getResources(), p, Xml.asAttributeSet(p) ); // FAILS
}
目前失败(API级别23,Marshmallow 6.0),因为inflate调用尝试将属性集强制转换为XmlBlock.Parser
,这会抛出ClassCastException
。原因记录在source;它将“仅适用于已编译的XML文件”,例如aapt
工具打包的资源。
答案 2 :(得分:0)
是的,有可能但可悲的是,根据某人给我看的东西,它有很多缺点:
话虽这么说,也许您可以通过查看其他库的代码来创建自己的XmlPullParser,例如here(或我的叉子,here)。有趣的类名是“ BinaryXmlParser”,我认为这可能会有所帮助。我尝试使用其他方法,但是导致了java.lang.ClassCastException: android.util.XmlPullAttributes cannot be cast to android.content.res.XmlBlock$Parser
的异常,所以也许它只想使用反射的XmlBlock类,这意味着即使您实现了它,我也很可能不会工作。
以下是代码(基于here):
object VectorDrawableParser {
/**
* Create a vector drawable from a binary XML byte array.
*
* @param context Any context.
* @param binXml Byte array containing the binary XML.
* @return The vector drawable or null it couldn't be created.
*/
@SuppressLint("PrivateApi", "DiscouragedPrivateApi")
fun getVectorDrawable(context: Context, binXml: ByteArray): Drawable? {
try {
// Get the binary XML parser (XmlBlock.Parser) and use it to create the drawable
// This is the equivalent of what AssetManager#getXml() does
val xmlBlock = Class.forName("android.content.res.XmlBlock")
val xmlBlockConstr = xmlBlock.getConstructor(ByteArray::class.java)
val xmlParserNew = xmlBlock.getDeclaredMethod("newParser")
xmlBlockConstr.isAccessible = true
xmlParserNew.isAccessible = true
val parser = xmlParserNew.invoke(xmlBlockConstr.newInstance(binXml)) as XmlPullParser
return if (Build.VERSION.SDK_INT >= 24) {
Drawable.createFromXml(context.resources, parser)
} else {
// Before API 24, vector drawables aren't rendered correctly without compat lib
val attrs = Xml.asAttributeSet(parser)
var type = parser.next()
while (type != XmlPullParser.START_TAG) {
type = parser.next()
}
VectorDrawableCompat.createFromXmlInner(context.resources, parser, attrs, null)
}
} catch (e: Exception) {
e.printStackTrace()
}
return null
}
}
以及使用方法:
val filePath = "/storage/emulated/0/abc_vector_test.xml"
val readBytes = FileInputStream(File(filePath)).readBytes()
val vectorDrawable = VectorDrawableParser.getVectorDrawable(this, readBytes)
Log.d("AppLog", "got it?${vectorDrawable != null}")