您的位置:首页 > 其它

ListView中getView的原理+如何在ListView中放置多个item

2011-04-25 18:10 344 查看
ListView和Adapter的基础

工作原理:

ListView针对List中每个item,要求adapter“给我一个视图”(getView)。

一个新的视图被返回并显示

如果我们有上亿个项目要显示怎么办?为每个项目创建一个新视图?NO!这不可能!

实际上Android为你缓存了视图。

Android中有个叫做Recycler的构件,下图是他的工作原理:



如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中。

ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。

当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图。

请看下面的示例代码,这里在getView中使用了System.out进行输出

viewsource
print
?

01

public

class

MultipleItemsList

extends

ListActivity{

02


03


private

MyCustomAdaptermAdapter;

04


05


@Override

06


public

void

onCreate(BundlesavedInstanceState){

07


super

.onCreate(savedInstanceState);

08


mAdapter=

new

MyCustomAdapter();

09


for

(

int

i=

0

;i<

50

;i++){

10


mAdapter.addItem(

"item"

+i);

11


}

12


setListAdapter(mAdapter);

13


}

14


15


private

class

MyCustomAdapter

extends

BaseAdapter{

16


17


private

ArrayListmData=

new

ArrayList();

18


private

LayoutInflatermInflater;

19


20


public

MyCustomAdapter(){

21


mInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);

22


}

23


24


public

void

addItem(

final

Stringitem){

25


mData.add(item);

26


notifyDataSetChanged();

27


}

28


29


@Override

30


public

int

getCount(){

31


return

mData.size();

32


}

33


34


@Override

35


public

StringgetItem(

int

position){

36


return

mData.get(position);

37


}

38


39


@Override

40


public

long

getItemId(

int

position){

41


return

position;

42


}

43


44


@Override

45


public

ViewgetView(

int

position,ViewconvertView,ViewGroupparent){

46


System.out.println(

"getView"

+position+

""

+convertView);

47


ViewHolderholder=

null

;

48


if

(convertView==

null

){

49


convertView=mInflater.inflate(R.layout.item1,

null

);

50


holder=

new

ViewHolder();

51


holder.textView=(TextView)convertView.findViewById(R.id.text);

52


convertView.setTag(holder);

53


}

else

{

54


holder=(ViewHolder)convertView.getTag();

55


}

56


holder.textView.setText(mData.get(position));

57


return

convertView;

58


}

59


60


}

61


62


public

static

class

ViewHolder{

63


public

TextViewtextView;

64


}

65

}

执行程序,然后在Logcat中查看日志



getView被调用9次,convertView对于所有的可见项目是空值(如下)

viewsource
print
?

02

-

05

13

:

47

:

32.559

:INFO/System.out(

947

):getView

0

null

02

-

05

13

:

47

:

32.570

:INFO/System.out(

947

):getView

1

null

02

-

05

13

:

47

:

32.589

:INFO/System.out(

947

):getView

2

null

02

-

05

13

:

47

:

32.599

:INFO/System.out(

947

):getView

3

null

02

-

05

13

:

47

:

32.619

:INFO/System.out(

947

):getView

4

null

02

-

05

13

:

47

:

32.629

:INFO/System.out(

947

):getView

5

null

02

-

05

13

:

47

:

32.708

:INFO/System.out(

947

):getView

6

null

02

-

05

13

:

47

:

32.719

:INFO/System.out(

947

):getView

7

null

02

-

05

13

:

47

:

32.729

:INFO/System.out(

947

):getView

8

null

然后稍微向下滚动List,直到item10出现:



convertView仍然是空值,因为recycler中没有视图(item1的边缘仍然可见,在顶端)

viewsource
print
?

02

-

05

13

:

48

:

25.169

:INFO/System.out(

947

):getView

9

null

再滚动List



convertView不是空值了!item1离开屏幕到Recycler中去了,然后item11被创建

viewsource
print
?

02

-

05

13

:

48

:

42.879

:INFO/System.out(

947

):getView

10

android.widget.LinearLayout

@437430f8

再滚动:

viewsource
print
?

02

-

05

14

:

01

:

31.069

:INFO/System.out(

947

):getView

