Androiid 如何动态加载assets目录下的xml布局文件(包括Drawable xml)

来源:互联网 发布:网络改造设备 编辑:程序博客网 时间:2024/05/22 14:15

目录:

    • Androiid 如何动态加载assets目录下的xml布局文件包括Drawable xml
    • - 如何动态加载布局
    • - 加载assets目录下的xml布局
    • - 加载Drawable xml
    • - 补充说明

Androiid 如何动态加载assets目录下的xml布局文件(包括Drawable xml)

博主是做sdk的,老大有个需求就是把一些资源文件都放到assets目录下一起打进jar包.查阅了一些相关博客,感觉都不全面,我就把我遇到的问题总结一下,希望朋友们以后遇到相同的问题能更好的处理.

- 如何动态加载布局

我们都用过LayoutInflater.infsater去添加一个布局方法如下:
LayoutInflater inflater = (LayoutInflater) mContext          .getSystemService(Context.LAYOUT_INFLATER_SERVICE);      v = inflater.inflate(R.layout.number_auto_roll, null);  

我们查看inflater的源码会发现(比较懒,就直接把源码粘出来了,想看源码分析的自己Google)

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {        synchronized (mConstructorArgs) {            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");            final Context inflaterContext = mContext;            final AttributeSet attrs = Xml.asAttributeSet(parser);            Context lastContext = (Context) mConstructorArgs[0];            mConstructorArgs[0] = inflaterContext;            View result = root;            try {                // Look for the root node.                int type;                while ((type = parser.next()) != XmlPullParser.START_TAG &&                        type != XmlPullParser.END_DOCUMENT) {                    // Empty                }                if (type != XmlPullParser.START_TAG) {                    throw new InflateException(parser.getPositionDescription()                            + ": No start tag found!");                }                final String name = parser.getName();                if (DEBUG) {                    System.out.println("**************************");                    System.out.println("Creating root view: "                            + name);                    System.out.println("**************************");                }                if (TAG_MERGE.equals(name)) {                    if (root == null || !attachToRoot) {                        throw new InflateException("<merge /> can be used only with a valid "                                + "ViewGroup root and attachToRoot=true");                    }                    rInflate(parser, root, inflaterContext, attrs, false);                } else {                    // Temp is the root view that was found in the xml                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);                    ViewGroup.LayoutParams params = null;                    if (root != null) {                        if (DEBUG) {                            System.out.println("Creating params from root: " +                                    root);                        }                        // Create layout params that match root, if supplied                        params = root.generateLayoutParams(attrs);                        if (!attachToRoot) {                            // Set the layout params for temp if we are not                            // attaching. (If we are, we use addView, below)                            temp.setLayoutParams(params);                        }                    }                    if (DEBUG) {                        System.out.println("-----> start inflating children");                    }                    // Inflate all children under temp against its context.                    rInflateChildren(parser, temp, attrs, true);                    if (DEBUG) {                        System.out.println("-----> done inflating children");                    }                    // We are supposed to attach all the views we found (int temp)                    // to root. Do that now.                    if (root != null && attachToRoot) {                        root.addView(temp, params);                    }                    // Decide whether to return the root that was passed in or the                    // top view found in xml.                    if (root == null || !attachToRoot) {                        result = temp;                    }                }            } catch (XmlPullParserException e) {                final InflateException ie = new InflateException(e.getMessage(), e);                ie.setStackTrace(EMPTY_STACK_TRACE);                throw ie;            } catch (Exception e) {                final InflateException ie = new InflateException(parser.getPositionDescription()                        + ": " + e.getMessage(), e);                ie.setStackTrace(EMPTY_STACK_TRACE);                throw ie;            } finally {                // Don't retain static reference on context.                mConstructorArgs[0] = lastContext;                mConstructorArgs[1] = null;                Trace.traceEnd(Trace.TRACE_TAG_VIEW);            }            return result;        }

inflater的4种重载的方法都是调用下面的方法来填充布局的.

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

那么看到第一个参数是XmlPullParser,那么我们是不是可以从XmlPullParser入手呢,那么怎么获得XmlPullParser呢?请往下看…..

- 加载assets目录下的xml布局

这个大家一个都知道,网上一收一大堆,我就不赘述了直接上代码
第一种方法:

private XmlPullParser getLayoutXmlPullParser() throws IOException {        XmlPullParser xmlPullParser = null;        AssetManager assetManager = mContext.getAssets();        InputStream open = assetManager.open("assets/gif_test_view.xml");        xmlPullParser = Xml.newPullParser();        try {            xmlPullParser.setInput(open,"UTF-8");            ........            解析的代码        } catch (XmlPullParserException e) {            e.printStackTrace();        }        return xmlPullParser;    }

这种方法是解析普通xml文件的方法,这个只是适合我们手动解析xml文件的方法,并不能用于inflate中.

第二种方法:

private XmlPullParser getLayoutXmlPullParser() {        XmlPullParser xmlPullParser = null;        AssetManager assetManager = mContext.getAssets();        try {            xmlPullParser = assetManager.openXmlResourceParser("assets/gif_test_view.xml");        } catch (IOException e) {            e.printStackTrace();        }        return xmlPullParser;    }

这才是正确的打开方式,但是这个方法读取的xml文件必须是编译后的,关于如何获取编译后的xml文件我们后面说
需要注意的是其中fileName必须包含assets/路径
下面就通过inflate方法得到我们想要的view布局了

protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        mContext = this;        XmlPullParser paser = getLayoutXmlPullParser();        ViewGroup view = new LinearLayout(this);        mView = LayoutInflater.from(this).inflate(paser, view);        setContentView(view);        }

我这里在在inflater的时候有传人一个ViewGroup,如果传人null会报错,我当时也没去深究.

- 加载Drawable xml

有的时候我们需要用xml布局去创建一个图片,比如shape,selector,我们是不是也可以放在assets目录下.当然可以.
我们有了上面的启发,我们先去看看Drawable是怎么创建的
这里写图片描述
是不是看到我们想要的东西了,而且看到了我们熟悉的身影xmlPullParser,话不多说看到代码
方法一:
得到xmlPullParser,创建Drawable.(这里的xml文件是编译后的)

 private XmlPullParser getDrawableXmlPullParser() {        XmlPullParser xmlPullParser = null;        AssetManager assetManager = this.getAssets();        try {            xmlPullParser = assetManager.openXmlResourceParser("assets/image.xml");        } catch (IOException e) {            e.printStackTrace();        }        return xmlPullParser;    }

方法二:
得到InputStream创建Drawable(这里的xml可以是编译的也可以是不是编译的)

public InputStream getDrawableXmlInputStrem() {        InputStream inputStream = null;        AssetManager assetManager = this.getAssets();        try {            inputStream = assetManager.open("assets/image1.xml");        } catch (IOException e) {            e.printStackTrace();        }        return inputStream;    }

创建的代码:

        XmlPullParser parser = getDrawableXmlPullParser();        InputStream is = getDrawableXmlInputStrem();        try {            Drawable drawable = Drawable.createFromXml(getResources(),parser);            Drawable drawable1 = Drawable.createFromStream(is,null);            bt.setBackground(drawable);            bt1.setBackground(drawable1);        } catch (XmlPullParserException e) {            e.printStackTrace();        } catch (IOException e) {            e.printStackTrace();        }

看到这里基本上都知道怎么动态加载assets目录下的资源文件了,但是还有些东西要和大家补充说明一下

- 补充说明

如何得到编译后的xml布局文件:
1.把写好的布局文件放到一个app工程的res/layout里
2.运行这个app,android studio会生成一个debug.apk
这里写图片描述
3.把这个apk改成zip格式解压,然后找到res/layout文件夹找到我们编译后的布局文件拷到assets目录下
这就是我得到编译后xml的方法,是不是很low,好吧,我承认我很low
加载后的布局文件怎么获取控件
上面我们完成加载布局的功能了,那么问题来了,我布局已经加载完成了,如果我布局里有个Button或者imageview,我怎么设置button的点击事件,有怎么去更改我们的imageview的图片呢?
这里写图片描述
你会发现你用findViewById是找不到的,因为你的res/layout里根本没有布局,更不会有这个ID.
然后我发现了这个
这里写图片描述
既然id找不到,那肯定还有别的东西能找到,然后就看到了findViewWithTag的使用.
1.在布局中使用id的地方用tag代替
这里写图片描述
2.这个tag属性只要我们自己知道就可以了,然后就可以在代码中调用了

 final GifImageView gif1 = (GifImageView) mView.findViewWithTag("Gif1");        GifImageView gif2 = (GifImageView) mView.findViewWithTag("Gif2");        GifImageView gif3 = (GifImageView) mView.findViewWithTag("Gif3");

好了到这里一切都结束了,因为我是新手难免有错误,希望有错误的地方大家积极指出谢谢
另:本人是一个android开发的小学生,也是第一次写博客,有不足的地方希望大家多多指出,然后我也跟在大神的后面多多进步.

阅读全文
3 1