Android Listview ArrayAdapter带有两个布局

4

我对Android还比较陌生。在下面的类中,从数据库检索数据并在ListView中显示,该ListView有两种不同的布局。 尽管它的功能符合预期,但问题是滚动不流畅,因为textviews一遍又一遍地被赋值。我无法弄清楚如何仅分配一次。请有人帮我解决这个问题。 提前致谢。对于代码,我很抱歉,我知道它看起来很糟糕。

public class FragmentVerses extends ListFragment {

Typeface font;
ViewHolder viewHolder = new ViewHolder();
ViewHolderHeader viewHolderHeader = new ViewHolderHeader();
DatabaseHelper db;

public List<VersesModel> verses;
public List<ChapterModel> chapterName;
ArrayAdapter<VersesModel> adapter;

public FragmentVerses() {
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.verses_fragment, container, false);

    db = new DatabaseHelper(getActivity());
    try {
        db.createDatabase();
    } catch (IOException e) {
        Toast.makeText(getActivity(), "Error Creating Database", Toast.LENGTH_LONG)
                .show();
    }

    verses = db.getVerses(" WHERE " + getActivity().getIntent().getStringExtra(MainActivity.CONDITION));
    chapterName = db.getChapter();
    adapter = new MyListAdapter();
    setListAdapter(adapter);
    return view;
}

private class MyListAdapter extends ArrayAdapter<VersesModel> {
    public MyListAdapter() {
        super(getActivity(), R.layout.verses_custom_list, verses);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        VersesModel currentVerse = verses.get(position);
        if (convertView == null) {
            convertView = getActivity().getLayoutInflater().inflate(
                    R.layout.verses_custom_list, parent, false);
            font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");
            viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse);
            viewHolder.textViewTranslation = (TextView) convertView.findViewById(R.id.textView_VerseTranslation);
            viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_verseNumber);
            viewHolder.textView.setTypeface(font);
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.versesImageView);
            convertView.setTag(viewHolder);
        } else {
            if (currentVerse.getVerseNumber() != 0) {
                convertView = getActivity().getLayoutInflater().inflate(
                        R.layout.verses_custom_list, parent, false);
                viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse);
                viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_verseNumber);
                viewHolder.textViewTranslation = (TextView) convertView.findViewById(R.id.textView_VerseTranslation);
                viewHolder.textView.setTypeface(font);
                viewHolder.textView.setText(currentVerse.getVerseText() + "", true);
                viewHolder.textViewTranslation.setText(currentVerse.getVerseTranslation());
                viewHolder.nView.setText(currentVerse.getVerseNumber() + "");
                convertView.setTag(viewHolder);
            } else {
                convertView = getActivity().getLayoutInflater().inflate(
                        R.layout.verses_custom_list_header, parent, false);
                ChapterModel chapterModel = chapterName.get(currentVerse.getChapterNumber() - 1);
                if (viewHolderHeader.textViewChapter == null)    viewHolderHeader.textViewBismillah = (TextView) convertView.findViewById(R.id.textView_Verse_Bismillah);
                    viewHolderHeader.textViewChapter = (TextView) convertView.findViewById(R.id.textView_Verse_ChapterName);
                    viewHolderHeader.textViewChapter.setText("سورة  " + chapterModel.getChapterText());
                    viewHolderHeader.textViewBismillah.setTypeface(font);
                    viewHolderHeader.textViewChapter.setTypeface(font);
                } else {
                    viewHolderHeader = (ViewHolderHeader) convertView.getTag();
                }
                convertView.setTag(viewHolderHeader);

            }
        }
        return convertView;
    }
}

为什么你要多次填充视图?你只需要填充一次,系统会根据需要回收视图。这是导致列表运行缓慢的原因。请查阅使用ArrayAdapters创建列表视图。 - ichthyocentaurs
4个回答

5
我知道这篇文章有点旧了,但为了将来的参考... 在这种情况下,您应该使用ViewHolder模式。
如果您想使用2个布局,只需创建两个ViewHolder,并在getView方法中在它们之间切换。
与被接受的答案非常相似,但性能更好。
声明视图类型。
private final int VIEW_TYPE_EXAMPLE = 0;
private final int VIEW_TYPE_EXAMPLE_TWO = 1;

按照您上面声明的类型返回。

@Override
public int getViewTypeCount() {
    return 2;
}

当项目位于位置X时,切换返回视图类型。在这种情况下,只有当项目是列表中的第一个时才更改类型。

@Override
public int getItemViewType(int position) {
    return (position == 0) ? VIEW_TYPE_EXAMPLE : VIEW_TYPE_EXAMPLE_TWO;
}

创建与您的布局相匹配的视图持有者。它们将保存您的数据。
class SecondViewHolder {
            TextView mDate;
            TextView mDescription;
            TextView mObservations;

            public SecondViewHolder(View view) {
                mDate = (TextView) view.findViewById(R.id.txt_date);
                mDescription = (TextView) view.findViewById(R.id.txt_description);
                mObservations = (TextView) view.findViewById(R.id.txt_observations);
            }
        }

class FirstViewHolder {
            ImageView mPhoto;
            TextView mName;
            TextView mAge;

            public FirstViewHolder(View view) {
                mPatientPhoto = (ImageView)view.findViewById(R.id.img_photo);
                mPatientName = (TextView)view.findViewById(R.id.txt_name);
                mPatientAge = (TextView)view.findViewById(R.id.txt_age);
            }
        }

