原文  http://blog.csdn.net/u012604322/article/details/18362575

主题 安卓开发

public class PowerInformationPreference extends Preference {    private TextView firstName;

    public PowerInformationPreference(Context context, AttributeSet attr, int defStyle) {
        super(context, attr, defStyle);
        setLayoutResource(R.layout.layout_power_information);
    }

    @Override    protected void onBindView(View view) {(1)
        // TODO Auto-generated method stub        super.onBindView(view);
        firstName = (TextView)view.findViewById(R.id.firstname);(2)
    }

}

上面是我们很常见到的自定义preference的基本形式,我们在onBindView()函数中操作自定义视图,比如上面的代码中我们需要动态的改变firstName这一TextView的text值。

如下,我们提供一个setText()接口,通过这个接口我们可以动态改变TextView的text值。

public void setText(String text){(3)
    firstName.setText(text);//NullPointerException(4)}

如果我们真的是这样写这个接口的话,会发现一定会出现NullPointerException,调试发现这里的firstName为空。而回到onBindView()中调试分析又会发现,firstName = (TextView)view.find...实际上是会运行的,也就是有这个firstName对象存在。那么唯一的解释就是setText()的调用在onBindView()运行之前,因此我们的疑惑来了,如何确保onBindView()在setText()调用之前运行呢?

事实上,到这里我们如果继续这样分析的话,就会钻入误区,跳出来,从逻辑层面上想想,我们会发现,(1),(2),(4)是对UI的操作,(3)是对数据的操作。这里,(1)(2)和(4)分开了,也就是说,(1)(2)运行的时候不能保证(4)运行;(4)运行的时候不能保证(1)(2)运行,这对UI操作是非常危险的事,很容易就产生了控制正异常。

不仅仅是这里,我们查看Adapter.java的源码,查看有getView(), onCreateView(), onBindView()等类的相关源码,都会发现,凡是涉及到UI操作的一定是放在一起的。

现给出上例的修正方案:

public class PowerInformationPreference extends Preference {    private TextView firstName;    private String text;

    public PowerInformationPreference(Context context, AttributeSet attr, int defStyle) {
        super(context, attr, defStyle);
        setLayoutResource(R.layout.layout_power_information);
    }

    @Override    protected void onBindView(View view) {(1)
        // TODO Auto-generated method stub        super.onBindView(view);
        firstName = (TextView)view.findViewById(R.id.firstname);(2)
        firstName.setText(text);
    }

public void setText(String text){(3) this.text = text; 
notifyChanged(); 


这里还需要强调的一点是一定不要忘记notifyChanged()这个函数通知UI更新数据,否则我们会发现通过这个接口设置的数据并没有改变原来的值。这个函数如同View中的invalidate(),虽然数据更新了,但是显示在视图中的数字图像依然没变,因此需要通知UI更新显示。 



注意:本文归作者所有,未经作者允许,不得转载