15

I'm writing a custom view that directly extends android.view.View. If I try to access fields mScrollX or mScrollY, I see an error that the field "cannot be resolved or is not a field." The source code for android.view.View has mScrollX, mScrollY, and similar variables declared protected. How is it that my direct subclass cannot access protected fields of its parent class? (Classes like ScrollView apparently can.)

P.S. I realize that I can call getScrollX(), but I want to update these fields; calling setScroll() has side effects that I don't want.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • Weird, subclasses, even being in other packages, can access protected variables of their superclass. I would guess that you're using the wrong version. Can you show some of your code? – Johan Sjöberg Feb 06 '11 at 21:28

3 Answers3

21

It's because they are not part of the Android SDK.

Here is the source code for mScrollX:

/**
 * The offset, in pixels, by which the content of this view is scrolled
 * horizontally.
 * {@hide}
 */
@ViewDebug.ExportedProperty(category = "scrolling")
protected int mScrollX;

You will notice the @hide annotation. That means this is not part of the Android SDK. The part of the build process that creates the Android SDK will not include this data member in the stub edition of android.view.View that is in the android.jar file that you are compiling against.

The @hide annotation is used for things that for internal purposes needed to be public or protected but are not considered something SDK developers should be using.

Please find other solutions for whatever problem you are experiencing.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 9
    Hmm, interesting! So to paraphrase the rationale: "We couldn't be bothered to sort out proper encapsulation, so we subverted the language."... – Oliver Charlesworth Feb 06 '11 at 21:53
  • I had noticed the `{@hide}` tag. I assumed it was why `mScrollX` did not appear in the JavaDocs (like the [proposed `@exclude` tag](http://java.sun.com/j2se/javadoc/proposed-tags.html), which supercedes `@hide`). I didn't realize that the SDK was a stub version of the API. – Ted Hopp Feb 06 '11 at 21:57
  • One thing i cant understand is Protected variable of **View** class is accessed in **ScrollView** class. How is this possible ? Hierarchy is - ScrollView extends FramLayout extends ViewGroup extends View. So, protected variable of View class should only accessible in ViewGroup. – Mitul Varmora Dec 07 '16 at 06:55
5

It's very straight forward: notice the @hide annotation above these variables. It's an Android-specific annotation that hides the fields/methods from the public SDK. That's why you can't access them directly.

Romain Guy mentioned it in this post.

Lior
  • 7,845
  • 2
  • 34
  • 34
  • that is disturbing. what's the point of open source? so people can read the source and understand what's going on. but the source released here is a fake one? not the one used in production? that is also acceptable, *if it is transparent*. I don't care if the JDK source is the *real* one, but any information I gained from read it must be true in the real system. – irreputable Feb 06 '11 at 23:39
  • You have to understand the meaning of open-source. First of all, you can build your own Android version directly from the source, do any modifications you want to it, and use every method or field whether hidden or not. That's what phone manufacturers do and some of the custom ROM cooks in the community. Developers can benefit from another aspect of Android being open-source, and that is going through the source and understand how things work behind the scenes, for me this is as-important as the documentation itself. – Lior Feb 07 '11 at 10:47
  • 2
    The fact that some fields or methods are hidden is usually one of the following two: 1. They might change in future release of the SDK, so they want to reduce the chance of app-incompatibility, saving you, the developer a lot of work maintaining your apps, and 2. Using these fields directly like in your case might interfere with proper work of how the API's work internally. – Lior Feb 07 '11 at 10:47
4

You could try setting the fields with reflection:

import java.lang.reflect.Field;

// ...

try {
    Field scrollXField = View.class.getDeclaredField("mScrollX");
    scrollXField.setAccessible(true);
    scrollXField.set(this, myNewValue);
} catch (Exception ex) {
    // oops, android changed the implementation. sucks to be you.
}

Note, however, that you're relying on undocumented and unsupported behavior when you do this, and so you should be prepared for things to break on some devices or in future versions.

mlc
  • 1,668
  • 2
  • 16
  • 30