views:

3163

answers:

5

I have two Android projects, a 'library project' containing a custom layout, and an 'application project' containing an application which uses the layout.

Everything seems to build and execute fine, except that the visual layout editor throws a ClassNotFoundException (which I assume is a bug in the plug-in), but when I try to start to make use of the attributes I defined for the custom layout in the xml, I can no longer build. That is; this works:

<?xml version="1.0" encoding="utf-8"?>
<se.fnord.android.layout.PredicateLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
  <TextView
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="asdfasdf"
    />
</se.fnord.android.layout.PredicateLayout>

Whereas this does not:

<?xml version="1.0" encoding="utf-8"?>
<se.fnord.android.layout.PredicateLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fnord="http://schemas.android.com/apk/res/se.fnord.android"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
  <TextView
    fnord:layout_horizontalSpacing="1px"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="asdfasdf"
    />
</se.fnord.android.layout.PredicateLayout>

The build fails with a message from aapt:

ERROR No resource identifier found for attribute 'layout_horizontalSpacing' in package 'se.fnord.android'

The resource identifier does exist in the R-file and attrs.xml contained the library project, and if I put the layout code and resources directly in the application project everything works fine. The layout_horizontalSpacing attribute (and layout_verticalSpacing) is a custom attribute used in the PredicateLayout.LayoutParam class to specify the distance to the next widget.

So far I've tried the standard eclipse ways by specifying project references and build path project dependencies. I was also told to try the tag in the application manifest, which did not help.

So, what do I need to do for the references in the xml-file to work?

I don't know if it's relevant, but the 'library' manifest looks like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="se.fnord.android"
      android:versionCode="1" android:versionName="1.0.0">
</manifest>

The 'application' manifest like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="se.fnord.appname"
      android:versionCode="1" android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".AppName"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

(The 'PredicateLayout', btw, is a cleaned-up version of this).

A: 

Export your library project as a JAR and reference it in your application project's "Java Build Path" as a JAR.

Hans Malherbe
+1  A: 

The "Export your library as a jar" solution" only works if your library project contains source code only. In this case the OP's question mentions that his library project contains ui-related stuff.

We have the exact same issue on my team of wanting to have library projects that hold ui-related source and resources. We ended up overhauling our Ant build system in order to have applications engulf the library projects during build time. Unfortunately no solution of this sort seems to be compatible with Eclipse and this is a major source of frustration for the developers. We are still able to use Eclipse, but we have to jump through hoops to get it working and have to put up with diminished productivity.

Joseph Johnson
See above update which mentions ADT 0.9.7 - it mostly solves this problem.
Joseph Johnson
+5  A: 

Google just delivered a new ADT that purports to solve this problem. See

http://developer.android.com/intl/de/guide/developing/eclipse-adt.html#libraryProject

Joseph Johnson
ADT 0.9.7 gets us 80% of what we want, but it still has these drawbacks:(1) a library project cannot hold .aidl files, (2) a library project cannot depend on another library project, (3) a library project cannot hold assets
Joseph Johnson
(1) isn't valid anymore as of ADT 0.9.8
neu242
A: 

Sorry, don't have the anwswer to the question.

I get stuck a step earlier: how can I reference a custom view defined in a library project (like se.fnord.android.layout.PredicateLayout is I think?) in a layout in the main project?

I use the in the main project, which is a custom view defined in the library project, but I keep getting ClassNotFoundExceptions when inflating the layout. In code, I have no problem using classes from the library project.

Am using more or less the same manifests as shown here, and using the ADT 0.9.9. Thanks.

Edwin
I think you should post this as a new question
Henrik Gustafsson
Thanks, but it suddenly started working.
Edwin
A: 

Also, I got the attributes working, but not in the way it should work I think.

You must use as the namespace in the element that uses your custom attributes, the namespace of your main app, not that of the library project. So, in your example, if you specify for the value of "xmlns:fnord" the namespace of your app project, it works.

Also, when reading the custom attributes in your custom PredicateLayout(Context,AttributeSet) constructor, you must specify the app's namespace as well in calls to attributes.getAttributeValue().

Which is a pain, since that code is in your library app which doesn't/shouldn't know about the app project it is used in. I worked around that by having the app call a static method ViewUtil.setAttributeNamespace(appNamespace) in my app's onCreate(), and the library's custom views use that namespace to retrieve the custom attributes. The attrs.xml file can then remain in the library project as well. Now the only ugly thing is that the layout XML must use the app's namespace on custom views, so you can't put those layout XML's in the library project.

Edwin