0

I have 2 View classes that implement the same functionality (display images). One is used for backwards compatibility and extends ImageView, while the other extends TextureView but is available only in API 14+. I set a custom factory to pick the right class to use at runtime (you place MyViewProxy in your XML layouts).

class View1 extends ImageView
{
    ...
}

class View2 extends TextureView // TextureView extends View (not ImageView)
{
    ...
}

class MyViewProxy extends ImageView
{
    ...
}

private static class MyViewFactory implements LayoutInflater.Factory
{
    @Override
    public View onCreateView( String name, Context context, AttributeSet attrs )
    {
        if( 0 == name.compareTo( "MyViewProxy" ) )
        {
            if( android.os.Build.VERSION.SDK_INT < 14 )
            {
                return new View1( context, attrs );
            }
            else
            {
                return new View2( context, attrs );
            }
        }
        return null;
    }
}

This all works fine, except for the part where View2 (which does not extend ImageView) should detect the default "src" image to display, like ImageView does. View1 extends ImageView, so it already works fine.

The goal: to be able to convert the "src" attribute from XML into a resource id, and open the resource using getResources().openRawResource( resId ). The value of the src attribute is typically in the form "@drawable/image".

For reference, here's how ImageView sets its default image:

public ImageView(Context context, AttributeSet attrs, int defStyle)
{
    super(context, attrs, defStyle);
    initImageView();
    TypedArray a = context.obtainStyledAttributes(attrs,
        com.android.internal.R.styleable.ImageView, defStyle, 0);
    Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);
    if (d != null)
    {
        setImageDrawable(d);
    }
    ...
}

I tried replicating this code in View2's constructor, but got "undefined reference" for com.android.internal.R. I thought I might use reflection to circumvent this, although that's probably a sketchy thing to do.

Here's what I've got so far. This code does not work yet

public View2( Context context, AttributeSet attrs, int defStyle )
{
    ...
    Class<?> clazz = Class.forName( "com.android.internal.R$styleable" );
    Field ImageView_field = clazz.getField( "ImageView" );
    Field ImageView_src_field = clazz.getField( "ImageView_src" );
    if( ImageView_field != null && ImageView_src_field != null )
    {
        if( ImageView_field.getType().isArray() )
        {
            Class<?> type = ImageView_field.getType().getComponentType();
            Object array = ImageView_field.get( clazz );
            if( type == Integer.TYPE )
            {
                int[] ImageView_intArray = (int[]) array;
                TypedArray aInternal = context.obtainStyledAttributes( attrs, ImageView_intArray, defStyle, 0 );

                int srcId = ImageView_src_field.getInt( clazz );
                String src = aInternal.getString( srcId );
                if( src != null )
                {
                    File testfile = new File( src );
                    boolean exists = testfile.exists();
                    //InputStream is = context.getAssets().open( src ); // throws FileNotFoundException
                    int resId = context.getResources().getIdentifier( src, "drawable", context.getPackageName() ); // returns 0
                    InputStream is = context.getResources().openRawResource( resId );
                    if( is != null )
                    {
                    }
                }

                aInternal.recycle();
            }
        }
    }
}

Using reflection, I can access the "src" variable correctly, which in my test is "res/drawable-hdpi/image.bmp" (from "@drawable/image" in XML). From there, how do I actually open it? AssetManager.open() throws a FileNotFoundException, Resources.getIdentifier() returns 0, and File.exists() returns false.

Am I even approaching this problem correctly? Will reflection jeopardize the future-proof-ness of my code?

foo64
  • 2,075
  • 3
  • 18
  • 25
  • You need to define a custom attribute. See this answer: http://stackoverflow.com/a/7608739/1007510 – Chris Feist May 04 '14 at 05:28
  • I know my question is rather long, but it looks like you didn't really read it. The "src" attribute already exists in ImageView and I've already found a way to access it (using reflection), now my problem is what to do with it. How do I open "res/drawable-hdpi/image.bmp"? – foo64 May 04 '14 at 08:13
  • Well its real easy to setup the solution I told you and the right solution. To get the bitmap after you have the resource ID, call `getDrawable(R.styleable.MyExtendedImageView_src)` on your TypedArray object. – Chris Feist May 04 '14 at 15:34
  • I'm not interested in drawables. I want an InputStream via Resources.openRawResource(). After some trial and error, I found that I can extract the "image" part from "res/drawable-hdpi/image.bmp", pass it to Resources.getIdentifier(), then I get a valid resource id to pass to Resources.openRawResource(). – foo64 May 05 '14 at 03:07

0 Answers0