Why isn't an Adapter with cached buttons worki

2019-09-02 02:25发布

Edit3: Exchanged the code for a complete runnable test case.

Edit2: Added some code that updates the number of buttons after five seconds. When this happens the buttons becomes unclickable no matter what layout you use.

Edit1: It seems this is depending on the Layout used for the ListView. I will investigate further.

I want to create the buttons once, i.e. cache them. I can't use the provided convertView and edit it for various reasons (every row will in the end contain a couple of components, all created by another framework).

If I create an Adapter like below, which seems very reasonable and imo should work, only buttons that have been outside the ListView, and are scrolled back in, are clickable.

It seems the button's clickable area isn't set correctly on first display. Can anyone explain why?

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;

public class TestActivity extends Activity
{
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        final ListView listView = new ListView(this);

        final ArrayList<View> cachedButtons = new ArrayList<View>(Arrays.asList(new View[20]));

        listView.setAdapter(new BaseAdapter() {
            public View getView(int position, View convertView, ViewGroup parent)
            {
                if (cachedButtons.get(position) == null) {
                    Button b = new Button(parent.getContext());
                    b.setText("Button " + position);
                    b.setClickable(true);
                    cachedButtons.set(position, b);
                }
                return cachedButtons.get(position);
            }

            public int getCount() { return cachedButtons.size(); }
            public Object getItem(int position) { return null; }
            public long getItemId(int position) { return position; }
        });

        // Add a new button after five seconds
        new Timer().schedule(new TimerTask() {
            public void run()
            {
                runOnUiThread(new Runnable() {
                    public void run()
                    {
                        cachedButtons.addAll(Arrays.asList(new View[1])); // Add one more
                        ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
                        Toast.makeText(listView.getContext(), "Now you can't press the buttons anymore", 0).show();
                    }
                });
            }
        }, 5000);

        // Doesn't work with these lines
        LinearLayout layout = new LinearLayout(this);
        layout.addView(listView);
        setContentView(layout);

        // Works with this, so no Layout works.
        //setContentView(layout);
    }
}

2条回答
可以哭但决不认输i
2楼-- · 2019-09-02 03:15

I think Android is reusing your views so that is causing you problems .I suggest you use a view holder .It is a static class that holds the view for you.See this tutorial

查看更多
地球回转人心会变
3楼-- · 2019-09-02 03:21

The answer was quite simple, yet eluded me for many hours. Just override getItemViewType and the views won't be recycled. At least it seems to work for now. I still find the JavaDocs confusing on this.

public int getItemViewType(int position)
{
    return AdapterView.ITEM_VIEW_TYPE_IGNORE;
}
查看更多
登录 后发表回答