web-dev-qa-db-ja.com

Android Nougat:TextureViewは、背景のドロアブルの表示をサポートしていません

私はAndroidアプリでTextureViewを使用していますが、正常に機能していました。つい最近、AndroidデバイスでAndroid AP​​I 25(7.1.2)を使用してコードをテストしました。現在、同じコードは機能せず、エラー_Java.lang.UnsupportedOperationException: TextureView doesn't support displaying a background drawable_をスローします。

void setBackgroundDrawable (Drawable background)長い間非推奨 であったことを知っていますが、今では削除されているはずです。しかし、私は自分で設定することすらしていません。

私は最新のbuildToolsとSDKを使用しています。だから、textureViewの内部実装がなぜ更新されていないのだろうか

関連するスタックトレースは次のとおりです:

_Java.lang.UnsupportedOperationException: TextureView doesn't support displaying a background drawable
at Android.view.TextureView.setBackgroundDrawable(TextureView.Java:315)
at Android.view.View.setBackground(View.Java:18124)
at Android.view.View.<init>(View.Java:4573)
at Android.view.View.<init>(View.Java:4082)
at Android.view.TextureView.<init>(TextureView.Java:159)
at com.abdulwasaetariq.xyz.ui.customView.AutoFitTextureView.<init>(AutoFitTextureView.Java:24)
at com.abdulwasaetariq.xyz.ui.customView.AutoFitTextureView.<init>(AutoFitTextureView.Java:20)
at Sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[...]
at Java.lang.Thread.run(Thread.Java:745)
_

ここで、(まだカスタマイズされていない)カスタムTextureViewの使用方法を示します:

_<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    tools:context="com.abdulwasaetariq.xyz.ui.activity.MainActivity">

    <com.abdulwasaetariq.xyz.ui.customView.AutoFitTextureView
        Android:id="@+id/texture"
        Android:layout_width="1080px"
        Android:layout_height="1080px"
        Android:layout_alignParentStart="true"
        Android:layout_alignParentTop="true" />

</RelativeLayout>
_

関連するAutoFitTextureView.Java:_enter code here_

_public class AutoFitTextureView extends TextureView {

private int mRatioWidth = 0;
private int mRatioHeight = 0;

public AutoFitTextureView(Context context) {
    this(context, null);
}

public AutoFitTextureView(Context context, AttributeSet attrs) {
    this(context, attrs, 0); //(LINE#20)
}

public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle); //(LINE#24)
}

public void setAspectRatio(int width, int height) {
    if (width < 0 || height < 0) {
        throw new IllegalArgumentException("Size cannot be negative.");
    }
    mRatioWidth = width;
    mRatioHeight = height;
    requestLayout();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    if (0 == mRatioWidth || 0 == mRatioHeight) {
        setMeasuredDimension(width, height);
    } else {
        if (width < height * mRatioWidth / mRatioHeight) {
            setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
        } else {
            setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
        }
    }
}}
_

したがって、ご覧のとおり、例外はsuper()メソッドで発生します。つまり、カスタムのTextureViewはこの例外を処理しません。それは内部呼び出しです。

私のgradle設定は次のとおりです。

_apply plugin: 'com.Android.application'

Android {
    compileSdkVersion 25
    buildToolsVersion '25.0.2'
    defaultConfig {
        applicationId "com.abdulwasaetariq.xyz"
        minSdkVersion 21
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "Android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    androidTestCompile('com.Android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.Android.support', module: 'support-annotations'
        })
    compile 'com.Android.support.constraint:constraint-layout:1.0.0-alpha8'
    compile 'com.github.hotchemi:permissionsdispatcher:2.3.2'
    annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:2.3.2'
}
_

なぜこれが起こっているのか?この変更について言及されているAndroid AP​​I 25のリリースノート

25
Abdul Wasae

API 24のテクスチャビューのソースを見ると、次のように表示されます。

_/**
 * Subclasses of TextureView cannot do their own rendering
 * with the {@link Canvas} object.
 *
 * @param canvas The Canvas to which the View is rendered.
 */
@Override
public final void draw(Canvas canvas) {
    // NOTE: Maintain this carefully (see View#draw)
    mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

    /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
    scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
    properties (alpha, layer Paint) affect all of the content of a TextureView. */

    if (canvas.isHardwareAccelerated()) {
        DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;

        HardwareLayer layer = getHardwareLayer();
        if (layer != null) {
            applyUpdate();
            applyTransformMatrix();

            mLayer.setLayerPaint(mLayerPaint); // ensure layer Paint is up to date
            displayListCanvas.drawHardwareLayer(layer);
        }
    }
}
_

