8

Custom xml file to view

This is an error produced from the above question

I managed to get the XML file saved into the assets folder, and loaded (and I can even navigate through the different parts of the parser and produce outputs from them) but when I try to pass the XmlPullParser to LayoutInflater I get the above error. I am not totally sure why it is happening though.

Below is the activity that I am using (the part of it that involves parsing the Xml file) as well as the xml file (called activity_main.sv) and the logcat.

Ignore the file extension of the xml file. I simply renamed it because the IDE was having fits about inclusion. If the xml file is saved in the res/layouts folder it works just fine (I know because I copied it directly out of the res/layouts folder).

public void onCreate(Bundle savedInstanceState){
...
     try {
          XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
          XmlPullParser parser = factory.newPullParser();
          InputStream in = getResources().getAssets().open("views/activity_main.sv");
          parser.setInput(new InputStreamReader(in));
          LayoutInflater inflate = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//        The below line is line 73, the line which is giving me issue
          View view = inflate.inflate(parser, null);
          setContentView(view);
     }catch(Exception e){
          e.printStackTrace();
//        Consider the below line Log.d("TAG","Well fuck me it didnt work"). AppLog is a custom class I created to help manage logging.
          AppLog.log("Well fuck me it didnt work");
     }
}

And my basic relativelayout saved as "activity_main.sv"

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <TextView android:text="@string/hello_world" android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

And finally the logcat output

10-24 19:36:55.273: W/EGL_emulation(4724): eglSurfaceAttrib not implemented
10-24 19:36:55.273: W/OpenGLRenderer(4724): Failed to set EGL_SWAP_BEHAVIOR on surface 0xa34192a0, error=EGL_SUCCESS
10-24 19:47:15.252: W/System.err(8074): java.lang.ClassCastException: android.util.XmlPullAttributes cannot be cast to 

android.content.res.XmlBlock$Parser
10-24 19:47:15.253: W/System.err(8074):     at android.content.res.Resources$Theme.obtainStyledAttributes

(Resources.java:1483)
10-24 19:47:15.253: W/System.err(8074):     at android.content.Context.obtainStyledAttributes(Context.java:460)
10-24 19:47:15.253: W/System.err(8074):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:708)
10-24 19:47:15.253: W/System.err(8074):     at android.view.LayoutInflater.inflate(LayoutInflater.java:482)
10-24 19:47:15.253: W/System.err(8074):     at android.view.LayoutInflater.inflate(LayoutInflater.java:385)
10-24 19:47:15.253: W/System.err(8074):     at pro.bladebeat.intentplayground.MainActivity.onCreate

(MainActivity.java:73)
10-24 19:47:15.253: W/System.err(8074):     at android.app.Activity.performCreate(Activity.java:5933)
10-24 19:47:15.253: W/System.err(8074):     at android.app.Instrumentation.callActivityOnCreate

(Instrumentation.java:1105)
10-24 19:47:15.253: W/System.err(8074):     at android.app.ActivityThread.performLaunchActivity

(ActivityThread.java:2251)
10-24 19:47:15.253: W/System.err(8074):     at android.app.ActivityThread.handleLaunchActivity

(ActivityThread.java:2360)
10-24 19:47:15.253: W/System.err(8074):     at android.app.ActivityThread.access$800(ActivityThread.java:144)
10-24 19:47:15.253: W/System.err(8074):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
10-24 19:47:15.253: W/System.err(8074):     at android.os.Handler.dispatchMessage(Handler.java:102)
10-24 19:47:15.253: W/System.err(8074):     at android.os.Looper.loop(Looper.java:135)
10-24 19:47:15.253: W/System.err(8074):     at android.app.ActivityThread.main(ActivityThread.java:5221)
10-24 19:47:15.253: W/System.err(8074):     at java.lang.reflect.Method.invoke(Native Method)
10-24 19:47:15.253: W/System.err(8074):     at java.lang.reflect.Method.invoke(Method.java:372)
10-24 19:47:15.253: W/System.err(8074):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run

(ZygoteInit.java:899)
10-24 19:47:15.253: W/System.err(8074):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
10-24 19:47:15.257: D/AppLog(8074): Well fuck me it didnt work

EDIT After adding the factory.setValidating(true) statement. I have a different error now.

