Ошибка установки текста в EditText внутри метода onBindViewHolder RecyclerView - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь установить текст в EditText внутри моего пользовательского адаптера, и я получаю этот стек:

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.

Я не уверен, что не так, я устанавливаю текстдо TextView точно так же и работает нормально.Я просмотрел форумы и статьи и видел людей с похожими проблемами, но, похоже, они либо не связывают представление со свойством I ViewHolder правильно, либо пытаются получить доступ к

.Класс адаптера:

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

А вот и мой ViewHolder

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

Ответы [ 5 ]

0 голосов
/ 06 марта 2019
 //update this line in your code, you will get your answer :) 

productListViewHolder.productQuantity.setText(Double.toString(productList.get(position).getQuantity()));
0 голосов
/ 05 марта 2019

Есть несколько вещей, которые требуют вашего внимания:

  1. Наличие EditText в RecyclerViews (и списках в целом), как правило, не очень хорошая идея, из-за их UX.Вы должны либо запретить пользователю прокручивать список, либо выполнить какое-либо действие на основе прокрутки, чтобы сделать вещи более плавными (поскольку они могут вводить что-то).

  2. Естьочень важная проблема в коде, и это ссылка на «TextWatcher» текста редактирования, который перерабатывается.Вам нужно удалить наблюдателя текста, пока представление перерабатывается.Что произойдет, если вы не удалите TextWatcher?Так как он не похож на OnClickListener (это не функция set и функция add), каждый раз, когда ваши ячейки воссоздаются, в EditText добавляется новый наблюдатель get, со ссылками на старый ViewHolder..

Чтобы исправить это, вам нужно добавить метод в ViewHolder, чтобы отменить привязку любого содержимого, которое он содержит:

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

Затем вы можете использовать RecyclerView's onViewRecycled способ узнать, когда ваш вид подвергается переработке, и удалить TextWatcher:

@Override
    public void onViewRecycled(ProductListViewHolder productListViewHolder) {
        super.onViewRecycled(holder);
        productListViewHolder.unbind();
    }
0 голосов
/ 28 февраля 2019

TextWatcher будет вызываться каждый раз, когда текст, который он просматривает, изменяется.Это не только означает, что пользовательские правки будут вызывать наблюдателя (хорошо), но каждый раз, когда держатель представления восстанавливается, наблюдатель также будет вызываться (не так хорошо).Это также означает, что productItemManager.setProductQuantity() будет вызываться без необходимости.(Я говорю «излишне», но, может быть, это то, что вы намереваетесь случиться.)

Один из способов избежать наблюдателя текста, когда держатель представления связан, - установить View.OnFocusChangeListener() на productQuantityкоторый будет применять и удалять наблюдателя текста, когда фокус получен или потерян для поля.Другими словами, наблюдатель текста будет активен только во время редактирования EditText.

productQuantity.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if (hasFocus) {
            productQuantity.addTextChangedListener(textWatcher);
        } else {
            productQuantity.removeTextChangedListener(textWatcher);
        }
    }
});

Это может не решить вашу проблему, но устранит ненужную работу, которая может бытьспособствующий фактор.

Я думаю, что публикация setProductQuantity() поможет кому-то разобраться в корне проблемы.

0 голосов
/ 04 марта 2019

Я хотел бы согласиться с реализацией, предложенной @Cheticamp.Исходя из моего опыта, слушатель изменения текста может срабатывать в разных ситуациях, когда он не должен был вызываться.EditText часто участвует в автокоррекции слов и предоставлении предложений и может быть вызван во время инициализации.Поэтому я хотел бы порекомендовать вам добавить следующее в ваше объявление EditText в файле макета.

android:inputType="textNoSuggestions"

И вместо использования setOnFocusChangeListener вы можете рассмотреть возможность проверки null в вашем наблюдателе текста, как показано ниже.

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) {

        }
    });
}

Надеюсь, это поможет!

0 голосов
/ 27 февраля 2019

Вы должны вызывать прослушиватель, установленный на TextWatch, как только вы увидите привязанный.В onBindViewHolder позвоните по вашей регистрации.

......
@Override
public void onBindViewHolder(@NonNull ProductListViewHolder productListViewHolder, final int position) {
......
productListViewHolder.productChangeListener();
....

И я также предлагаю изменить функцию регистрации слушателей.Без создания сотен предметов, при создании RecyclerView.

...