draw()の本文のコメントは、あなたが見た変更の根拠を与えます。これは私が見つけた唯一のドキュメントです。これをAPI 23のTextureViewと比較してください:

_/**
 * Subclasses of TextureView cannot do their own rendering
 * with the {@link Canvas} object.
 *
 * @param canvas The Canvas to which the View is rendered.
 */
@Override
public final void draw(Canvas canvas) {
    // NOTE: Maintain this carefully (see View.Java)
    mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;

    applyUpdate();
    applyTransformMatrix();
}
_

API 24では、API 23でオーバーライドされない「バックグラウンドの設定」メソッドのオーバーライドも導入されました。バックグラウンドの設定は明らかに推奨されておらず、許可されていません。サポートされていない操作の例外が表示され、明示的に背景を設定していない場合は、おそらくスタイルを介してこっそりと侵入しています。 XMLに_Android:background="@null"_を設定して、エラーを回避するために背景を強制的にnullにしてみてください。次のコードをカスタムビューに追加して、背景の設定をサポートするバージョンの機能を保持することもできます。

_@Override
public void setBackgroundDrawable(Drawable background) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N && background != null) {
        setBackgroundDrawable(background);
    }
}
_

API 24+で失われた機能をどのように置き換えるか、それが必要な場合でもバックグラウンドツールを武器にしたいだけなのかは不明です。

3
Cheticamp

以下は、 View for Android Nougat :)のソースコードからの抜粋です。

/**
 * Allow setForeground/setBackground to be called (and ignored) on a textureview,
 * without throwing
 */
static boolean sTextureViewIgnoresDrawableSetters = false;

単一引数コンストラクター(他のすべてから呼び出される):

        // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
        // On N+, we throw, but that breaks compatibility with apps that use these methods.
        sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;

例外がスローされるViewコンストラクター内:

...
        switch (attr) {
            case com.Android.internal.R.styleable.View_background:
                background = a.getDrawable(attr);
                break;
...
    if (background != null) {
        setBackground(background);  // <--- this is the problematic line, apparently "background" is not null here
    }

setBackgroundの実際の定義:

/**
 * Set the background to a given Drawable, or remove the background. If the
 * background has padding, this View's padding is set to the background's
 * padding. However, when a background is removed, this View's padding isn't
 * touched. If setting the padding is desired, please use
 * {@link #setPadding(int, int, int, int)}.
 *
 * @param background The Drawable to use as the background, or null to remove the
 *        background
 */
public void setBackground(Drawable background) {
    //noinspection deprecation
    setBackgroundDrawable(background);
}

次に、 setBackgroundDrawableTextureViewのオーバーライド:

@Override
public void setBackgroundDrawable(Drawable background) {
    if (background != null && !sTextureViewIgnoresDrawableSetters) {
        throw new UnsupportedOperationException(
                "TextureView doesn't support displaying a background drawable");
    }
}

1)ターゲットSDK N(Nougat)があります-ビルドファイルから明らかです。 2)Viewのコンストラクターはnull以外の背景を決定します(現時点ではこの部分を説明できません)。

これが実際の問題になるのに必要なことはそれだけです。 xmlでドロウアブルを定義できたとは思わないので、setBackgroundまたはsetBackgroundDrawableをオーバーライドすることが、問題を解決するための最も賢明な可能性のようです。コンストラクターでbackground変数を強制的にnullに強制することができる別の回避策があるかもしれません(または、「推奨される使用法」がより良い用語かもしれません)。

8
Dave

TextureViewだけでなく、言うまでもなく、GridLayoutはAPI 24以降、背景のドロアブルの表示もサポートしていません。

私は試した:

A)gridLayout.setBackgroundResource(R.drawable.board_960x960px_border_in_bg);

B)Resources res = getResources(); Drawable drawable = res.getDrawable(R.drawable.board_960x960px_border_in_bg); gridLayout.setBackground(drawable);

上記のどちらもAPI 23を超えて機能しているようには見えません。

ただし、TableLayoutの背景はAPI 24以降でも消えないので、関連するすべてのコードをGridLayoutからTableLayoutに書き直して、今では大丈夫です。

1
Hardzsi