11-04 14:59:52.682: W/System.err(4664): org.xmlpull.v1.XmlPullParserException: unsupported feature: http://xmlpull.org/v1/doc/features.html#validation (position:START_DOCUMENT null@1:1) 
11-04 14:59:52.684: W/System.err(4664):     at org.kxml2.io.KXmlParser.setFeature(KXmlParser.java:2100)
11-04 14:59:52.684: W/System.err(4664):     at org.xmlpull.v1.XmlPullParserFactory.newPullParser(XmlPullParserFactory.java:135)
11-04 14:59:52.684: W/System.err(4664):     at pro.bladebeat.intentplayground.MainActivity.onCreate(MainActivity.java:36)
11-04 14:59:52.684: W/System.err(4664):     at android.app.Activity.performCreate(Activity.java:5933)
11-04 14:59:52.684: W/System.err(4664):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
11-04 14:59:52.684: W/System.err(4664):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
11-04 14:59:52.684: W/System.err(4664):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
11-04 14:59:52.684: W/System.err(4664):     at android.app.ActivityThread.access$800(ActivityThread.java:144)
11-04 14:59:52.684: W/System.err(4664):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
11-04 14:59:52.684: W/System.err(4664):     at android.os.Handler.dispatchMessage(Handler.java:102)
11-04 14:59:52.684: W/System.err(4664):     at android.os.Looper.loop(Looper.java:135)
11-04 14:59:52.684: W/System.err(4664):     at android.app.ActivityThread.main(ActivityThread.java:5221)
11-04 14:59:52.684: W/System.err(4664):     at java.lang.reflect.Method.invoke(Native Method)
11-04 14:59:52.684: W/System.err(4664):     at java.lang.reflect.Method.invoke(Method.java:372)
11-04 14:59:52.684: W/System.err(4664):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
11-04 14:59:52.684: W/System.err(4664):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Community
  • 1
  • 1
miversen33
  • 573
  • 5
  • 19
  • An idea: I got a solution from someone about doing a similar thing: load a binary XML to form VectorDrawable, and the same issue you wrote exists there. The solution there is to use reflection. Maybe it could help you too : https://stackoverflow.com/a/59023594/878126 – android developer Nov 30 '19 at 09:18

3 Answers3

6

(I know it is an old question but I want to give an answer for those who want to use this method or faced with the problem recently.)

Based on the source code, XmlBlock is a package-private class, and so is the XmlBlock.Parser. If you use this method with an XML got from method Resources.getXml(id) it will work without any problem because getXml ends up calling a function that creates an XmlBlock.Parser with its special algorithm designed for the application's internal resources. So I don't think we can get it worked (XmlResourceParser or anything like that cannot be cast to XmlBlock.Parser).

momvart
  • 1,737
  • 1
  • 20
  • 32
  • So what is your suggestion exactly? – android developer Nov 30 '19 at 09:14
  • You cannot use the default layout inflater of android, but you can have your custom implementation (it would be a bit sophisticated!). More detail: The problem is caused when inflater wants to obtain styled attributes. After compilation they are somehow coded for optimization and the parser doesn't work with their names. If you provided an equivalent method to that, you would be able to parse your xml. I would suggest you take a look at [this comment](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/content/res/ResourcesImpl.java#1397) in the source code. – momvart Nov 30 '19 at 10:11
  • But somehow Google has intercepted how inflation works by replacing TextView with the app-compat version of it, for example. How does this work? – android developer Nov 30 '19 at 23:00
  • 1
    @androiddeveloper I said the problem is obtaining styles, not the view's name. It's been made possible by [`LayoutInflater.Factory`](https://developer.android.com/reference/android/view/LayoutInflater.Factory2.html) which creates a view by its tag name. Also take a look at: [`AppcompatViewInflater`](https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/appcompat/appcompat/src/main/java/androidx/appcompat/app/AppCompatViewInflater.java) – momvart Dec 02 '19 at 12:05
  • I see. Thank you – android developer Dec 02 '19 at 15:49
5

Doc LayoutInflate

look this:

Important For performance reasons, view inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use LayoutInflater with an XmlPullParser over a plain XML file at runtime.

Santi
  • 130
  • 1
  • 6
  • I know this has been the accepted answer. But do you have any background on how that would work? I assume i can manually parse each view but that would be a massive pain, not knowing what is going on. Do you have any links to the background of how that is supposed to work? – miversen33 Nov 07 '15 at 02:01
-1

put after factory

factory.setValidating(true);
Santi
  • 130
  • 1
  • 6
  • I am at work right now but I'll give it a shot when I get home. I swear though if it's that simple of a line I'll fresh out – miversen33 Nov 04 '15 at 16:47
  • I edited the code and added the line factory.setValidating(true). I have gotten a new error now. I added the new error in my post – miversen33 Nov 04 '15 at 20:04
  • 1
    Sorry, after looking at the documentation, I found this: [link](http://developer.android.com/reference/android/view/LayoutInflater.html#inflate(org.xmlpull.v1.XmlPullParser, android.view.ViewGroup)) Important For performance reasons, view inflation relies heavily on pre-processing of XML files that is done at build time. Therefore, it is not currently possible to use LayoutInflater with an XmlPullParser over a plain XML file at runtime. – Santi Nov 05 '15 at 17:14
  • 1
    Well aint that some shit. They have the code to do it but you cant use it. Well thanks for the food for thought. If you post that as an answer I guess i'll have to accept it. – miversen33 Nov 05 '15 at 20:06