Unconditional layout, inflation from view adapter: Should use View Holder pattern

后端 未结 5 1816
天命终不由人
天命终不由人 2020-12-08 13:33

I am getting following warning in eclipse:

Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed

相关标签:
5条回答
  • 2020-12-08 13:35

    you should init the convert view only if it is null

    these lines

    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;
    

    should look like this:

    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;
    

    the goal is to recycle the already existing view in that list, not to init it each time you display it when scrolling the list for example.

    0 讨论(0)
  • 2020-12-08 13:36

    Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling.

    It means that you need to use View Holder pattern in your Adapter. The point of using View Holder is to reusing the views because inflating and using findViewById are slow.

    When you're using the following code:

    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;
    
    } 
    

    you're not reusing the views but instead you always create new views.

    You need to change your code to something like this (please check the comment):

    // 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;
    }
    
    0 讨论(0)
  • 2020-12-08 13:40

    Try this

    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;
    }
    
    0 讨论(0)
  • 2020-12-08 13:55

    My suggestion is try to use convertView = vi.inflate(R.layout.activity_friend_list_row, null); insted of convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false); this may help you.

    :- okey.. insted of accessing like this TextView friendsname = (TextView) convertView.findViewById(R.id.friendsName); // title ImageView thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb image you have to use viewholder class in your adapter

    for example

    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;
      }
    
    0 讨论(0)
  • 2020-12-08 13:56

    What i have done is created a BaseSpinnerAdapter class and reusing it if needed

    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
    
    
    }
    

    Here is an example How you can use BaseSpinnerAdapter in your implementation. I believe that there is no need to detail out the code description.

        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
            }
        
        
        }
    
    0 讨论(0)
提交回复
热议问题