我在eclipse中收到以下警告:
来自视图适配器的无条件布局膨胀:应使用View Holder模式(使用传递给此方法的循环视图作为第二个参数)以实现更流畅的滚动。
在:
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
我有一个实现了CheckBox的基础适配器,我添加了一个标签以使CheckBox正常工作。
以下是代码:
public View getView(final int position, View convertView, ViewGroup parent)
{
ViewHolder mViewHolder;
mViewHolder = new ViewHolder();
LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
mViewHolder.cb = (CheckBox) convertView.findViewById(R.id.checkBox);
convertView.setTag(mViewHolder);
if (InviteFriends.isChecked[position] == true)
{
mViewHolder.cb.setChecked(true);
}
else
{
mViewHolder.cb.setChecked(false);
}
mViewHolder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean ischecked)
{
if (buttonView.isChecked())
{
InviteFriends.isChecked[position] = true;
}
else
{
InviteFriends.isChecked[position] = false;
}
}
});
TextView friendsname = (TextView) convertView.findViewById(R.id.friendsName); // title
ImageView thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb image
HashMap<String, String> song = new HashMap<String, String>();
song = data.get(position);
// Setting all values in listview
friendsname.setText(song.get(InviteFriends.KEY_DISPLAY_NAME));
imageLoader.DisplayImage(song.get(InviteFriends.KEY_IMAGEPROFILE_URL), thumb_image);
return convertView;
}
结果正常。我该如何修复此警告?我无法为此获得解决方案吗?
谢谢!
答案 0 :(得分:55)
试试这个
static class ViewHolder {
private TextView friendsname;
private ImageView thumb_image;
private CheckBox cb;
}
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder = null;
HashMap<String, String> song = null;
if (convertView == null) {
song = new HashMap <String, String>();
mViewHolder = new ViewHolder();
LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
mViewHolder.friendsname = (TextView) convertView.findViewById(R.id.friendsName); // title
mViewHolder.thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb image
mViewHolder.cb = (CheckBox) convertView.findViewById(R.id.checkBox);
convertView.setTag(mViewHolder);
mViewHolder.cb.setTag(data.get(position));
mViewHolder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean ischecked) {
InviteFriends.isChecked[position] = buttonView.isChecked();
}
});
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
song = mViewHolder.cb.getTag();
mViewHolder.friendsname.setText(song.get(InviteFriends.KEY_DISPLAY_NAME));
mViewHolder.imageLoader.DisplayImage(song.get(InviteFriends.KEY_IMAGEPROFILE_URL), thumb_image);
mViewHolder.cb.setChecked(InviteFriends.isChecked[position]);
return convertView;
}
答案 1 :(得分:28)
只有在转换视图为空时才应该初始化
这些行
LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
// [...] the rest of initialization part
// [...] some changes that must be done at refresh
return convertView;
应如下所示:
if (convertView == null) {
LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
// [...] the rest of initialization part
}
// [...] some changes that must be done at refresh
return convertView;
目标是回收该列表中现有的视图,而不是在每次滚动列表时显示它时初始化它。
答案 2 :(得分:4)
我的建议是尝试使用convertView = vi.inflate(R.layout.activity_friend_list_row, null);
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
TextView friendsname = (TextView) convertView.findViewById(R.id.friendsName); // title
ImageView thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb image
这可能会对您有帮助。
: - okey ..如果你需要在你的适配器
中使用viewholder类,那么就像这样访问static class ViewHolder {
public TextView text;
public ImageView image;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
// reuse views
if (rowView == null) {
LayoutInflater inflater = context.getLayoutInflater();
rowView = inflater.inflate(R.layout.rowlayout, null);
// configure view holder
ViewHolder viewHolder = new ViewHolder();
viewHolder.text = (TextView) rowView.findViewById(R.id.TextView01);
viewHolder.image = (ImageView) rowView
.findViewById(R.id.ImageView01);
rowView.setTag(viewHolder);
}
// fill data
ViewHolder holder = (ViewHolder) rowView.getTag();
String s = names[position];
holder.text.setText(s);
if (s.startsWith("Windows7") || s.startsWith("iPhone")
|| s.startsWith("Solaris")) {
holder.image.setImageResource(R.drawable.no);
} else {
holder.image.setImageResource(R.drawable.ok);
}
return rowView;
}
例如
{{1}}
答案 3 :(得分:1)
视图适配器的无条件布局膨胀:应该使用View Holder模式(将传递给此方法的回收视图用作第二个参数),以实现平滑滚动。
这意味着您需要在适配器中使用View Holder模式。使用View Holder的目的在于重用视图,因为膨胀和使用findViewById
的速度很慢。
使用以下代码时:
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder;
mViewHolder = new ViewHolder();
LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
mViewHolder.cb = (CheckBox) convertView.findViewById(R.id.checkBox);
convertView.setTag(mViewHolder);
...
return convertView;
}
您不是在重用视图,而是总是创建新视图。
您需要将代码更改为以下内容(请检查注释):
// class for holding the cached view
static class ViewHolder {
TextView tvFriendsName;
ImageView imvThumbImage;
CheckBox cbInviteFriend;
}
public View getView(final int position, View convertView, ViewGroup parent) {
// holder of the views to be reused.
ViewHolder viewHolder;
// get data based on the position
HashMap<String, String> song = data.get(position);
// if no previous views found
if (convertView == null) {
// create the container ViewHolder
viewHolder = new ViewHolder();
// inflate the views from layout for the new row
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
convertView = inflater.inflate(R.layout.rowlayout, parent, false);
// set the view to the ViewHolder.
viewHolder.cbInviteFriend = convertView.findViewById(R.id.checkBox);
viewHolder.tvFriendsName = convertView.findViewById(R.id.friendsName);
viewHolder.imvThumbImage = convertView.findViewById(R.id.list_image);
// save the viewHolder to be reused later.
convertView.setTag(viewHolder);
} else {
// there is already ViewHolder, reuse it.
viewHolder = (ViewHolder) convertView.getTag();
}
// now we can set populate the data via the ViewHolder into views
viewHolder.tvFriendsName.setText(song.get(InviteFriends.KEY_DISPLAY_NAME));
imageLoader.DisplayImage(song.get(InviteFriends.KEY_IMAGEPROFILE_URL), viewHolder.imvThumbImage);
viewHolder.cbInviteFriend.isChecked(InviteFriends.isChecked[position]);
return convertView;
}
答案 4 :(得分:0)
我所做的是创建一个BaseSpinnerAdapter类,并在需要时重用它
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import androidx.annotation.LayoutRes
/**
* @param T Model class
* @param VH ViewHolder class, which holds the view to reuse it
* */
abstract class BaseSpinnerAdapter<T, VH>(context: Context?, private val items: ArrayList<T>) :
BaseAdapter() {
private var inflater: LayoutInflater = LayoutInflater.from(context)
/** use viewHolder pattern to reusing the views
* @param p0 current view position
* @param p1
* @param viewGroup
* */
override fun getView(p0: Int, p1: View?, viewGroup: ViewGroup?): View {
var pClone = p1
val viewHolder: VH
if (pClone == null) {
pClone = inflater.inflate(setSpinnerItemLayout(), viewGroup, false)
viewHolder = createViewHolder(pClone)
pClone?.tag = viewHolder
} else {
viewHolder = pClone.tag as VH
}
getView(viewHolder, p0)
return pClone!!
}
override fun getItem(p0: Int): T {
return items[p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getCount(): Int {
return items.size
}
@LayoutRes
abstract fun setSpinnerItemLayout(): Int
abstract fun getView(viewHolder: VH, position: Int)
abstract fun createViewHolder(view: View?): VH
}
这里是一个示例,您如何在实现中使用BaseSpinnerAdapter。我相信没有必要详细说明代码说明。
class SpinnerImplAdapter(context: Context?, private val items: ArrayList<AnyModelClass>) : BaseSpinnerAdapter<AnyModelClass, SpinnerImplAdapter.ViewHolderImp>(context, items) {
override fun setSpinnerItemLayout(): Int {
return R.layout.spinner_item
}
override fun createViewHolder(view: View?): ViewHolderImp {
return ViewHolderImp(view)
}
override fun getView(viewHolder: ViewHolderImp, position: Int) {
val model = items[position]
viewHolder.textView?.text = "" // model.etc get anything you want
}
/**
* I have used kotlin extension to get the viewId,
* if you are not using then simply call the view.findViewById(R.id.yourView)
* */
class ViewHolderImp(view: View?) {
val textView: TextView? = view?.textView
}
}