Drawable的mutate方法Android 1.6中的NullPointerException

当在Android 1.6上使用带有列表状态Drawable的mutate时,我总是得到一个空指针异常.它在更高的Android版本上完美运行.我使用默认的android list_selector_background作为drawable来变异,我需要改变它,否则按下背景会变得非常混乱 – >当按下一个或多个时,它们中的全部或部分都会突出显示.

该项目在这里:

http://code.google.com/p/tree-view-list-android/

相关的一段代码在这里:http://code.google.com/p/tree-view-list-android/source/browse/src/pl/polidea/treeview/AbstractTreeViewAdapter.java#205

return activity.getResources()
                    .getDrawable(android.R.drawable.list_selector_background)
                    .mutate();

堆栈跟踪如下:

3-11 11:37:39.973: ERROR/AndroidRuntime(5304): java.lang.NullPointerException
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.graphics.drawable.StateListDrawable.mutate(StateListDrawable.java:227)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at pl.polidea.treeview.AbstractTreeViewAdapter.getDrawableOrDefaultBackground(AbstractTreeViewAdapter.java:201)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at pl.polidea.treeview.AbstractTreeViewAdapter.populateTreeItem(AbstractTreeViewAdapter.java:210)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at pl.polidea.treeview.AbstractTreeViewAdapter.getView(AbstractTreeViewAdapter.java:153)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.AbsListView.obtainView(AbsListView.java:1273)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.ListView.makeAndAddView(ListView.java:1658)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.ListView.fillDown(ListView.java:637)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.ListView.fillFromTop(ListView.java:694)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.ListView.layoutChildren(ListView.java:1516)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.AbsListView.onLayout(AbsListView.java:1112)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.View.layout(View.java:6569)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.LinearLayout.onLayout(LinearLayout.java:918)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.View.layout(View.java:6569)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.View.layout(View.java:6569)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.LinearLayout.layoutVertical(LinearLayout.java:998)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.LinearLayout.onLayout(LinearLayout.java:918)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.View.layout(View.java:6569)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.widget.FrameLayout.onLayout(FrameLayout.java:333)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.View.layout(View.java:6569)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.ViewRoot.performTraversals(ViewRoot.java:979)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1613)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.os.Handler.dispatchMessage(Handler.java:99)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.os.Looper.loop(Looper.java:123)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at android.app.ActivityThread.main(ActivityThread.java:4203)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at java.lang.reflect.Method.invokeNative(Native Method)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at java.lang.reflect.Method.invoke(Method.java:521)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
03-11 11:37:39.973: ERROR/AndroidRuntime(5304):     at dalvik.system.NativeStart.main(Native Method)

解决方法:

似乎Android 1.6中存在一个错误.当您深入了解Android 1.6源代码时,您可以找到以下代码:

android.graphics.drawable.StateListDrawable.java:
...
public Drawable mutate() {
    if (!mMutated && super.mutate() == this) {
        final int[][] sets = mStateListState.mStateSets;
        final int count = sets.length;
        mStateListState.mStateSets = new int[count][];
        for (int i = 0; i < count; i++) {
            mStateListState.mStateSets[i] = sets[i].clone(); //NPE causing line
        }
        mMutated = true;
    }
    return this;
}
...

排队

mStateListState.mStateSets[i] = sets[i].clone(); //NPE causing line

clone() method is sometimes called on null object and it causes NullPointerException

在Android> 1.6
它已被修复:

public Drawable mutate() {
        if (!mMutated && super.mutate() == this) {
            final int[][] sets = mStateListState.mStateSets;
            final int count = sets.length;
            mStateListState.mStateSets = new int[count][];
            for (int i = 0; i < count; i++) {
                final int[] set = sets[i];
                if (set != null) {
                    mStateListState.mStateSets[i] = set.clone();
                }
            }
            mMutated = true;
        }
        return this;
    }

但在Android 1.6中我们需要做一些解决方法.让我们看看为什么mStateSets [i]有时包含空值:

android.graphics.drawable.DrawableContainer.DrowableContainerState:
... 
public final int addChild(Drawable dr) {
        final int pos = mNumChildren;

        if (pos >= mDrawables.length) {
            growArray(pos, pos+10); //Interesting line
        }

        dr.setVisible(false, true);
        dr.setCallback(mOwner);

        mDrawables[pos] = dr;
        mNumChildren++;
        mChildrenChangingConfigurations |= dr.getChangingConfigurations();
        mHaveOpacity = false;
        mHaveStateful = false;

        mConstantPadding = null;
        mPaddingChecked = false;
        mComputedConstantSize = false;

        return pos;
    }
...

在从xml膨胀对象期间调用上面的方法.所以mStateListState.mStateSets的大小是N * 10.

现在让我们看看你试图从android.R.drawable.list_selector_background引用的资源中膨胀的list_selector_background.xml的主体:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_window_focused="false"
        android:drawable="@color/transparent" />

    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
    <item android:state_focused="true" android:state_enabled="false"
        android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_disabled" />
    <item android:state_focused="true" android:state_enabled="false"
        android:drawable="@drawable/list_selector_background_disabled" />

    <item android:state_focused="true" android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_transition" />
    <item android:state_focused="false" android:state_pressed="true"
        android:drawable="@drawable/list_selector_background_transition" />

    <item android:state_focused="true"
        android:drawable="@drawable/list_selector_background_focus" />

</selector>

此文件仅包含6个项目!
那么我们如何解决这个问题呢?
1.在{Project} / res / drowable /中创建list_selector_background.xml,您可以复制Android one并只更改一行:

<item android:state_window_focused="false"
    android:drawable="@color/transparent" />

<item android:state_window_focused="false" android:drawable="@android:color/transparent" />

>复制Android或创建自己的文件:

list_selector_background_disabled.9.png
list_selector_background_focus.9.png
list_selector_background_longpress.9.png
list_selector_background_pressed.9.png
list_selector_background_transition.xml
>修改list_selector_background.xml添加虚拟项目以完全匹配(6 4 = 10)个项目condidtion:

<item android:animationCache="true"
    android:drawable="@android:color/transparent" />

<item android:animationCache="false"
    android:drawable="@android:color/transparent" />

<item android:alwaysDrawnWithCache="false"
    android:drawable="@android:color/transparent" />

<item android:alwaysDrawnWithCache="true"
    android:drawable="@android:color/transparent" />

瞧.编译并运行.它现在应该工作.

上一篇:java – 防止NullPointerException警告的最佳方法?


下一篇:android – Screen旋转后的nullPointerException