InitializeScrollbars undefined?

Фон

Я использую эту библиотеку, которая для одного из ее классов (которая простирается от ViewGroup) в "PLA_AbsListView.java", внутри CTOR есть такие строки:

    final TypedArray a = context.obtainStyledAttributes(R.styleable.View);
    initializeScrollbars(a);
    a.recycle();

Недавно я обновил SDK и ADT Android для поддержки новой версии Android (Lollipop - API21).

Проблема

С тех пор как я обновил все, я продолжаю получать эту ошибку:

Метод initializeScrollbars (TypedArray) - undefined для типа PLA_AbsListView

Что я пробовал

Я попытался установить API для использования ниже 21, но это не помогло.

Я также попытался выяснить, где объявлена ​​эта функция. Он должен быть защищенной функцией внутри "View.java", но по какой-то причине я не вижу его в документациях

Вопрос

Как это могло быть?

Как я могу это исправить?

Возможно ли это в документации?

До этого он работал, когда нацеливался на Kitkat...

Ответ 1

из View.java источников android-21:

/**
 * ...
 *
 * @removed
 */
protected void initializeScrollbars(TypedArray a) {
    // It not safe to use this method from apps. The parameter 'a' must have been obtained
    // using the View filter array which is not available to the SDK. As such, internal
    // framework usage now uses initializeScrollbarsInternal and we grab a default
    // TypedArray with the right filter instead here.
    TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View);

    initializeScrollbarsInternal(arr);

    // We ignored the method parameter. Recycle the one we actually did use.
    arr.recycle();
}

/**
 * ...
 *
 * @hide
 */
protected void initializeScrollbarsInternal(TypedArray a) {

Вы не видите этого, потому что метод аннотируется с помощью @removed. initializeScrollbarsInternal() также не может использоваться, поскольку он аннотируется с помощью @hide. Поскольку из комментария небезопасно использовать этот метод, вы должны обязательно сообщить об этом автору lib.

Ответ 2

Как отметил в своем ответе @biegleux, initializeScrollbars() теперь аннотируется с @removed в исходном коде API 21. Вот источник метода из API 21:

protected void initializeScrollbars(TypedArray a) {
    // It not safe to use this method from apps. The parameter 'a' must have been obtained 
    // using the View filter array which is not available to the SDK. As such, internal 
    // framework usage now uses initializeScrollbarsInternal and we grab a default 
    // TypedArray with the right filter instead here. 
    TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View);

    initializeScrollbarsInternal(arr);

    // We ignored the method parameter. Recycle the one we actually did use. 
    arr.recycle();
}

Основываясь на комментарии в методе, это похоже на проблему до того, как API 21 был в том, что передавать не удалось в TypedArray, но теперь он больше не использует переданный в TypedArray. Похоже, что это должно быть аннотировано с помощью @Deprecated вместо @removed, и должна быть новая версия этого метода, которая не принимает никакого параметра, который можно вызвать, когда нам нужно инициализировать полосы прокрутки из пользовательского представления, созданного программным путем.

Пока это не будет исправлено, вы можете обойти эту проблему двумя способами:

1) Наполните свой пользовательский вид из xml с помощью набора атрибутов android:scrollbars. Это самый безопасный метод и должен работать со всеми прошлыми и будущими версиями платформы. Например:

Создайте файл макета xml (my_custom_view.xml):

<com.example.MyCustomView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="horizontal|vertical"/>

Наполните свой пользовательский вид:

MyCustomView view = (MyCustomView) LayoutInflater.from(context).inflate(R.layout.my_custom_view, container, false);

2) Используйте рефлексию для вызова initializeScrollbars() в свой пользовательский конструктор представлений. Это может привести к сбою в будущих версиях API, если метод initializeScrollbars() фактически удален или переименован. Например:

В вашем пользовательском представлении (например, MyCustomView.java):

public MyCustomView(Context context) {
    super(context);

    // Need to manually call initializedScrollbars() if instantiating view programmatically
    final TypedArray a = context.getTheme().obtainStyledAttributes(new int[0]);
    try {
        // initializeScrollbars(TypedArray)
        Method initializeScrollbars = android.view.View.class.getDeclaredMethod("initializeScrollbars", TypedArray.class);
        initializeScrollbars.invoke(this, a);
    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
        e.printStackTrace();
    }
    a.recycle();
}