How to create an AttributeSet in Android?

MyProg picture MyProg · May 11, 2014 · Viewed 12.4k times · Source

I am trying to write some code in Android to set parameters in an AttributeSet from attrs.xml file. But I am getting a "Resource not Found" error.

Java Code

MainActivity.java

package com.example.mycompoundbutton;

import org.xmlpull.v1.XmlPullParser;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.Xml;
import android.app.Activity;
import android.content.res.Resources;


public class MainActivity extends Activity 
{

@Override
protected void onCreate(Bundle savedInstanceState) 
{

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

    Resources res = this.getResources();

    XmlPullParser parser = res.getXml(R.attr.xyz);

    AttributeSet attrs = Xml.asAttributeSet(parser);

    MyCompound my = new MyCompound(this,attrs);

    my.MyTestFun(300,500);

}
}

MyCompound.java

package com.example.mycompoundbutton;


import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.CompoundButton;

public class MyCompound extends CompoundButton
{

public MyCompound(Context context, AttributeSet attrs) 
{

        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.MyCustomView, R.attr.xyz, 0);

        a.recycle();

}

public void MyTestFun(int x,int y)
{

     // Some Code to Execute


}}

attrs.xml

<resources>
<declare-styleable name="MyCustomView">

    <attr name="abc" format="integer"/>            
    <attr name="pqr" format="integer" />

</declare-styleable>

<attr name="xyz" format="integer"/>

</resources>

Error :

05-11 07:29:27.345: E/AndroidRuntime(1919): FATAL EXCEPTION: main
05-11 07:29:27.345: E/AndroidRuntime(1919): java.lang.RuntimeException: Unable to start activity         ComponentInfo{com.example.mycompoundbutton/com.example.mycompoundbutton.MainActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x7f010000
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.ActivityThread.access$600(ActivityThread.java:141)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.os.Handler.dispatchMessage(Handler.java:99)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.os.Looper.loop(Looper.java:137)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.ActivityThread.main(ActivityThread.java:5103)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at java.lang.reflect.Method.invokeNative(Native Method)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at java.lang.reflect.Method.invoke(Method.java:525)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at dalvik.system.NativeStart.main(Native Method)
05-11 07:29:27.345: E/AndroidRuntime(1919): Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x7f010000
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.content.res.Resources.getValue(Resources.java:1118)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.content.res.Resources.loadXmlResourceParser(Resources.java:2304)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.content.res.Resources.getXml(Resources.java:983)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at com.example.mycompoundbutton.MainActivity.onCreate(MainActivity.java:24)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.Activity.performCreate(Activity.java:5133)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
05-11 07:29:27.345: E/AndroidRuntime(1919):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
05-11 07:29:27.345: E/AndroidRuntime(1919):     ... 11 more

So , here is all the above Code and Error description. I want to call MyCompound class from MainActivity. I know how to do it using an XML file such as

<com.example.mycompoundbutton.MyCompound
     ... attributes here ...
> 
</com.example.mycompoundbutton.MyCompound>

This above structure will help me to design a static custom layout but it won't help me to design a dynamic layout.

So, how can I call the MyCompound class from MainActivity with an AttributeSet?

Answer

ataulm picture ataulm · May 11, 2014

Upon re-reading, one of your issues will lie in the fact that the xyz attribute is declared outside of the CustomViewStyleable in attrs.xml.


Instead of calling your custom view's constructor directly, you can let the system handle that by inflating your custom view from xml.

Create an xml layout file which contains only your custom view, e.g. view_my_compound.xml:

<?xml version="1.0" encoding="utf-8"?>
<com.example.mycompoundbutton.MyCompound
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:xyz="2" />

Then in your Activity, you'll just inflate it:

// the view which will contain your MyCompoundButton
View container = findViewById(R.id.XXXXXXXX);
LayoutInflater inflater = getLayoutInflater();
MyCompound button = (MyCompound) inflater.inflate(R.layout.view_my_compound, container, true);

This way you don't need to consider the attribute set apart from inside your view class; Android will call the MyCompound(Context, AttributeSet) constructor for you, with the values set in the XML layout file.

If you need to set XYZ parameter programmatically, expose a public method in MyCompound which lets you set it.