0

I am new to recylerView but have implemented one for a Uni project. The recylcer view works ok, It has a list with an imageView and a texView in each row. I use the same method to dynamically add an item to the list.

When I add the second item to the adapter.list the view seems to create a new list and then displays them both, with the first item on top. Here is a screenie of what the view looks like after I have added a few items:

Screenshot of overlapping list items in recyclerview

I've no idea why the view is doing this, I'm new to recycleViews.. I implemented a plain view which had items all added at once and that was okay, I don't know why this would happen. Any clues anyone? It's driving me nuts.

Things i've tried: Clearing the adapter.list and recreating the list: same behaviour. initialising the RecyclerView and recreating the list: same behaviour.

Thanks! Edit: row_layout.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardView"
android:layout_below="@+id/tvWelcome"
android:layout_width="320dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/activity_vertical_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
app:cardCornerRadius="@dimen/activity_vertical_margin"
app:cardElevation="@dimen/activity_vertical_margin" >


<!-- id was textView -->
<TextView
    android:id="@+id/txtRecycler"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_marginTop="10dp"
    android:layout_marginBottom="10dp"
    android:layout_marginLeft="16dp"
    android:layout_marginRight="30dp"

    android:text="First Clue will go here "
    android:textAppearance="?android:attr/textAppearanceMedium" />

<ImageView
    android:id="@+id/imgShowHTML"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:src="@android:drawable/ic_menu_info_details"
    android:layout_margin="16dp"
    android:layout_gravity="end"
    android:background="@color/colorAccent"
    android:layout_below="@+id/txtRecycler"/>

</android.support.v7.widget.CardView>

and the content_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="cave.mike.btle_de.MainActivity"
tools:showIn="@layout/activity_main">


<TextView
    android:id="@+id/tvTeamName"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="20dp"
    android:layout_margin="@dimen/layout_margin"
    android:text="Team Name"/>

<TextView
    android:id="@+id/tvWelcome"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/tvTeamName"
    android:textSize="@dimen/font_size"
    android:layout_margin="@dimen/layout_margin"
    android:layout_marginBottom="@dimen/activity_vertical_margin"
    android:text="@string/welcome_text"/>


<!-- MJC this holds and displays the list of clues as they are found -->
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/recyclerview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:scrollbars="vertical"
    android:layout_below="@+id/tvWelcome"
    />


<!-- Recycler View List-->
<include layout="@layout/row_layout"/>

</RelativeLayout>

And this is the recyclerview adapter on create:

    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    //Inflate the layout, initialize the View Holder
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
    MyViewHolder holder = new MyViewHolder(v);

    return holder;
}

RECYCLER Class:

public class Recycler_View_Adapter extends RecyclerView.Adapter<Recycler_View_Adapter.MyViewHolder> {

//private List list = Collections.emptyList();
private List list = new ArrayList();
Context context;
private int iCnt =0;

public Recycler_View_Adapter(List list, Context context) {
    this.list = list;
    this.context = context;


    setHasStableIds(false);

}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    //Inflate the layout, initialize the View Holder
    View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
    MyViewHolder holder = new MyViewHolder(v);

    return holder;
}


@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
    //Use the provided View Holder on the onCreateViewHolder method to populate the current row on the RecyclerView

    //List list = new ArrayList();
    if(list.get(position).toString() == null) {
        holder.recyclerText.setVisibility(View.GONE);
    }else {

        String s = "";

        if (list != null) {
            for (int i = 0; i <= list.size() - 1; i++) {
                s = list.get(i).toString();
                Log.d("onBindViewHolder", "List.item = " + String.valueOf(i) + " Desc: " + s);
            }
        }

        iCnt++;
        Log.d("onBindViewHolder", "icnt = " + String.valueOf(iCnt) + "POS = " + String.valueOf(position));

        String sDesc = "" + list.get(position);
        Log.d("onBindViewHolder", "Position = " + String.valueOf(position) + " DESC:: " + sDesc);

        holder.recyclerText.setText(sDesc);

    }

}


@Override
public int getItemCount() {
    //returns the number of elements the RecyclerView will display
    return list.size();
}

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}


// Insert a new item to the RecyclerView on a predefined position
public void insert(int position, String sDesc) {

    Log.d("BTLE DE", "RecyclerVIew Insert: position:" + String.valueOf(position) + "  Desc: "+ sDesc);

    list.add(position, sDesc);

    notifyItemInserted(position);
}


// Define listener member variable
private static OnItemClickListener listener;
// Define the listener interface
public interface OnItemClickListener {
    void onItemClick(View itemView, int position);
}

// MJC allows the Main (or parent) activity to define the listener - so bubbled up to main
public void setOnItemClickListener(OnItemClickListener listener) {
    this.listener = listener;
}


public void clearData() {
    Log.d("RecyclerView", "INSIDE clearData" );

    int size = this.list.size();
    if (size > 0) {
        for (int i = 0; i < size; i++) {
            this.list.remove(0);

            Log.d("RecyclerView", "INSIDE clearData.List.Remove" );
        }

        this.notifyItemRangeRemoved(0, size);
    }
}


