As I'm tired of writing a cast operator for EVERY Activity.findViewById()
that returns raw View
, I finally tried one way that was suggested by Internet.
public abstract class MyActivity extends Activity {
@SuppressWarnings("unchecked")
protected <T extends View> T findViewByID(int id) {
return (T) this.findViewById(id);
}
}
Note this isn't overloaded (the last "D" is upper case). The compiler says we can't cast View
into T
. Is there anything wrong with my implementing? Strangely, this suggestion was hardly seen in English websites (e.g. even in our lovely Stack Overflow), and the exception was the site posted above.
This works fine in my test project. No compiler error:
To be honest, this approach adds some subtle complexity overhead for the next Android maintainer (who would be used to the casting approach) to save a few characters in the code files.
I would propose to cast the Views in the traditional way, or opt for a reflection-based solution like Roboguice.
I solved this by using a custom eclipse-builder that generates classes with references for each layout-file, because:
- It's typesafe and easy to use
- RoboGuice and all other reflection-based APIs are very slow on Android.
In my opinion this is the cleanest and most performant way of solving this problem.
See my gist here for the builder: https://gist.github.com/fab1an/10533872
Layout: test.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/text1" />
<ScrollView
android:id="@+id/scroll"
android:layout_width="match_parent"
android:layout_height="350px"
android:layout_below="@id/text2"
android:layout_marginTop="50px" />
</merge>
usage: TestView.java
public final class TestView extends RelativeLayout {
//~ Constructors ---------------------------------------------------------------------------------------------------
private final ViewRef_test v;
public TestView(final Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.test, this, true);
this.v = ViewRef_test.create(this);
this.v.text1.setText();
this.v.scroll.doSomething();
}
}
generated file (in gen/
): ViewRef_test.java
package org.somecompany.somepackage;
import android.view.*;
import android.widget.*;
import java.lang.String;
@SuppressWarnings("unused")
public final class ViewRef_test {
public final TextView text1;
public final TextView text2;
public final ScrollView scroll;
private ViewRef_test(View root) {
this.text1 = (TextView) root.findViewById(R.id.text1);
this.text2 = (TextView) root.findViewById(R.id.text2);
this.scroll = (ScrollView) root.findViewById(R.id.scroll);
}
public static ViewRef_test create(View root) {
return new ViewRef_test(root);
}
}
来源:https://stackoverflow.com/questions/11433722/android-a-findviewbyid-method-that-returns-values-we-dont-need-to-cast