2017-06-30 2 views
2

Je crée une vue composée personnalisée dans android qui contient deux TextView dans une disposition relative. Il y a deux classes, l'une est BarcodeScannerView qui est la vue composée et une autre activité qui utilise l'affichage personnalisé. Le code est comme suit.Les écouteurs d'événements de vue personnalisée Android ne fonctionnent pas correctement sans référence statique

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

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); 
} 

} 

La question est quand je l'appelle la méthode onClick() de la classe BarcodeScannerView donne une exception point zéro.

java.lang.NullPointerException: tentative d'invoquer la méthode de l'interface 'void [packagename] ScannerListener.onClickScannerBox de $()' sur une référence d'objet null

Dans le débogage I remarqué que, lorsque le onClickScannerBox() est appelée, l'objet scanner est initialisé. Mais une fois onClickScannerBox() exécuté dans BarcodeScannerView, l'objet scanner devient nul. Selon mon observation la raison est lorsque onClickScannerBox() est appelée une instance d'objet BarcodeScannerView est initialisée et lorsque onClickScannerBox() se termine et sort de la méthode car il est dans la méthode onClick() d'une autre instance d'objet BarcodeScannerView l'objet scanner devient nul.

Je peux simplement corriger ce problème en utilisant un objet scanner statique. (Le code n'est pas fourni ici car le délai est trop long) Je ne pense pas que l'utilisation de références statiques soit la meilleure approche pour ce problème. Y at-il une approche pour corriger le problème sans utiliser de références statiques? Toutes les suggestions sont appréciées.

Répondre

0

Dans votre implémentation, deux instances de votre vue composée personnalisée entrent en jeu, l'une est dans la disposition (disposition d'activité) et l'autre est explicitement créée dans la méthode onCreate.

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

Vous avez défini l'auditeur à celui créé explicitement qui n'a pas la moindre idée de vue utilisé dans la mise en page, tout simplement, ils sont deux instances. Vous devriez utiliser l'instance créée (gonflée) dans le fichier XML comme suit.

@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 devrait être l'identifiant que vous avez donné à la vue composé utilisé dans la mise en page d'activité.