天天看點

[Android]ListView性能優化之視圖緩存(續)

一、新浪微網誌

    1.1  截圖

      

[Android]ListView性能優化之視圖緩存(續)

(來自網絡)

    1.2  反編譯後相關代碼

      HomeListActivity

    public View getView(int paramInt, View paramView, ViewGroup paramViewGroup)

    {

      int i = --paramInt;

      int j = -1;

      if (i == j);

      for (Object localObject1 = HomeListActivity.this.getReloadView(); ; localObject1 = HomeListActivity.this.getLoadMoreView())

      {

        label26: return localObject1;

        int k = HomeListActivity.this.mList.size();

        int l = paramInt;

        int i1 = k;

        if (l != i1)

          break;

      }

      boolean bool1 = true;

      boolean bool2 = null;

      String str1;

      label110: Object localObject2;

      if (StaticInfo.mUser == null)

        List localList1 = HomeListActivity.this.mList;

        int i2 = paramInt;

        str1 = ((MBlog)localList1.get(i2)).uid;

        List localList2 = HomeListActivity.this.mList;

        int i3 = paramInt;

        String str2 = ((MBlog)localList2.get(i3)).uid;

        String str3 = str1;

        if (!str2.equals(str3))

          break label271;

        int i4 = 1;

        label156: if (paramView != null)

          break label277;

        HomeListActivity localHomeListActivity1 = HomeListActivity.this;

        ListView localListView1 = HomeListActivity.this.mLvHome;

        List localList3 = HomeListActivity.this.mList;

        int i5 = paramInt;

        MBlog localMBlog1 = (MBlog)localList3.get(i5);

        HomeListActivity localHomeListActivity2 = HomeListActivity.this;

        int i6 = paramInt;

        boolean bool4 = localHomeListActivity2.isNewCommer(i6);

        int i7 = HomeListActivity.this.mReadMode;

        localObject2 = new MBlogListItemView(localHomeListActivity1, localListView1, localMBlog1, bool1, bool2, i4, bool4, i7);

      while (true)

        localObject1 = localObject2;

        break label26:

        str1 = StaticInfo.mUser.uid;

        break label110:

        label271: boolean bool3 = null;

        break label156:

        label277: localObject2 = paramView;

        try

        {

          MainListItemView localMainListItemView = (MainListItemView)localObject2;

          List localList4 = HomeListActivity.this.mList;

          int i8 = paramInt;

          Object localObject3 = localList4.get(i8);

          HomeListActivity localHomeListActivity3 = HomeListActivity.this;

          int i9 = paramInt;

          boolean bool5 = localHomeListActivity3.isNewCommer(i9);

          int i10 = HomeListActivity.this.mReadMode;

          boolean bool6 = bool1;

          boolean bool7 = bool2;

          localMainListItemView.update(localObject3, bool6, bool7, bool5, i10);

        }

        catch (Exception localException)

          HomeListActivity localHomeListActivity4 = HomeListActivity.this;

          ListView localListView2 = HomeListActivity.this.mLvHome;

          List localList5 = HomeListActivity.this.mList;

          int i11 = paramInt;

          MBlog localMBlog2 = (MBlog)localList5.get(i11);

          HomeListActivity localHomeListActivity5 = HomeListActivity.this;

          int i12 = paramInt;

          boolean bool8 = localHomeListActivity5.isNewCommer(i12);

          int i13 = HomeListActivity.this.mReadMode;

          localObject2 = new MBlogListItemView(localHomeListActivity4, localListView2, localMBlog2, bool1, bool2, bool3, bool8, i13);

    }

        代碼說明:

          代碼流程已經比較混亂,但是這裡能看到并沒有直接的inflate,而是自定義了繼承自LinearLayout的MBlogListItemView。

      MBlogListItemView

  public MBlogListItemView(Context paramContext, ListView paramListView, MBlog paramMBlog, boolean paramBoolean1, boolean paramBoolean2, boolean paramBoolean3, boolean paramBoolean4, int paramInt)

  {

    super(paramContext);

    this.context = paramContext;

    this.parent = paramListView;

    this.mBlog = paramMBlog;

    String str1 = paramContext.getCacheDir().getAbsolutePath();

    this.mCacheDir = str1;

    String str2 = paramContext.getFilesDir().getAbsolutePath();

    this.mFileDir = str2;

    ((LayoutInflater)paramContext.getSystemService("layout_inflater")).inflate(2130903061, this);

    TextView localTextView1 = (TextView)findViewById(2131624016);

    this.mName = localTextView1;

    TextView localTextView2 = (TextView)findViewById(2131624041);

    this.mDate = localTextView2;

    TextView localTextView3 = (TextView)findViewById(2131624018);

    this.mContent = localTextView3;

    TextView localTextView4 = (TextView)findViewById(2131624046);

    this.mSubContent = localTextView4;

    ImageView localImageView1 = (ImageView)findViewById(2131624040);

    this.mIconV = localImageView1;

    ImageView localImageView2 = (ImageView)findViewById(2131624042);

    this.mIconPic = localImageView2;

    ImageView localImageView3 = (ImageView)findViewById(2131624044);

    this.mUploadPic1 = localImageView3;

    ImageView localImageView4 = (ImageView)findViewById(2131623979);

    this.mUploadPic2 = localImageView4;

    TextView localTextView5 = (TextView)findViewById(2131624047);

    this.tvForm = localTextView5;

    TextView localTextView6 = (TextView)findViewById(2131623989);

    this.tvComment = localTextView6;

    this.tvComment.setOnClickListener(this);

    TextView localTextView7 = (TextView)findViewById(2131623988);

    this.tvRedirect = localTextView7;

    this.tvRedirect.setOnClickListener(this);

    ImageView localImageView5 = (ImageView)findViewById(2131624049);

    this.imComment = localImageView5;

    this.imComment.setOnClickListener(this);

    ImageView localImageView6 = (ImageView)findViewById(2131624048);

    this.imRedirect = localImageView6;

    this.imRedirect.setOnClickListener(this);

    ImageView localImageView7 = (ImageView)findViewById(2131624043);

    this.imGpsIcon = localImageView7;

    ImageView localImageView8 = (ImageView)findViewById(2131624013);

    this.mPortrait = localImageView8;

    LinearLayout localLinearLayout = (LinearLayout)findViewById(2131624045);

    this.mSubLayout = localLinearLayout;

    this.mReadMode = paramInt;

    MBlogListItemView localMBlogListItemView = this;

    MBlog localMBlog = paramMBlog;

    boolean bool1 = paramBoolean1;

    boolean bool2 = paramBoolean2;

    boolean bool3 = paramBoolean4;

    int i = paramInt;

    localMBlogListItemView.update(localMBlog, bool1, bool2, bool3, i);

    this.mUploadPic1.setOnClickListener(this);

    this.mUploadPic2.setOnClickListener(this);

  }

    代碼說明:

      a).  MBlogListItemView extends LinearLayout implements MainListItemView

      b).  inflate(2130903061,this)這個數字代表R.layout.itemview。

