问题
I am quite new to Android. In the following class the data is retrieved from the database and displayed in a ListView which has two different layouts. Though it works as expected, the problem is that scrolling is not smooth because the textviews are assigned again and again. I couldn't figure out how to have them assigned only once. Please somebody help me out with this. Thanks in advance. My apology for the code, I know it looks bad.
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;
}
}
回答1:
Android's adapter provide a way to use multiple layouts in a single adapter.
First, tell your adapter how many layouts you need:
public int getViewTypeCount()
{
return 2;
}
Then, gives some logic to tell which layout should be used for the current item:
public int getItemViewType(int position)
{
if (verses.get(position).getVerseNumber() != 0)
{
return 0;
}
return 1;
}
Finally, in your build the appropriate view:
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;
}
回答2:
I know this post is old, but just for future reference... In this case you should use the ViewHolder pattern.
If you want to use 2 layouts just create two ViewHolder's and switch between then in the getView method.
Pretty similar to the accepted answer but with better performance.
Declare the view types.
private final int VIEW_TYPE_EXAMPLE = 0;
private final int VIEW_TYPE_EXAMPLE_TWO = 1;
Return as many types as you declared above.
@Override
public int getViewTypeCount() {
return 2;
}
Switch when returning the viewType when the item is at position X. in this case I only change the type when the item is the first on the list.
@Override
public int getItemViewType(int position) {
return (position == 0) ? VIEW_TYPE_EXAMPLE : VIEW_TYPE_EXAMPLE_TWO;
}
Create the view holders matching your layouts. They will hold your data.
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);
}
}
Switch between then in the getView method.
@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;
}
But I can not ignore the fact that in this specific question, you should use the CursorAdapter because you are querying from a database.
You also should not do the access to the database directly. Should create a Loader instead (does the async task but not tied to the activity).
And if you want to follow best practices and save some trouble later on, create the ContentProvider to manage your SQLite database.
But that's just too much code for me to put in this answer :/
Hope this helps someone.
回答3:
There are two many things to changes have a look at code below it will give you idea. You dont have to inflate layout everytime and no need to call findViewById everytime as well look at sample code below
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);
回答4:
Here is what i did.
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;
}
}
The toast displays 3 times when the list loads and the scrolling is slower at the beginning.
来源:https://stackoverflow.com/questions/29721753/android-listview-arrayadapter-with-two-layouts