1

I my case: I want to override a hide method in TextView by extends TextView, and make call to its super method.

public class MyTextView extends TextView {
    protected void makeNewLayout(int wantWidth, int hintWidth,
                                 BoringLayout.Metrics boring,
                                 BoringLayout.Metrics hintBoring,
                                 int ellipsisWidth, boolean bringIntoView) {
        // omit try catch for simple
        Method method = Class.forName("android.widget.TextView").getDeclaredMethod("makeNewLayout", int.class, int.class, BoringLayout.Metrics.class, BoringLayout.Metrics.class, int.class, boolean.class);
        method.setAccessible(true);
        method.invoke(this, wantWidth, hintWidth, boring, hintBoring, ellipsisWidth, bringIntoView);
    }
}

The problem is my self define makeNewLayout is called and the method.invoke is executed, but the method invoke is MyTextView::makeNewLayout not TextView::makeNewLayout, it a dead recursive call.

How can I acheive it?

PS: makeNewLayout is a hide function, so I cannot call it directly by super.makeNewLayout(...)

Looks like it's not possible for java/android to do this kind of work easily. java is too safe to hack around.

Gohan
  • 2,422
  • 2
  • 26
  • 45
  • Don't override. Rename your makeNewLayout to something else. – laune Sep 22 '15 at 07:55
  • @laune yeah, that will work, but what I want is to hook the time TextView called makeNewLayout, and do some work based on that. – Gohan Sep 22 '15 at 07:57
  • 1
    if it is hidden then devs had a good reason of doing this, what do you need it for? – pskink Sep 22 '15 at 07:58
  • 1
    @pskink because there are some bugs in `TextView` like: imagespan or other custom spans conflict with ellipsize setting, and also the `EditText` with multiple imagespans has some strange behaviors(the layout truncate newline result changes when it should not changed), looks like it is caused by DynamicLayout reflow(I'm not very sure). – Gohan Sep 22 '15 at 08:07
  • @pskink like this bug, textview goes to multiline, or textview's widthmode is WRAP_CONTENT, it will still be a problem. http://stackoverflow.com/questions/28892115/android-imagespan-image-is-cut-error-in-singleline-textview I think the best solution is to implement own TextView not extend android's `TextView`, but it will need more effort. – Gohan Sep 22 '15 at 08:07
  • sorry but what you want cannot be done, if it has bugs you can open the bug report in the Issue Tracker and wait till it is fixed... – pskink Sep 22 '15 at 08:16

1 Answers1

1

There's a solution below android 8.0 if you can accept packaging some *.so library. There's a family of calling non-virtual methods in JNI interface (https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#CallNonvirtual_type_Method_routines) Using it like this:

Declaring in java:

public native void callNonvirtualVoidMethodHelper(Object obj, String classNameOfMethod, String methodName, String methodSignature);

Implementation in cpp:

extern "C"
JNIEXPORT
void JNICALL
Java_yourpackage_yourclass_callNonvirtualVoidMethodHelper(
    JNIEnv *env,
    jobject /* this */,
    jobject obj,
    jstring classNameOfMethod,
    jstring methodName,
    jstring methodSignature) {
    const char *classNameStr = env->GetStringUTFChars(classNameOfMethod, JNI_FALSE);
    const char *methodNameStr = env->GetStringUTFChars(methodName, JNI_FALSE);
    const char *methodSignatureStr = env->GetStringUTFChars(methodSignature, JNI_FALSE);
    jclass classOfMethod = env->FindClass(classNameStr);
    jmethodID method = env->GetMethodID(classOfMethod, methodNameStr, methodSignatureStr);
    env->CallNonvirtualVoidMethod(obj, classOfMethod, method);
}

Using it in java:

callNonvirtualVoidMethodHelper(new SubClass(),
        "some/package/SuperClass", // specify the class of non-virtual method
        "foo",
        "()V"); // method signature

Or using MethodHandle when running above android 8.0 (Reference: https://stackoverflow.com/a/15674467/2300252).

eggfly
  • 21
  • 3