简体   繁体   English

没有静态引用,Android自定义视图事件侦听器将无法正常工作

[英]Android custom view event listeners not working properly without static reference

I'm creating a custom compound view in android which contains two TextViews within a relative layout. 我在android中创建一个自定义复合视图,该视图在相对布局中包含两个TextView。 There are two classes, one is BarcodeScannerView which is the compound view and another activity that uses the custom view. 有两类,一类是BarcodeScannerView,它是复合视图,另一类是使用自定义视图的活动。 The code is as follows. 代码如下。

BarcodeScannerView.java BarcodeScannerView.java

    public class BarcodeScannerView extends RelativeLayout implements View.OnClickListener {

    private int boxRadius;
    private String boxText;
    private int boxColor, boxEntityColor;
    private TextView entityName;
    private TextView manualEntry;
    private ImageView scannerReadyImv;
    private RelativeLayout scannerBox;
    private OnClickListener listener;
    private ScannerListener scanner;
    private ScannerState state;
   // private static BarcodeScannerView instance;

    public enum ScannerState {
        IDLE, READY, COMPLETE;
    }

    public interface ScannerListener {

        void onClickScannerBox();
        void scannerIdle();
    }

    public BarcodeScannerView(Context context) {
        super(context);
    }

    public BarcodeScannerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {

        View.inflate(context, R.layout.activity_barcode_scanner, this);
        setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS);

        entityName = (TextView) findViewById(R.id.entityNameTV);
        manualEntry = (TextView) findViewById(R.id.manualEntryTV);
        scannerReadyImv = (ImageView) findViewById(R.id.scannerReadyImv);
        scannerBox = (RelativeLayout) findViewById(R.id.scannerBox);

        manualEntry.setOnClickListener(this);
        scannerBox.setOnClickListener(this);

        // Assign custom attributes
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.barcodeviewer, 0, 0);

        try {

            boxEntityColor = a.getInteger(R.styleable.barcodeviewer_boxEntityColor, 0);
            setBoxEntityColor(boxEntityColor);

        } finally {
            a.recycle();
        }

    }

    // Set custom attributes
    private void setBoxEntityColor(int color) {
        this.entityName.setTextColor(color);
    }

    // Set event handlers
    public void setOnClickListener(OnClickListener listener) {
        this.listener = listener;
    }

    public void setOnScannerListener(ScannerListener scanner) {
        this.scanner = scanner;
    }


    // Setters and getters
    public void setScannerState(ScannerState state) {
        this.state = state;
    }

    public ScannerState getScannerState() {
        return this.state;
    }

    private void setScannerReadyState() {
        scannerBox.setBackgroundResource(R.drawable.bc_active_4);
        scannerReadyImv.setVisibility(View.VISIBLE);
    }

    public void onClick(View v) {

        if (v.getId() == R.id.scannerBox) {
            this.scanner.onClickScannerBox();
            if (this.getScannerState() == ScannerState.IDLE) {
                setScannerReadyState();
            }
        }
    }
}

MainActivity.java MainActivity.java

public class MainActivity extends AppCompatActivity implements BarcodeScannerView.ScannerListener {

private BarcodeScannerView barcodeScannerView;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    /*barcodeScannerView = BarcodeScannerView.instance(MainActivity.this);
    barcodeScannerView.setOnScannerListener(this);*/
    barcodeScannerView = new BarcodeScannerView(this);
    barcodeScannerView.setOnScannerListener(this);
}

@Override
public void onClickScannerBox() {
    scannerIdle();
}

@Override
public void scannerIdle(){
    barcodeScannerView.setScannerState(BarcodeScannerView.ScannerState.IDLE);
}

}

The issue is when I call the onClick() method of the BarcodeScannerView class it gives a null point exception. 问题是当我调用BarcodeScannerView类的onClick()方法时,它给出了一个空点异常。

java.lang.NullPointerException: Attempt to invoke interface method 'void [packagename]$ScannerListener.onClickScannerBox()' on a null object reference java.lang.NullPointerException:尝试在空对象引用上调用接口方法'void [packagename] $ ScannerListener.onClickScannerBox()'

In debugging I noticed that when the onClickScannerBox() is called, the scanner object get initialized. 在调试中,我注意到当调用onClickScannerBox()时,将初始化扫描程序对象。 But after onClickScannerBox() is executed in BarcodeScannerView the scanner object gets null. 但是在BarcodeScannerView中执行onClickScannerBox()之后,扫描程序对象将为null。

According to my observation the reason is when onClickScannerBox() is called one BarcodeScannerView object instance is initialized and when the onClickScannerBox() finishes and comes out of the method since it is in the onClick() method of another BarcodeScannerView object instance the scanner object gets null. 根据我的观察,原因是当onClickScannerBox()被调用时,一个BarcodeScannerView对象实例被初始化;当onClickScannerBox()完成并退出该方法时,因为它位于另一个BarcodeScannerView对象实例的onClick()方法中,所以扫描器对象被获取。空值。

I can simply correct this issue using static scanner object. 我可以使用静态扫描仪对象简单地解决此问题。 (The code is not provided here since the gets too long) I don't think having static references is the best approach for this problem. (由于太长了,所以这里没有提供代码)我不认为拥有静态引用是解决此问题的最佳方法。 Is there any approach to correct the issue without using any static references? 是否有任何方法可以在不使用任何静态引用的情况下更正此问题? Any suggestions are appreciated. 任何建议表示赞赏。

In your implementation there are two instances of your custom compound view comes into play, one is in the layout (activity layout) and other one is explicitly created one in the activity onCreate method. 在您的实现中,您将使用自定义复合视图的两个实例,一个在布局(活动布局)中,另一个在活动onCreate方法中显式创建。

barcodeScannerView = new BarcodeScannerView(this);
barcodeScannerView.setOnScannerListener(this);

You have set the listener to the explicitly created one which doesn't have clue about view used in the layout, simply they are two instances. 您已将侦听器设置为显式创建的侦听器,该侦听器不知道布局中使用的视图,只是它们是两个实例。 You should use the instance created (inflated) in the xml as follows. 您应该使用在xml中创建(膨胀)的实例,如下所示。

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);

    barcodeScannerView = (BarcodeScannerView) findViewById(R.id.barcode_scanner);
    barcodeScannerView.setOnScannerListener(this);
}

barcode_scanner should be the id you have given to the compound view used in the activity layout. barcode_scanner应该是您为活动布局中使用的复合视图指定的ID。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM