简体   繁体   English

更新到API 27后,RecyclerView Adapter遇到困难

[英]A difficulty with RecyclerView Adapter after update to API 27

Everything was fine until I updated Sdk Version to 27. It says here that ViewHolder views must not be attached when created. 一切正常,直到我将Sdk版本更新为27。它表示在创建ViewHolder视图时不得附加它。 But the attachToRoot parameter in my LayoutInflater is already set 'true'. 但是我的LayoutInflater中的attachToRoot参数已经设置为“ true”。 Please explain me what could have caused this problem? 请向我解释可能导致此问题的原因? Logcat : Logcat

06-02 11:40:15.669 22801-22801/com.bestworldgames.bestwordgame E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.bestworldgames.bestwordgame, PID: 22801
java.lang.IllegalStateException: ViewHolder views must not be attached when created. Ensure that you are not passing 'true' to the attachToRoot parameter of LayoutInflater.inflate(..., boolean attachToRoot)
at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6687)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5869)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5752)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5748)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2232)
at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:556)
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.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
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:18788)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:141)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
at android.view.View.measure(View.java:18788)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1216)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)

Here is my RecyclerView Adapter : 这是我的RecyclerView适配器

public class GameTableAdapter extends RecyclerView.Adapter<GameTableAdapter.ViewHolder> {


private ArrayList<Litera> literas;
private LayoutInflater mInflater;
private Map<Integer, Integer> hashMap;
private Context context;
private ArrayList<Button> adapterItems;
private View mainView;
private int itemSize;

public GameTableAdapter(Context context, ArrayList<Litera> literas, Map<Integer, Integer> hashMap, int itemSize) {
    this.mInflater = LayoutInflater.from(context);
    this.literas = literas;
    this.hashMap = hashMap;
    this.context = context;
    this.adapterItems = new ArrayList<>();
    this.itemSize = itemSize;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = mInflater.inflate(R.layout.but_item, parent, false);
    parent.removeView(view);
    parent.addView(view);
    mainView = parent;
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
    char mChar = literas.get(position).getCharValue();
    holder.item.setText(String.valueOf(mChar));
    if (this.hashMap.containsKey(position) && (hashMap.get(position)!=null)) {
        setImg(hashMap.get(position), holder.item);
        holder.item.setTextColor(context.getResources().getColor(R.color.colorWhite));
    }
}

@Override
public int getItemCount() {
    return literas.size();
}

public class ViewHolder extends RecyclerView.ViewHolder {
    Button item;
    ViewHolder(View itemView) {
        super(itemView);
        item = (Button) itemView.findViewById(R.id.item);
        item.setLayoutParams(new RecyclerView.LayoutParams(itemSize, itemSize));
        item.setTextSize(TypedValue.COMPLEX_UNIT_PX,(float)itemSize/2);
        adapterItems.add(item);
    }

}

public Litera getItem(int id) {
    return literas.get(id);
}

public Button getButItem(int id) {
    return adapterItems.get(id);
}

public View getMainView() {
    return mainView;
}

public void animateItem(int id) {
    adapterItems.get(id).setVisibility(View.INVISIBLE);
    adapterItems.get(id).setVisibility(View.VISIBLE);
}

}

in Fragment : 片段中

    recyclerView = (TouchableRecyclerView) rootView.findViewById(R.id.rv_chars);

... ...

public void setUpAdapter() {
        numberOfColumns = col;
        int itemSize = screenWidth / numberOfColumns;
        recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), numberOfColumns));
        adapter = new GameTableAdapter(getActivity(), literas, hashMapAllColors, itemSize);
        recyclerView.setAdapter(adapter);
        recyclerView.setNestedScrollingEnabled(false);
        recyclerView.setOnTouchListener(this);
    }

TouchableRecyclerView.java TouchableRecyclerView.java

public class TouchableRecyclerView extends RecyclerView {
    public TouchableRecyclerView(Context context) {
        super(context);
    }

    public TouchableRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public TouchableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public boolean performClick() {
        return super.performClick();
    }

}

in xml : 在xml中

 <com.bestworldgames.bestwordgame.widgets.TouchableRecyclerView
        android:id="@+id/rv_chars"
        android:layout_below="@+id/tapped_word"
        android:paddingLeft="5dp"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:overScrollMode="never"
        android:clickable="true"
        android:focusable="true"
        android:longClickable = "false">

    </com.bestworldgames.bestwordgame.widgets.TouchableRecyclerView>

but_item.xml but_item.xml

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/item"
    android:paddingRight="6dp"
    android:paddingBottom="8dp"
    android:animateLayoutChanges="true"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:background="@drawable/button_color_1"
    android:longClickable="false"
    android:clickable="false"
    android:focusable="false">
</Button>

This error occurs after working constructor public ViewHolder(View itemView) and before method onBindViewHolder(ViewHolder holder, final int position) . 在工作构造函数public ViewHolder(View itemView) ,在方法onBindViewHolder(ViewHolder holder, final int position)之前,将发生此错误。 That's all I can say at the moment. 目前,我只能说这些。

Try this: The parent.addView() method used here attach the view to the parent, so the problem aren't onCreateItemViewHolder custom implementation. 试试看:这里使用的parent.addView()方法将视图附加到父视图,因此问题不在onCreateItemViewHolder定制实现上。

override onCreateMyViewHolder method into custom adapter like the others 将onCreateMyViewHolder方法覆盖到其他自定义适配器中

 public class MyViewHolder extends RecyclerView.ViewHolder {
    public  Button item;

    public MyViewHolder(View view) {
        super(view);
        item = (Button) itemView.findViewById(R.id.item);
    item.setLayoutParams(new RecyclerView.LayoutParams(itemSize, itemSize));
    item.setTextSize(TypedValue.COMPLEX_UNIT_PX,(float)itemSize/2);
    adapterItems.add(item);
    }
}

Overide onCreate viewHolder like below: 覆盖onCreate viewHolder,如下所示:

@Override
public MyViewHolder onCreateMyViewHolder (ViewGroup parent) {

LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View mView= inflater.inflate(R.layout.but_item, parent, false);


return new MyViewHolder (mView);
}

Thanks Jarvis_J for helping me solve my problem! 感谢Jarvis_J帮助我解决了问题! The solution is to set return type of overriding method by refer to a class. 解决方案是通过引用一个类来设置重写方法的返回类型。

Instead of: 代替:

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = mInflater.inflate(R.layout.but_item, parent, false);
    parent.removeView(view);
    parent.addView(view);
    mainView = parent;
    return new ViewHolder(view);
}

I had to do it: 我不得不这么做:

@Override
public GameTableAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    View view = inflater.inflate(R.layout.but_item, parent, false);
    mainView = parent;
    return new GameTableAdapter.ViewHolder(view);
}

And there's really no need to be parent.removeView(view) parent.addView(view) . 而且,实际上没有必要成为parent.removeView(view) parent.addView(view)

I hope it'll help someone! 希望对您有所帮助!

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

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