J'essaie de définir un texte sur un EditText
dans mon adaptateur personnalisé et j'obtiens cette pile:
public class ProductListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView productDescription, productSellingPrice, productFinalPrice; public ImageView removeProductIcon; public EditText productQuantity; private ProductItemManager productItemManager; public ProductListViewHolder(View itemView, ProductItemManager productItemManager) { super(itemView); productDescription = itemView.findViewById(R.id.productDescription); productSellingPrice = itemView.findViewById(R.id.productSellingPrice); productFinalPrice = itemView.findViewById(R.id.productFinalPrice); removeProductIcon = itemView.findViewById(R.id.removeProductIcon); productQuantity = itemView.findViewById(R.id.productQuantity); this.productItemManager = productItemManager; removeProductIcon.setOnClickListener(this); this.productChangeListener(); } private void productChangeListener() { productQuantity.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { Double quantity = Double.parseDouble(productQuantity.getText().toString()); productItemManager.setProductQuantity(getAdapterPosition(), quantity); } @Override public void afterTextChanged(Editable s) { } }); } @Override public void onClick(View v) { productItemManager.removeProduct(getAdapterPosition()); } }
Je ne sais pas quoi est faux, je mets le texte sur un TextView
exactement de la même manière et cela fonctionne très bien. J'ai regardé des forums et des articles et j'ai vu des gens avec des problèmes similaires, mais il semble qu'ils ne lient pas correctement la vue avec la propriété ViewHolder
de I ou essaient d'accéder à la
Ici c'est ma classe d'adaptateur personnalisée:
public class ProductListAdapter extends RecyclerView.Adapter<ProductListViewHolder>{ private List<Product> productList; private ProductItemManager productItemManager; public ProductListAdapter(List<Product> productList, ProductItemManager productItemManager) { this.productList = productList; this.productItemManager = productItemManager; } @NonNull @Override public ProductListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View productListView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.adapter_product_list, parent, false); return new ProductListViewHolder(productListView, productItemManager); } @Override public void onBindViewHolder(@NonNull ProductListViewHolder productListViewHolder, final int position) { Product product = productList.get(position); Double finalPrice = product.getSellingPrice() * product.getQuantity(); productListViewHolder.productDescription.setText(product.getDescription()); productListViewHolder.productSellingPrice.setText("un. " + Utils.doubleToReal(product.getSellingPrice())); productListViewHolder.productFinalPrice.setText(Utils.doubleToReal(finalPrice)); productListViewHolder.productQuantity.setText(Double.toString(product.getQuantity())); } @Override public int getItemCount() { return productList.size(); } }
Et ici c'est mon ViewHolder
java.lang.NullPointerException: Attempt to read from field 'android.support.v7.widget.ViewInfoStore android.support.v7.widget.RecyclerView.mViewInfoStore' on a null object reference at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:8194) at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8180) at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:8168) at android.support.v7.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1573) at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1519) at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:614) at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3812) at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:3225) at android.view.View.measure(View.java:17547) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436) at android.widget.LinearLayout.measureVertical(LinearLayout.java:722) at android.widget.LinearLayout.onMeasure(LinearLayout.java:613) at android.view.View.measure(View.java:17547) at android.widget.ScrollView.measureChildWithMargins(ScrollView.java:1260) at android.widget.FrameLayout.onMeasure(FrameLayout.java:436) at android.widget.ScrollView.onMeasure(ScrollView.java:337) at android.view.View.measure(View.java:17547) at android.support.constraint.ConstraintLayout.onMeasure(ConstraintLayout.java:1676) at android.view.View.measure(View.java:17547) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) at android.widget.FrameLayout.onMeasure(FrameLayout.java:436) at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:141) at android.view.View.measure(View.java:17547) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) at android.support.v7.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:400) at android.view.View.measure(View.java:17547) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) at android.widget.FrameLayout.onMeasure(FrameLayout.java:436) at android.view.View.measure(View.java:17547) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1436) at android.widget.LinearLayout.measureVertical(LinearLayout.java:722) at android.widget.LinearLayout.onMeasure(LinearLayout.java:613) at android.view.View.measure(View.java:17547) at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5535) at android.widget.FrameLayout.onMeasure(FrameLayout.java:436) at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2615) at android.view.View.measure(View.java:17547) at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2015) at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1173) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1379) at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1061) at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5885) at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767) at android.view.Choreographer.doCallbacks(Choreographer.java:580) at android.view.Choreographer.doFrame(Choreographer.java:550) at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.andro 02-21 14:14:29.702 1707-1707/com.android.inputmethod.latin E/RichInputConnection: Unable to connect to the editor to retrieve text. 02-21 14:14:31.705 1707-1707/com.android.inputmethod.latin E/RichInputConnection: Unable to connect to the editor to retrieve text. 02-21 14:14:33.706 1707-1707/com.android.inputmethod.latin E/RichInputConnection: Unable to connect to the editor to retrieve text. 02-21 14:14:35.709 1707-1707/com.android.inputmethod.latin E/RichInputConnection: Unable to connect to the editor to retrieve text.
5 Réponses :
Vous devez appeler l'auditeur défini sur TextWatch, une fois que vous l'avez vu lié. Dans onBindViewHolder
appelez votre enregistrement.
...... @Override public void onBindViewHolder(@NonNull ProductListViewHolder productListViewHolder, final int position) { ...... productListViewHolder.productChangeListener(); ....
Et je suggère également de changer de fonction avec les écouteurs d'enregistrement. Sans création de centaines d'articles, lors de la création de RecyclerView
.
Selon un article que j'ai lu, déclarer les auditeurs en dehors du détenteur de la vue est une mauvaise pratique. Est-ce vrai? L'auteur a recommandé d'implémenter l'écouteur sur le visualiseur, puis de créer ma propre interface qui sera ensuite étendue par mon activité et là, la méthode de mon interface devrait être remplacée. C'est ce que j'ai fait sur le ViewHolder pour l'événement de clic et cela a bien fonctionné.
Le TextWatcher
va être appelé à chaque fois que le texte qu'il regarde change. Cela signifie non seulement que les modifications utilisateur appelleront l'observateur (bien), mais chaque fois qu'un détenteur de vue est rebondi, l'observateur sera également appelé (pas si bon). Cela signifie également que productItemManager.setProductQuantity ()
sera appelé inutilement. (Je dis "inutilement" mais, peut-être, c'est quelque chose que vous avez l'intention de se produire.)
Une façon d'éviter l'observateur de texte lorsqu'un détenteur de vue est lié est de définir un View.OnFocusChangeListener () code> sur
productQuantity
qui s'appliquera et supprimera l'observateur de texte lorsque le focus est gagné ou perdu pour le champ. En d'autres termes, l'observateur de texte ne sera actif que pendant la modification de EditText
.
productQuantity.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { productQuantity.addTextChangedListener(textWatcher); } else { productQuantity.removeTextChangedListener(textWatcher); } } });
Cela peut ne pas résoudre le problème que vous rencontrez , mais cela éliminera le travail inutile qui peut être un facteur contributif.
Je pense que publier setProductQuantity ()
aidera quelqu'un à aller à la racine du problème.
Je voudrais être d'accord avec l'implémentation proposée par @Cheticamp. D'après mon expérience, l'écouteur de changement de texte peut se déclencher dans différentes situations où il n'était pas censé être appelé. Les EditText
sont souvent impliqués dans la correction automatique des mots et la fourniture de suggestions et peuvent être appelés lors de l'initialisation. Par conséquent, je voudrais vous recommander de mettre ce qui suit dans votre déclaration EditText
dans le fichier de mise en page.
private void productChangeListener() { productQuantity.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { String editTextContent = productQuantity.getText().toString(); if(editTextContent != null && editTextContent.trim().length() > 0) { Double quantity = Double.parseDouble(productQuantity.getText().toString()); productItemManager.setProductQuantity(getAdapterPosition(), quantity); } } @Override public void afterTextChanged(Editable s) { } }); }
Et au lieu d'utiliser setOnFocusChangeListener
, vous pourriez envisager d'avoir une vérification null
dans votre observateur de texte comme suit.
android:inputType="textNoSuggestions"
J'espère que cela vous aidera!
Il y a quelques éléments qui nécessitent votre attention:
Avoir EditText dans RecyclerViews (et les listes en général) n'est généralement pas une bonne idée, à cause de leur UX. Vous devez soit empêcher l'utilisateur de faire défiler la liste, soit effectuer une action basée sur le défilement, pour rendre les choses plus fluides (car ils peuvent être en train de saisir quelque chose).
Il y a un problème très important dans le code et c'est une référence au "TextWatcher" du texte d'édition qui est recyclé. Vous devez supprimer l'observateur de texte lorsqu'une vue est en cours de recyclage. Que se passe-t-il si vous ne supprimez pas TextWatcher? Comme ce n'est pas comme OnClickListener
(ce n'est pas une fonction set
et c'est une fonction add
), chaque fois que vos cellules sont recréées, un le nouvel observateur de texte est ajouté à EditText avec ses références à l'ancien ViewHolder.
Pour résoudre ce problème, vous devez ajouter une méthode à votre ViewHolder pour dissocier tout ce qu'il contient:
@Override public void onViewRecycled(ProductListViewHolder productListViewHolder) { super.onViewRecycled(holder); productListViewHolder.unbind(); }
Ensuite, vous pouvez utiliser le méthode onViewRecycled pour savoir quand votre vue est recyclée et supprimer TextWatcher:
public class ProductListViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView productDescription, productSellingPrice, productFinalPrice; public ImageView removeProductIcon; public EditText productQuantity; private ProductItemManager productItemManager; private TextWatcher textWatcher; public ProductListViewHolder(View itemView, ProductItemManager productItemManager) { super(itemView); productDescription = itemView.findViewById(R.id.productDescription); productSellingPrice = itemView.findViewById(R.id.productSellingPrice); productFinalPrice = itemView.findViewById(R.id.productFinalPrice); removeProductIcon = itemView.findViewById(R.id.removeProductIcon); productQuantity = itemView.findViewById(R.id.productQuantity); this.productItemManager = productItemManager; removeProductIcon.setOnClickListener(this); this.productChangeListener(); } private void productChangeListener() { textWatcher = new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { Double quantity = Double.parseDouble(productQuantity.getText().toString()); productItemManager.setProductQuantity(getAdapterPosition(), quantity); } @Override public void afterTextChanged(Editable s) { } }; productQuantity.addTextChangedListener(textWatcher); } public void unbind(){ productQuantity.removeTextChangedListener(textWatcher); } @Override public void onClick(View v) { productItemManager.removeProduct(getAdapterPosition()); } }
//update this line in your code, you will get your answer :) productListViewHolder.productQuantity.setText(Double.toString(productList.get(position).getQuantity()));
Pouvez-vous expliquer cela davantage? Qu'est-ce qui n'allait pas avec la ligne d'origine, qu'avez-vous fait pour qu'elle fonctionne? Gardez à l'esprit que le PO doit pouvoir apprendre de votre amélioration et non simplement la copier
Récemment, j'avais fait face à ce même problème, et je l'ai résolu en accédant directement à l'empoisonnement de la liste principale.
Veuillez ajouter toutes les explications à la réponse, pas à la section des commentaires. De plus, expliquez plus en détail ce que vous avez changé et pourquoi - qu'est-ce qui n'allait pas avec le code d'origine?
Copie possible de Qu'est-ce qu'une NullPointerException, et comment puis-je le réparer?
post plein stacktrace non seulement erreur
J'ai modifié la question en ajoutant la pile complète.
Donc, je testais juste l'application et j'ai découvert que le problème ne semble se produire que lorsque j'ai un écouteur TextWatcher dans le constructeur de ProductListViewHolder. J'apprécierais toute réflexion à ce sujet.
Ce serait utile si vous publiez le code de la classe ProductItemManager car c'est de là que ce bogue semble provenir.
@GuilhermeRamalho pouvez-vous s'il vous plaît vérifier ma réponse et voir si cela aide? Merci :)
@GuilhermeRamalho De la trace de la pile, il semble que vous imbriquez 2 recycler View, le trou à l'intérieur d'un ScrollView ... pourriez-vous s'il vous plaît poster le code source de R.layout.adapter_product_list? le deuxième recyclerView semble manquer un adaptateur et un layoutManager ...