关于从服务器下载XML布局字符串后使用LayoutInflater加载的疑问
嘿,我来帮你把这个问题掰扯清楚~
首先先解释下你看到的那段文档是什么意思:Android的LayoutInflater本质上是和系统的编译后资源体系绑定的——它默认期望的XmlPullParser是从R.layout.xxx这类编译资源里来的,这些资源在APP打包时已经被处理过,和APP的资源ID、主题样式等信息绑定在一起。而普通的XML文件(或者你从服务器下载的XML字符串)没有经过这个编译流程,所以直接用默认的方式让LayoutInflater去解析,它会找不到对应的资源上下文,自然就报错了。
那回到你的问题:用一个“dummy” XML文件获取的XmlPullParser,能不能用来加载你的XML字符串?答案是不行。因为那个dummy的PullParser已经和它对应的编译资源绑定死了,它的解析状态、命名空间、资源解析逻辑都是基于那个dummy XML的,你没法把自己的XML字符串塞进去复用它,强行操作只会导致解析异常。
不过别担心,我们有更直接的解决方案,不需要绕dummy这个弯:
正确的实现方式:手动创建XmlPullParser解析服务器XML字符串
你可以自己创建一个XmlPullParser来解析从服务器下载的XML字符串,然后直接传给LayoutInflater的inflate方法,步骤如下:
将XML字符串转换成PullParser的输入源
用StringReader把你的XML字符串包装起来,然后创建并配置XmlPullParser:// 假设这是你从服务器下载的XML布局字符串 String serverXml = "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" + " android:layout_width=\"match_parent\"\n" + " android:layout_height=\"wrap_content\"\n" + " android:orientation=\"vertical\">\n" + " <TextView\n" + " android:layout_width=\"match_parent\"\n" + " android:layout_height=\"wrap_content\"\n" + " android:text=\"从服务器加载的布局\"/>\n" + "</LinearLayout>"; // 创建XmlPullParser并设置输入 XmlPullParser parser = Xml.newPullParser(); try { parser.setInput(new StringReader(serverXml)); } catch (XmlPullParserException e) { e.printStackTrace(); }用LayoutInflater加载这个PullParser
直接调用LayoutInflater的inflate方法,传入我们创建的PullParser即可:// parentView是你要把这个布局附加到的父容器(可以为null) View loadedView = getLayoutInflater().inflate(parser, parentView, false); // 之后就可以把loadedView添加到你的界面中了 parentView.addView(loadedView);
需要注意的坑点
- 资源引用问题:如果你的服务器XML里包含
android:id="@+id/xxx"或者引用了本地的资源(比如@drawable/xxx、@style/xxx),LayoutInflater会尝试从当前APP的资源中查找这些内容,如果找不到就会抛出异常。解决办法:- 要么确保服务器XML里的资源引用在本地APP中都存在;
- 要么把XML里的
android:id换成android:tag,之后通过findViewWithTag来获取View; - 或者自己实现一个自定义的
Resources来处理远程资源,但这个复杂度较高,一般不推荐。
- 命名空间:一定要确保服务器返回的XML里包含Android的命名空间
xmlns:android="http://schemas.android.com/apk/res/android",否则LayoutInflater无法识别Android的标准属性。
内容的提问来源于stack exchange,提问作者Jim