public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

    public ImageView imgShowHTML;

    public TextView recyclerText;

    public MyViewHolder(final View itemView) {
        super(itemView);

        imgShowHTML = (ImageView) itemView.findViewById(R.id.imgShowHTML);
        recyclerText = (TextView) itemView.findViewById(R.id.txtRecycler);

        itemView.setOnClickListener(this);

        imgShowHTML.setOnClickListener(this);
        recyclerText.setOnClickListener(this);
}

    // onClick Listener for view
    @Override
    public void onClick(View v) {
        /* MJC Listener for image button*/
        // Triggers click upwards to the adapter on click
        if (listener != null)
            //only pass it up if button has been clicked
            if (v.getId() == imgShowHTML.getId()) {
                Toast.makeText(v.getContext(), "ITEM/ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
                listener.onItemClick(itemView, getLayoutPosition());
            }

    }


    @Override
    public boolean onLongClick(View v) { //must have long click support
        return false;
    }
}

}

Mike Cave
  • 127
  • 1
  • 4
  • 16
  • Can you post your xml, that doesn't seem like part of the RecyclerView unless you are doing something funky. – zgc7009 May 11 '16 at 13:13
  • done, thanks for looking – Mike Cave May 11 '16 at 13:51
  • Your problem is this `` at the bottom of content_main. That is adding a row_layout view to your parent layout. Your adapter will dynamically add views to your RecyclerView, you don't need to add one as a holder to your parent layout like that. – zgc7009 May 11 '16 at 13:53
  • So I don't need to include the row layout in the content? Recycler looks after it? Thanks, I'll give it a go... – Mike Cave May 11 '16 at 13:55
  • When I remove the row_layout.xml from the content main I dont see the recycler list. Do yo know where I add it to the layout? Thanks again. – Mike Cave May 11 '16 at 13:58
  • That's weird. Mind posting your adapter code? – zgc7009 May 11 '16 at 14:02
  • Will add recycler class, apologies for all the comments and logs and toasts, i've been trying to get to the bottom of my issue.... – Mike Cave May 11 '16 at 14:11

2 Answers2

2

You should not include row's layout directly as you got adapter to do that. You need to remove

<!-- Recycler View List-->
<include layout="@layout/row_layout"/>

line from your XML.

EDIT

What you enclosed as "adapter" is just one method out of it. You need to have whole proper adapter and that adapter must be connected with your recycler view and populated with dataset, otherwise it will not work incomplete.

Here's training documentation: https://developer.android.com/training/material/lists-cards.html#RecyclerView

Marcin Orlowski
  • 67,279
  • 10
  • 112
  • 132
  • When I remove it the screen is empty, do you know how I tell the adapter to use the row_layout? – Mike Cave May 11 '16 at 13:59
  • This is how I'm initialising the recyclerview: RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(this)); – Mike Cave May 11 '16 at 14:00
  • I've added my layout inflater in my question - thanks! – Mike Cave May 11 '16 at 14:05
  • My dataset is just a txtView in the row_layout and the imageView. I have created a list which is part of the adapter, then I add to the list.: private List list = new ArrayList(); Recycler_View_Adapter adapter = new Recycler_View_Adapter(list, getApplication()); – Mike Cave May 11 '16 at 14:26
  • I believe that it will be much more efficient for you to read some tutorials about recycler views and adapters now as you got too big knowledge gap and even we help you make your code working you will still not know how it works. Your former question was about persistent card visible on screen - this has been answered so you should accept the answer now. Then try doing any tutorial as I suggested (if you stuck ask new question). I believe that after that you will be able to fix your current code w/o any additional help. – Marcin Orlowski May 11 '16 at 14:32
  • all due respect, I did follow tutorials to get it working. I'm under time pressure so starting again from scratch is not possible unfortunately. Thanks though. Removing the row layout from my content_main just made the whole thing vanish. I DO inflate the row_layout when I create the Recyclerview..as shown above. – Mike Cave May 11 '16 at 14:35
  • Show how you connect recycler and adapter together – Marcin Orlowski May 11 '16 at 15:00
  • Hi guys. First off, THANKS for all your help. The main reason I was getting that behaviour WAS due to the fact the row_layout.xml was being included in content_main.xml, BUT also, when I was adding data to my list I was actually setting the content of the text view before adding it to the list. I did this initially as I started with a recyclerView which was filled all at once and not dynamically. It works as expected now. Thanks again, you are fantastic! – Mike Cave May 11 '16 at 15:40
1

Remove

<include layout="@layout/row_layout"/>

And use the adapter set to your recycler view to populate your list of items. Take a look to the official documentation here.

Here is few examples :

http://code.tutsplus.com/tutorials/getting-started-with-recyclerview-and-cardview-on-android--cms-23465 http://www.androidhive.info/2016/01/android-working-with-recycler-view/ http://www.vogella.com/tutorials/AndroidRecyclerView/article.html

Hope this help.

GuillaumeAgis
  • 3,535
  • 1
  • 18
  • 24
  • Thanks but I've looked at these before. My recycler view works but I keep getting a persistent artifact when I add a new item dynamically. – Mike Cave May 11 '16 at 14:08
  • I've posted the recycler view class and the initialise in ActivityMain and the row layout inflator.. thanks – Mike Cave May 11 '16 at 14:22
  • you might find your answer here : http://stackoverflow.com/questions/25914003/recyclerview-and-handling-different-type-of-row-inflation – GuillaumeAgis May 11 '16 at 14:27
  • I have made an edit. I access the RV data through the adapter list – Mike Cave May 11 '16 at 14:28