11

android.widget.LinearLayout

@437447d0

02

-

05

14

:

01

:

31.142

:INFO/System.out(

947

):getView

12

android.widget.LinearLayout

@43744ff8

02

-

05

14

:

01

:

31.279

:INFO/System.out(

947

):getView

13

android.widget.LinearLayout

@43743fa8

02

-

05

14

:

01

:

31.350

:INFO/System.out(

947

):getView

14

android.widget.LinearLayout

@43745820

02

-

05

14

:

01

:

31.429

:INFO/System.out(

947

):getView

15

android.widget.LinearLayout

@43746048

02

-

05

14

:

01

:

31.550

:INFO/System.out(

947

):getView

16

android.widget.LinearLayout

@43746870

02

-

05

14

:

01

:

31.669

:INFO/System.out(

947

):getView

17

android.widget.LinearLayout

@43747098

02

-

05

14

:

01

:

31.839

:INFO/System.out(

947

):getView

18

android.widget.LinearLayout

@437478c0

02

-

05

14

:

03

:

30.900

:INFO/System.out(

947

):getView

19

android.widget.LinearLayout

@43748df0

02

-

05

14

:

03

:

32.069

:INFO/System.out(

947

):getView

20

android.widget.LinearLayout

@437430f8

convertView如我们所期待的非空了,在item11离开屏幕之后,它的视图(@437430f8)作为convertView容纳item21了

不同的项目布局(itemlayout)

我们再举一个稍微复杂的例子,在上例的list中加入一些分隔线

你需要做这些:

重(@Override)写getViewTypeCount()–返回你有多少个不同的布局

重写getItemViewType(int)–由position返回viewtypeid

根据viewitem的类型,在getView中创建正确的convertView

以下是代码:

viewsource
print
?

001

public

class

MultipleItemsList

extends

ListActivity{

002


003


private

MyCustomAdaptermAdapter;

004


005


@Override

006


public

void

onCreate(BundlesavedInstanceState){

007


super

.onCreate(savedInstanceState);

008


mAdapter=

new

MyCustomAdapter();

009


for

(

int

i=

1

;i<

50

;i++){

010


mAdapter.addItem(

"item"

+i);

011


if

(i%

4

==

0

){

012


mAdapter.addSeparatorItem(

"separator"

+i);

013


}

014


}

015


setListAdapter(mAdapter);

016


}

017


018


private

class

MyCustomAdapter

extends

BaseAdapter{

019


020


private

static

final

int

TYPE_ITEM=

0

;

021


private

static

final

int

TYPE_SEPARATOR=

1

;

022


private

static

final

int

TYPE_MAX_COUNT=TYPE_SEPARATOR+

1

;

023


024


private

ArrayListmData=

new

ArrayList();

025


private

LayoutInflatermInflater;

026


027


private

TreeSetmSeparatorsSet=

new

TreeSet();

028


029


public

MyCustomAdapter(){

030


mInflater=(LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);

031


}

032


033


public

void

addItem(

final

Stringitem){

034


mData.add(item);

035


notifyDataSetChanged();

036


}

037


038


public

void

addSeparatorItem(

final

Stringitem){

039


mData.add(item);

040


//saveseparatorposition

041


mSeparatorsSet.add(mData.size()-

1

);

042


notifyDataSetChanged();

043


}

044


045


@Override

046


public

int

getItemViewType(

int

position){

047


return

mSeparatorsSet.contains(position)?TYPE_SEPARATOR:TYPE_ITEM;

048


}

049


050


@Override

051


public

int

getViewTypeCount(){

052


return

TYPE_MAX_COUNT;

053


}

054


055


@Override

056


public

int

getCount(){

057


return

mData.size();

058


}

059


060


@Override

061


public

StringgetItem(

int

position){

062


return

mData.get(position);

063


}

064


065


@Override

066


public

long

getItemId(

int

position){

067


return

position;

068


}

069


070


@Override

071


public

ViewgetView(

int

position,ViewconvertView,ViewGroupparent){

072


ViewHolderholder=

null

;

073


int

type=getItemViewType(position);

074


System.out.println(

"getView"

+position+

""

+convertView+

"type="

+type);

075


if

(convertView==

null

){

076


holder=

new

ViewHolder();

077


switch

(type){

078


case

TYPE_ITEM:

079


convertView=mInflater.inflate(R.layout.item1,

null

);

080


holder.textView=(TextView)convertView.findViewById(R.id.text);

081


break

;

082


case

TYPE_SEPARATOR:

083


convertView=mInflater.inflate(R.layout.item2,

null

);

084


holder.textView=(TextView)convertView.findViewById(R.id.textSeparator);

085


break

;

086


}

087


convertView.setTag(holder);

088


}

else

{

089


holder=(ViewHolder)convertView.getTag();

090


}

091


holder.textView.setText(mData.get(position));

092


return

convertView;

093


}

094


095


}

096


097


public

static

class

ViewHolder{

098


public

TextViewtextView;

099


}

100

}

