2014년 7월 8일 화요일

Android Holder Pattern

Using the Holder Pattern
Another somewhat expensive operation commonly done with fancy views is calling findViewById(). This dives into our inflated row and pulls out widgets by their assigned identifiers, so we can customize the widget contents (e.g., to change the text of a TextView or change the icon in an ImageView). Since findViewById() can find widgets anywhere in the tree of children of the row’s root View, this could take a fair number of instructions to execute, particularly if we need to find the same widgets repeatedly.
In some GUI toolkits, this problem is avoided by having the composite View objects, like rows, be declared totally in program code (in this case, Java). Then, accessing individual widgets is merely a matter of calling a getter or accessing a field. And we can certainly do that with Android, but the code gets rather verbose. What would be nice is a way that enables us still to use the layout XML, yet cache our row’s key child widgets so that we need to find them only once. That’s where the holder pattern comes into play, in a class we’ll call ViewHolder.
All View objects have getTag() and setTag() methods. These allow us to associate an arbitrary object with the widget. The holder pattern uses that “tag” to hold an object that, in turn, holds each of the child widgets of interest. By attaching that holder to the row View, every time we use the row, we already have access to the child widgets we care about, without having to call findViewById() again.
So, let’s take a look at one of these holder classes

package com.commonsware.android.fancylists.five;
import android.view.View;
import android.widget.ImageView;
class ViewHolder {
 ImageView icon=null;
 ViewHolder(View base) {
   this.icon=(ImageView)base.findViewById(R.id.icon);
 }
}

ViewHolder holds onto the child widgets, initialized via findViewById() in its constructor.
The widgets are simply package-protected data members, accessible from other classes in this project, such as a ViewHolderDemo activity. In this case, we are holding onto only one widget—the icon—since we will let ArrayAdapter handle our label for us.
Using ViewHolder is a matter of creating an instance whenever we inflate a row and attaching said instance to the row View via setTag(), as shown in this rewrite of getView(), found in ViewHolderDemo:

public View getView(int position, View convertView, ViewGroup parent) {
 View row=super.getView(position, convertView, parent);
 ViewHolder holder=(ViewHolder)row.getTag();
 if (holder==null) {
   holder=new ViewHolder(row);
   row.setTag(holder);
 }
 if (getModel(position).length()>4) {
   holder.icon.setImageResource(R.drawable.delete);
 }
 else {
   holder.icon.setImageResource(R.drawable.ok);
 }
 return(row);
}

Here, we go back to allowing ArrayAdapter to handle our row inflation and recycling for us. If the call to getTag() on the row returns null, we know we need to create a new ViewHolder, which we then attach to the row via setTag() for later reuse. Then, accessing the child widgets is merely a matter of accessing the data members on the holder. The first time the ListView is displayed, all new rows need to be inflated, and we wind up creating a ViewHolder for each. As the user scrolls, rows get recycled, and we can reuse their corresponding ViewHolder widget caches.
Using a holder helps performance, but the effect is not as dramatic. Whereas recycling can give you a 150 percent performance improvement, adding in a holder increases the improvement to 175 percent. Hence, while you may wish to implement recycling up front when you create your adapter, adding in a holder might be something you deal with later, when you are working specifically on performance tuning.
In this particular case, we certainly could simplify all of this by skipping ViewHolder and using getTag() and setTag() with the ImageView directly. This example is written as it is to demonstrate how to handle a more complex scenario, where you might have several widgets that would need to be cached via the holder pattern.

Source From “Beginning Android 4”

댓글 없음:

댓글 쓰기

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...