Data update problem of Android's ListView

Introduction to this section:

We have learned some basic usages of ListView before, but if you are careful, you may find that our data is defined at the beginning and is static, but in actual development, our data often changes dynamically, such as I added or deleted a certain column, so the data displayed in the list should also be updated synchronously, so in this section we will discuss the issue of ListView data update, including all updates, and one of them, then start this section!


1. Write a normal demo first

Okay, let’s write a normal demo first, and then we’ll adjust it slowly:

Entity class: Data.java :

/**
 * Created by Jay on 2015/9/21 0021.
 */
public class Data {
    private int imgId;
    private String content;

    public Data() {}

    public Data(int imgId, String content) {
        this.imgId = imgId;
        this.content = content;
    }

    public int getImgId() {
        return imgId;
    }

    public String getContent() {
        return content;
    }

    public void setImgId(int imgId) {
        this.imgId = imgId;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

Activity layout and list item layout :

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/list_one"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

item_list.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/img_icon"
        android:layout_width="56dp"
        android:layout_height="56dp"/>

    <TextView
        android:id="@+id/txt_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="10dp"
        android:textSize="18sp" />

</LinearLayout>

Implementation of custom BaseAdapter: MyAdapter.java :

/**
 * Created by Jay on 2015/9/21 0021.
 */
public class MyAdapter extends BaseAdapter {

    private Context mContext;
    private LinkedList<Data> mData;

    public MyAdapter() {}

    public MyAdapter(LinkedList<Data> mData, Context mContext) {
        this.mData = mData;
        this.mContext = mContext;
    }

    @Override
    public int getCount() {
        return mData.size();
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
        if(convertView == null){
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_list,parent,false);
            holder = new ViewHolder();
            holder.img_icon = (ImageView) convertView.findViewById(R.id.img_icon);
            holder.txt_content = (TextView) convertView.findViewById(R.id.txt_content);
            convertView.setTag(holder);
        }else{
            holder = (ViewHolder) convertView.getTag();
        }
        holder.img_icon.setImageResource(mData.get(position).getImgId());
        holder.txt_content.setText(mData.get(position).getContent());
        return convertView;
    }

    private class ViewHolder{
        ImageView img_icon;
        TextView txt_content;
    }
    
}

Writing of MainActivity.java :

public class MainActivity extends AppCompatActivity {

    private ListView list_one;
    private MyAdapter mAdapter = null;
    private List<Data> mData = null;
    private Context mContext = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = MainActivity.this;
        bindViews();
        mData = new LinkedList<Data>();
        mAdapter = new MyAdapter((LinkedList<Data>) mData,mContext);
        list_one.setAdapter(mAdapter);
    }

    private void bindViews(){
        list_one = (ListView) findViewById(R.id.list_one);
    }

}

It can run. After running, we find that our page does not have any data, and it is a vast expanse of whiteness. This kind of user experience is not good. We can call a setEmptyView(View) method of ListView . When the ListView data is empty, Display a corresponding View. In addition, I found that this method is very strange. The dynamically added View is invalid. You can only add the View that you want to display when the ListView has no data in the layout file where the ListView is located. In addition, use this setEmptyView to set the View , it won’t be displayed when loading, it’s amazing...For example, here is a TextView without data when there is no data, part of the code is as follows:

<TextView
        android:id="@+id/txt_empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="15pt"
        android:textColor="#000000"/>
        
txt_empty = (TextView) findViewById(R.id.txt_empty);    
txt_empty.setText("暂无数据~");
list_one.setEmptyView(txt_empty);

Of course, in addition to this method, we can also define a layout with the same size as the ListView, and then set, android:visibility="gone", to judge the size of the mData collection in the Java code. If ==0, it means there is no data , let this layout be displayed, and let this layout be hidden when there is data~


2. Add a record

Okay, let's get an add button, and add a record without pressing it~

Running effect diagram:

Code

Define a method in our custom BaseAdapter, the content of the method is as follows:

public void add(Data data) {
    if (mData == null) {
        mData = new LinkedList<>();
    }
    mData.add(data);
    notifyDataSetChanged();
}

Then add a button to the layout, and then set the event, the code is as follows:

private Button btn_add;
btn_add = (Button) findViewById(R.id.btn_add);
btn_add.setOnClickListener(this);

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.btn_add:
            mAdapter.add(new Data(R.mipmap.ic_icon_qitao,"给猪哥跪了~~~ x " + flag));
            flag++;
            break;
    }
}

Hey, it’s done, adding data is as simple as that~, if you want to insert it into a specific position, it’s okay, let’s write another method in the Adapter class:

//Add an element to a specific position 
public void add(int position,Data data){ 
    if (mData == null) { 
        mData = new LinkedList<>(); 
    } 
    mData.add(position,data); 
    notifyDataSetChanged() ; 
}

Then add a button and write an event:

private Button btn_add2; 
btn_add2 = (Button) findViewById(R.id.btn_add2); 
btn_add2.setOnClickListener(this); 

case R.id.btn_add2: 
//position starts from 0 
mAdapter.add(4,new Data(R .mipmap.ic_icon_qitao, "Kneel for Brother Pig~~~ x " + flag)); 
break;

Running effect diagram:

You can see that our ninth item is inserted into the fifth position~


3. Delete an item

Similarly, we write two methods, one directly deletes the object, and the other deletes according to the cursor:

public void remove(Data data) {
    if(mData != null) {
        mData.remove(data);
    }
    notifyDataSetChanged();
}

public void remove(int position) {
    if(mData != null) {
        mData.remove(position);
    }
    notifyDataSetChanged();
}

Then add two Buttons and call these two methods:

case R.id.btn_remove:
    mAdapter.remove(mData_5);
    break;
case R.id.btn_remove2:
    mAdapter.remove(2);
    break;

Running effect diagram :

We can see from the picture that the fifth item has been removed, and then click the cursor to delete the data, and the third item has been deleted!


4. Remove all records:

This is simpler, just call the clear method directly! The method code is as follows:

public void clear() {
    if(mData != null) {
        mData.clear();
    }
    notifyDataSetChanged();
}

5. Update a certain record

If you are careful, you should have noticed that after the data modification operation, a notifyDataSetChanged() will be called;  at first I thought:

notifyDataSetChanged() will redraw all the actual items on the interface once, which will affect the UI performance. If the amount of data is large, but I change one item, I have to redraw all the items. This is definitely unreasonable, right? Ever since, I used a silly way to modify the value of a control in an Item. I wrote such a piece of code in Java code:

private void updateListItem(int postion,Data mData){
    int visiblePosition = list_one.getFirstVisiblePosition();
    View v = list_one.getChildAt(postion - visiblePosition);
    ImageView img = (ImageView) v.findViewById(R.id.img_icon);
    TextView tv = (TextView) v.findViewById(R.id.txt_content);
    img.setImageResource(mData.getImgId());
    tv.setText(mData.getContent());
}

After discussing with friends in the group, I found that I was wrong :

The notifyDataSetChanged() method will determine whether re-rendering is required. If the current item does not need to be re-rendered, it will not be re-rendered. If the state of an Item changes, it will cause the View to be redrawn, but not all Items will be redrawn. , but the Item whose View state changes! So we can directly notifyDataSetChange() method, of course, it’s okay to know one more method above~

Guess you like

Origin blog.csdn.net/leyang0910/article/details/131073824