二、測試方案(方案五)

    按照新浪微網誌類似的做法進行測試。

    2.1  測試代碼

        @Override

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

            // 開始計時

            long startTime = System.nanoTime();

            TestItemLayout item;

            if (convertView == null) {

                item = new TestItemLayout(BaseAdapterActivity.this);

            } else

                item = (TestItemLayout) convertView;

            item.icon1.setImageResource(R.drawable.icon);

            item.text1.setText(mData[position]);

            item.icon2.setImageResource(R.drawable.icon);

            item.text2.setText(mData[position]);

            // 停止計時

            long endTime = System.nanoTime();

            // 計算耗時

            long val = (endTime - startTime) / 1000L;

            Log.e("Test", "Position:" + position + ":" + val);

            if (count < 100) {

                if (val < 2000L) {

                    sum += val;

                    count++;

                }

                mTV.setText(String.valueOf(sum / 100L) + ":" + nullcount);// 顯示統計結果

            return item;

      TestItemLayout

public class TestItemLayout extends LinearLayout {

    public TextView text1;

    public ImageView icon1;

    public TextView text2;

    public ImageView icon2;

    public TestItemLayout(Context context) {

        super(context);

        ((LayoutInflater) context

                .getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(

                R.layout.list_item_icon_text, this);

        icon1 = (ImageView) findViewById(R.id.icon1);

        text1 = (TextView) findViewById(R.id.text1);

        icon2 = (ImageView) findViewById(R.id.icon2);

        text2 = (TextView) findViewById(R.id.text2);

}

    2.2  測試結果

次數

4個子元素

10個子元素

第一次

 347

460

第二次

310

477

第三次

 324

508

第四次

339

492

第五次

 341

465

三、總結 

    從測試結果來看與ViewHolder性能非常接近,不會出現tag圖檔變小的問題(關于圖檔變小的問題,有朋友說是TAG中的元素對大小和位置有記憶),也能有效的減少findViewById的執行次數,這裡建議完全可以取代ViewHolder。

    關于ListView内部Adapter的心得大家可以看一下上文的總結4.1。

四、考慮

    關于靜态内部類這裡不是很了解,是否能應用方案五還有待驗證。

五、後期維護

           2011-4-29     來自Stony Wang關于Tag的解釋:

Stony Wang

tag的用途應該是仿照delphi的來的,設定一個關聯的資料。 

簡單的說就是,你的UI控件有時候顯示的内容帶源于(綁定?)某個資料或者對象執行個體。 

當你處理一些事件的時候,不推薦從UI上來重新擷取,而是從Tag裡面取出來。 

舉一個例子是,有一個按鈕,一開始顯示"0",然後每按一次計數增1。 

每次click的時候, 

1 從btn.getText()再轉回Integer 

2 從tag裡面把之前設好的Integer拿出來,加一,再settag? 

如果覺得1和2差別不大的話,那麼如果顯示的内容不是"0",而是"已經點了0次"呢? 

更新UI的時候,可以将關聯的對象放到tag裡面,在處理相關觸發事件的時候,可以友善的擷取原始的資料。 

ListView的Tag用法也不算很錯,而是用的時候沒有注意設定的時候要注意“對稱”。 

Tag本身可以了解成放ViewHolder,那麼和ViewHolder的加速隻不過是存放的位置不同,加速效果基本一緻。 

“對稱”我所指的内容是: 

不管你要顯示的資料的邏輯是如何的,如果你設定了某個View的寬度,那麼在任何一種資料的填充UI邏輯裡面,不可以有不設定這個View寬度的代碼路徑。 

簡單的例子就是,我根據某個布爾值,如果是false的話,将ImageView設定為View.INVISIBLE 

if ( item.isHidden()){ 

  mImage.setVisibility(View.INVISIBLE); 

這樣是錯誤的,因為如果這裡緩存的UI控件的狀态會被複用到其它item上,而這個item恰巧可能是需要顯示的。 

必須補上else語句 

else{ 

  mImage.setVisibility(View.VISIBLE); 

這個估計就是那位仁兄拖動圖檔變小的原因了。 

最後說一下,ListView控件條目部分,一共産生的條目是螢幕能容納的數目+2(還是+1?我記不清楚了),然後循環使用。

繼續閱讀