在getView方法中切换它们之间。

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            int viewType = getItemViewType(position);

            switch (viewType) {

                case VIEW_TYPE_EXAMPLE: {
                    FirstViewHolder firstViewHolder = null;

                    if(convertView == null){
                        convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_example, parent, false);
                        firstViewHolder = new FirstViewHolder(convertView);
                        convertView.setTag(firstViewHolder);
                    }
                    else firstViewHolder = (FirstViewHolder)convertView.getTag();

                    firstViewHolder.mName.setText("Your name");
                    firstViewHolder.mAge.setText("20 years old");

                    break;
                }

                case VIEW_TYPE_EXAMPLE_TWO: {
                    SecondViewHolder holder = null;

                    if(convertView == null){
                        convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_example_two, parent, false);
                        holder = new SecondViewHolder(convertView);
                        convertView.setTag(holder);
                    }
                    else holder = (SecondViewHolder)convertView.getTag();

                    holder.mDate.setText("01/01/2016");
                    holder.mDescription.setText("Description");
                    holder.mObservations.setText("Obs");


                    break;
                }
            }

            return convertView;
        }

但是我不能忽略一个事实,在这个特定的问题中,您应该使用CursorAdapter,因为您是从数据库查询。
同时您也不应该直接访问数据库,而应该创建Loader(执行异步任务但不与活动绑定)。
如果您想遵循最佳实践并节省后续的麻烦,请创建ContentProvider来管理您的SQLite数据库。
但是对我来说,这只是太多的代码需要放在这个答案中:/ 希望这能帮助到某些人。

2

Android的适配器提供了一种在单个适配器中使用多个布局的方法。

首先,告诉您的适配器需要多少个布局:

public int getViewTypeCount()
{
    return 2;
}

然后,给出一些逻辑来确定当前项目应使用哪种布局:
public int getItemViewType(int position)
{
    if (verses.get(position).getVerseNumber() != 0)
    {
        return 0;
    }

    return 1;
}

最后,在您的构建中适当地创建视图:
public View getView(int position, View convertView, ViewGroup parent)
{
    if (this.getItemViewType(position) == 0)
    {
        // TODO Build the appropriate view
        return view;
    }

    // TODO Build the appropriate other view
    return view;
}

谢谢@Gaetan,稍作修改后它对我有用了。虽然我仍然感觉有点滞后。 - Aalem

0

有太多的事情需要改变,请看下面的代码,它会给你一个想法。您不必每次都膨胀布局,也不需要每次调用findViewById,请查看下面的示例代码。

    ViewHolder holder;
    if ((convertView == null)) {
        convertView = layoutInflater
                .inflate(R.layout.list_item,
                        viewGroup, false);
        holder = new ViewHolder();
        holder.itemImage = (ImageView) convertView
                .findViewById(R.id.logo);
        holder.itemName = ((TextView) convertView
                .findViewById(R.id.title_product_search));
        convertView.setTag(holder);

    } else {
        holder = (ViewHolder) convertView.getTag();
    }
    //assign text and images to controls after this
    holder.itemName.setText("text");
    imageLoader.displayImage(item.imageUrl, holder.itemImage,
                options);

0

这是我所做的。

private class MyListAdapter extends ArrayAdapter<VersesModel> {
    public MyListAdapter() {
        super(getActivity(), R.layout.verses_custom_list, verses);
    }

    @Override
    public int getViewTypeCount() {
        return 2;
    }

    @Override
    public int getItemViewType(int position) {
        if (verses.get(position).getVerseNumber() != 0) {
            return 0;
        }
        return 1;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        VersesModel currentVerse = verses.get(position);


        if (convertView == null) {
            viewHolder = new ViewHolder();
            switch (getItemViewType(position)) {
                case 0:
                    convertView = getActivity().getLayoutInflater().inflate(
                            R.layout.verses_custom_list, parent, false);
                    viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse);
                    viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_verseNumber);
                    viewHolder.textViewTranslation = (TextView) convertView.findViewById(R.id.textView_VerseTranslation);
                    font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");
                    viewHolder.textView.setTypeface(font);
                    Toast.makeText(getActivity(), "" + position, Toast.LENGTH_SHORT).show();
                    break;
                case 1:
                    convertView = getActivity().getLayoutInflater().inflate(
                            R.layout.verses_custom_list_header, parent, false);
                    chapterModel = chapterName.get(currentVerse.getChapterNumber() - 1);
                    viewHolder.textView = (TextViewEx) convertView.findViewById(R.id.textView_Verse_Bismillah);
                    viewHolder.nView = (TextView) convertView.findViewById(R.id.textView_Verse_ChapterName);
                    font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");
                    viewHolder.textView.setTypeface(font);
                    viewHolder.nView.setTypeface(font);
                    break;
            }
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        switch (getItemViewType(position)) {
            case 0:
                viewHolder.textView.setText(currentVerse.getVerseText() + "", true);
                viewHolder.textViewTranslation.setText(currentVerse.getVerseTranslation());
                viewHolder.nView.setText(currentVerse.getVerseNumber() + "");
                break;
            case 1:
                viewHolder.nView.setText("سورة  " + chapterModel.getChapterText());
                break;
        }
        return convertView;
    }
}

当列表加载时,Toast 显示 3 次,并且滚动在开始时较慢。


你正在为每个视图和每个视图类型执行以下操作:font = Typeface.createFromAsset(convertView.getContext().getAssets(), "Quran_Taha.ttf");。也许你可以在适配器构造函数中只加载一次。不确定它是否会改变你的速度问题。 - Gaëtan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接