运行程序,你会看到每4个item一个分割线



看看日志,无异常,所有的convertView都是空的

viewsource
print
?

02

-

05

15

:

19

:

03.080

:INFO/System.out(

1035

):getView

0

null

type=

0

02

-

05

15

:

19

:

03.112

:INFO/System.out(

1035

):getView

1

null

type=

0

02

-

05

15

:

19

:

03.130

:INFO/System.out(

1035

):getView

2

null

type=

0

02

-

05

15

:

19

:

03.141

:INFO/System.out(

1035

):getView

3

null

type=

0

02

-

05

15

:

19

:

03.160

:INFO/System.out(

1035

):getView

4

null

type=

1

02

-

05

15

:

19

:

03.170

:INFO/System.out(

1035

):getView

5

null

type=

0

02

-

05

15

:

19

:

03.180

:INFO/System.out(

1035

):getView

6

null

type=

0

02

-

05

15

:

19

:

03.190

:INFO/System.out(

1035

):getView

7

null

type=

0

02

-

05

15

:

19

:

03.210

:INFO/System.out(

1035

):getView

8

null

type=

0

02

-

05

15

:

19

:

03.210

:INFO/System.out(

1035

):getView

9

null

type=

1

滚动list:

viewsource
print
?

02

-

05

15

:

19

:

54.160

:INFO/System.out(

1035

):getView

10

null

type=

0

02

-

05

15

:

19

:

57.440

:INFO/System.out(

1035

):getView

11

android.widget.LinearLayout

@43744528

type=

0

02

-

05

15

:

20

:

01.310

:INFO/System.out(

1035

):getView

12

android.widget.LinearLayout

@43744eb0

type=

0

02

-

05

15

:

20

:

01.880

:INFO/System.out(

1035

):getView

13

android.widget.LinearLayout

@437456d8

type=

0

02

-

05

15

:

20

:

02.869

:INFO/System.out(

1035

):getView

14

null

type=

1

02

-

05

15

:

20

:

06.489

:INFO/System.out(

1035

):getView

15

android.widget.LinearLayout

@43745f00

type=

0

02

-

05

15

:

20

:

07.749

:INFO/System.out(

1035

):getView

16

android.widget.LinearLayout

@43747170

type=

0

02

-

05

15

:

20

:

10.250

:INFO/System.out(

1035

):getView

17

android.widget.LinearLayout

@43747998

type=

0

02

-

05

15

:

20

:

11.661

:INFO/System.out(

1035

):getView

18

android.widget.LinearLayout

@437481c0

type=

0

02

-

05

15

:

20

:

13.180

:INFO/System.out(

1035

):getView

19

android.widget.LinearLayout

@437468a0

type=

1

02

-

05

15

:

20

:

16.900

:INFO/System.out(

1035

):getView

20

android.widget.LinearLayout

@437489e8

type=

0

02

-

05

15

:

20

:

25.690

:INFO/System.out(

1035

):getView

21

android.widget.LinearLayout

@4374a8d8

type=

0

convertView对于分割线是空的,直到第一个分割线可见,当其离开屏幕,视图去到Recycler并且convertView开始起作用。

本文翻译自http://android.amberfog.com/?p=296

代码下载:MultipleItemsList.zip–sourcecode
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: