I have a ListView
which displays news items. They contain an image, a title and some text. The image is loaded in a separate thread (with a queue and all) and when the image is downloaded, I now call notifyDataSetChanged()
on the list adapter to update the image. This works, but getView()
is getting called too frequently, since notifyDataSetChanged()
calls getView()
for all visible items. I want to update just the single item in the list. How would I do this?
我有一个显示新闻项目的列表视图。它们包含图像、标题和一些文本。映像被加载到一个单独的线程中(带有一个队列和所有的线程),当映像被下载时,我现在调用列表适配器上的notifyDataSetChanged()来更新映像。这是可行的,但是getView()被调用得太频繁了,因为notifyDataSetChanged()对所有可见项调用getView()。我只想更新列表中的单个项目。我该怎么做呢?
Problems I have with my current approach are:
我目前的方法存在的问题是:
- Scrolling is slow
- 滚动是缓慢的
- I have a fade-in animation on the image which happens every time a single new image in the list is loaded.
- 我在图像上有一个fade-in的动画,每当一个新的图像在列表中加载时,它就会发生。
10 个解决方案
#1
185
I found the answer, thanks to your information Michelle. You can indeed get the right view using View#getChildAt(int index)
. The catch is that it starts counting from the first visible item. In fact, you can only get the visible items. You solve this with ListView#getFirstVisiblePosition()
.
我找到了答案,谢谢你的信息,Michelle。您确实可以使用view# getChildAt(int index)获得正确的视图。问题是它开始从第一个可见项开始计数。事实上,你只能得到可见的项目。您可以使用ListView#getFirstVisiblePosition()解决这个问题。
Example:
例子:
private void updateView(int index){
View v = yourListView.getChildAt(index -
yourListView.getFirstVisiblePosition());
if(v == null)
return;
TextView someText = (TextView) v.findViewById(R.id.sometextview);
someText.setText("Hi! I updated you manually!");
}
#2
66
This question has been asked at the Google I/O 2010, you can watch it here:
这个问题已经在谷歌I/O 2010上被提出,你可以在这里观看:
The world of ListView, time 52:30
ListView的世界,时间是52:30。
Basically what Romain Guy explains is to call getChildAt(int)
on the ListView
to get the view and (I think) call getFirstVisiblePosition()
to find out the correlation between position and index.
基本上,Romain Guy解释说的是在ListView上调用getChildAt(int)来获取视图(我认为)调用getFirstVisiblePosition()来找出位置和索引之间的关系。
Romain also points to the project called Shelves as an example, I think he might mean the method ShelvesActivity.updateBookCovers()
, but I can't find the call of getFirstVisiblePosition()
.
Romain还以称为shelf的项目为例,我认为他可能指的是方法shelvesactivity . updatebookcover(),但是我找不到getFirstVisiblePosition()的调用。
AWESOME UPDATES COMING:
很棒的更新来:
The RecyclerView will fix this in the near future. As pointed out on http://www.grokkingandroid.com/first-glance-androids-recyclerview/, you will be able to call methods to exactly specify the change, such as:
回收视图将在不久的将来修复这个问题。正如http://www.grokkingandroid.com/first—androids-view/所指出的,您将能够调用方法来精确地指定更改,例如:
void notifyItemInserted(int position)
void notifyItemRemoved(int position)
void notifyItemChanged(int position)
Also, everyone will want to use the new views based on RecyclerView because they will be rewarded with nicely-looking animations! The future looks awesome! :-)
而且,每个人都希望使用基于回收视图的新视图,因为它们会得到漂亮的动画效果!未来看起来帅呆了!:-)
#3
6
This is how I did it:
我是这样做的:
Your items (rows) must have unique ids so you can update them later. Set the tag of every view when the list is getting the view from adapter. (You can also use key tag if the default tag is used somewhere else)
您的项目(行)必须具有惟一的id,以便稍后更新它们。当列表从适配器获取视图时,设置每个视图的标记。(如果默认标记在其他地方使用,也可以使用key tag)
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View view = super.getView(position, convertView, parent);
view.setTag(getItemId(position));
return view;
}
For the update check every element of list, if a view with given id is there it's visible so we perform the update.
对于更新检查列表中的每个元素,如果有给定id的视图在那里,那么我们执行更新。
private void update(long id)
{
int c = list.getChildCount();
for (int i = 0; i < c; i++)
{
View view = list.getChildAt(i);
if ((Long)view.getTag() == id)
{
// update view
}
}
}
It's actually easier than other methods and better when you dealing with ids not positions! Also you must call update for items which get visible.
它实际上比其他方法更简单,当你处理id而不是位置时更好!还必须为可见的项调用update。
#4
2
The answers are clear and correct, I'll add an idea for CursorAdapter
case here.
答案是清晰和正确的,我将在这里为CursorAdapter case添加一个想法。
If youre subclassing CursorAdapter
(or ResourceCursorAdapter
, or SimpleCursorAdapter
), then you get to either implement ViewBinder
or override bindView()
and newView()
methods, these don't receive current list item index in arguments. Therefore, when some data arrives and you want to update relevant visible list items, how do you know their indices?
如果您正在子类化CursorAdapter(或者ResourceCursorAdapter,或SimpleCursorAdapter),那么您可以实现ViewBinder或override bindView()和newView()方法,这些方法不会在参数中接收当前列表项索引。因此,当一些数据到达并希望更新相关可见列表项时,您如何知道它们的索引?
My workaround was to:
我的解决方法是:
- keep a list of all created list item views, add items to this list from
newView()
- 保存所有创建的列表项视图的列表,从newView()向该列表添加项
- when data arrives, iterate them and see which one needs updating--better than doing
notifyDatasetChanged()
and refreshing all of them - 当数据到达时,迭代它们,看看哪个需要更新——比执行notifyDatasetChanged()和刷新所有它们要好
Due to view recycling the number of view references I'll need to store and iterate will be roughly equal the number of list items visible on screen.
由于视图回收,我需要存储和迭代的视图引用的数量将大致等于屏幕上可见的列表项的数量。
#5
2
get the model class first as global like this model class object
首先将模型类作为全局对象,如这个模型类对象。
SampleModel golbalmodel=new SchedulerModel();
and initialise it to global
并将其推广到全球
get the current row of the view by the model by initialising the it to global model
通过将it初始化为全局模型,通过模型获取视图的当前行
SampleModel data = (SchedulerModel) sampleList.get(position);
golbalmodel=data;
set the changed value to global model object method to be set and add the notifyDataSetChanged its works for me
将更改后的值设置为全局模型对象方法,并添加notifyDataSetChanged它对我的工作。
golbalmodel.setStartandenddate(changedate);
notifyDataSetChanged();
Here is a related question on this with good answers.
这里有一个相关的问题,有很好的答案。
#6
1
I used the code that provided Erik, works great, but i have a complex custom adapter for my listview and i was confronted with twice implementation of the code that updates the UI. I've tried to get the new view from my adapters getView method(the arraylist that holds the listview data has allready been updated/changed):
我使用了提供Erik的代码,效果很好,但是我的listview有一个复杂的自定义适配器,我遇到了两次更新UI的代码实现。我尝试从我的适配器getView方法中获取新的视图(保存listview数据的arraylist已经被更新/更改):
View cell = lvOptim.getChildAt(index - lvOptim.getFirstVisiblePosition());
if(cell!=null){
cell = adapter.getView(index, cell, lvOptim); //public View getView(final int position, View convertView, ViewGroup parent)
cell.startAnimation(animationLeftIn());
}
It's working well, but i dont know if this is a good practice. So i don't need to implement the code that updates the list item two times.
它运行得很好,但我不知道这是否是一个好的实践。所以我不需要实现两次更新列表项的代码。
#7
1
int wantedPosition = 25; // Whatever position you're looking for
int firstPosition = linearLayoutManager.findFirstVisibleItemPosition(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
if (wantedChild < 0 || wantedChild >= linearLayoutManager.getChildCount()) {
Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
return;
}
View wantedView = linearLayoutManager.getChildAt(wantedChild);
mlayoutOver =(LinearLayout)wantedView.findViewById(R.id.layout_over);
mlayoutPopup = (LinearLayout)wantedView.findViewById(R.id.layout_popup);
mlayoutOver.setVisibility(View.INVISIBLE);
mlayoutPopup.setVisibility(View.VISIBLE);
For RecycleView please use this code
请使用此代码
#8
0
My solution: If it is correct*, update the data and viewable items without re-drawing the whole list. Else notifyDataSetChanged.
我的解决方案:如果是正确的*,更新数据和可查看的项目,而不重新绘制整个列表。notifyDataSetChanged。
Correct - oldData size == new data size, and old data IDs and their order == new data IDs and order
正确的- oldData size ==新的数据大小,旧的数据id和它们的order ==新的数据id和顺序。
How:
怎样去:
/**
* A View can only be used (visible) once. This class creates a map from int (position) to view, where the mapping
* is one-to-one and on.
*
*/
private static class UniqueValueSparseArray extends SparseArray<View> {
private final HashMap<View,Integer> m_valueToKey = new HashMap<View,Integer>();
@Override
public void put(int key, View value) {
final Integer previousKey = m_valueToKey.put(value,key);
if(null != previousKey) {
remove(previousKey);//re-mapping
}
super.put(key, value);
}
}
@Override
public void setData(final List<? extends DBObject> data) {
// TODO Implement 'smarter' logic, for replacing just part of the data?
if (data == m_data) return;
List<? extends DBObject> oldData = m_data;
m_data = null == data ? Collections.EMPTY_LIST : data;
if (!updateExistingViews(oldData, data)) notifyDataSetChanged();
else if (DEBUG) Log.d(TAG, "Updated without notifyDataSetChanged");
}
/**
* See if we can update the data within existing layout, without re-drawing the list.
* @param oldData
* @param newData
* @return
*/
private boolean updateExistingViews(List<? extends DBObject> oldData, List<? extends DBObject> newData) {
/**
* Iterate over new data, compare to old. If IDs out of sync, stop and return false. Else - update visible
* items.
*/
final int oldDataSize = oldData.size();
if (oldDataSize != newData.size()) return false;
DBObject newObj;
int nVisibleViews = m_visibleViews.size();
if(nVisibleViews == 0) return false;
for (int position = 0; nVisibleViews > 0 && position < oldDataSize; position++) {
newObj = newData.get(position);
if (oldData.get(position).getId() != newObj.getId()) return false;
// iterate over visible objects and see if this ID is there.
final View view = m_visibleViews.get(position);
if (null != view) {
// this position has a visible view, let's update it!
bindView(position, view, false);
nVisibleViews--;
}
}
return true;
}
and of course:
当然:
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final View result = createViewFromResource(position, convertView, parent);
m_visibleViews.put(position, result);
return result;
}
Ignore the last param to bindView (I use it to determine whether or not I need to recycle bitmaps for ImageDrawable).
忽略bindView的最后一个参数(我使用它来确定是否需要为ImageDrawable循环位图)。
As mentioned above, the total number of 'visible' views is roughly the amount that fits on the screen (ignoring orientation changes etc), so no biggie memory-wise.
如上所述,“可见”视图的总数大约是适合屏幕的数量(忽略方向变化等),所以没有大的内存。
#9
0
exactly I used this
我用这个
private void updateSetTopState(int index) {
View v = listview.getChildAt(index -
listview.getFirstVisiblePosition()+listview.getHeaderViewsCount());
if(v == null)
return;
TextView aa = (TextView) v.findViewById(R.id.aa);
aa.setVisibility(View.VISIBLE);
}
#10
0
I made up another solution, like RecyclyerView method void notifyItemChanged(int position)
, create CustomBaseAdapter class just like this:
我还创建了另一个解决方案,比如回收clyerview方法void notifyItemChanged(int position),创建CustomBaseAdapter类,如下所示:
public abstract class CustomBaseAdapter implements ListAdapter, SpinnerAdapter {
private final CustomDataSetObservable mDataSetObservable = new CustomDataSetObservable();
public boolean hasStableIds() {
return false;
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
public void notifyItemChanged(int position) {
mDataSetObservable.notifyItemChanged(position);
}
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
public boolean areAllItemsEnabled() {
return true;
}
public boolean isEnabled(int position) {
return true;
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
public int getItemViewType(int position) {
return 0;
}
public int getViewTypeCount() {
return 1;
}
public boolean isEmpty() {
return getCount() == 0;
} {
}
}
Don't forget to create a CustomDataSetObservable class too for mDataSetObservable
variable in CustomAdapterClass, like this:
不要忘记在CustomAdapterClass中为mDataSetObservable变量创建一个CustomDataSetObservable类,如下所示:
public class CustomDataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
public void notifyItemChanged(int position) {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
mObservers.get(position).onChanged();
}
}
}
on class CustomBaseAdapter there is a method notifyItemChanged(int position)
, and you can call that method when you want update a row wherever you want (from button click or anywhere you want call that method). And voila!, your single row will update instantly..
在类CustomBaseAdapter中有一个方法notifyItemChanged(int position),当您想要更新一行时(从按钮单击或您想要调用该方法的任何地方),您可以调用该方法。瞧!,你的单行会即时更新。
#1
185
I found the answer, thanks to your information Michelle. You can indeed get the right view using View#getChildAt(int index)
. The catch is that it starts counting from the first visible item. In fact, you can only get the visible items. You solve this with ListView#getFirstVisiblePosition()
.
我找到了答案,谢谢你的信息,Michelle。您确实可以使用view# getChildAt(int index)获得正确的视图。问题是它开始从第一个可见项开始计数。事实上,你只能得到可见的项目。您可以使用ListView#getFirstVisiblePosition()解决这个问题。
Example:
例子:
private void updateView(int index){
View v = yourListView.getChildAt(index -
yourListView.getFirstVisiblePosition());
if(v == null)
return;
TextView someText = (TextView) v.findViewById(R.id.sometextview);
someText.setText("Hi! I updated you manually!");
}
#2
66
This question has been asked at the Google I/O 2010, you can watch it here:
这个问题已经在谷歌I/O 2010上被提出,你可以在这里观看:
The world of ListView, time 52:30
ListView的世界,时间是52:30。
Basically what Romain Guy explains is to call getChildAt(int)
on the ListView
to get the view and (I think) call getFirstVisiblePosition()
to find out the correlation between position and index.
基本上,Romain Guy解释说的是在ListView上调用getChildAt(int)来获取视图(我认为)调用getFirstVisiblePosition()来找出位置和索引之间的关系。
Romain also points to the project called Shelves as an example, I think he might mean the method ShelvesActivity.updateBookCovers()
, but I can't find the call of getFirstVisiblePosition()
.
Romain还以称为shelf的项目为例,我认为他可能指的是方法shelvesactivity . updatebookcover(),但是我找不到getFirstVisiblePosition()的调用。
AWESOME UPDATES COMING:
很棒的更新来:
The RecyclerView will fix this in the near future. As pointed out on http://www.grokkingandroid.com/first-glance-androids-recyclerview/, you will be able to call methods to exactly specify the change, such as:
回收视图将在不久的将来修复这个问题。正如http://www.grokkingandroid.com/first—androids-view/所指出的,您将能够调用方法来精确地指定更改,例如:
void notifyItemInserted(int position)
void notifyItemRemoved(int position)
void notifyItemChanged(int position)
Also, everyone will want to use the new views based on RecyclerView because they will be rewarded with nicely-looking animations! The future looks awesome! :-)
而且,每个人都希望使用基于回收视图的新视图,因为它们会得到漂亮的动画效果!未来看起来帅呆了!:-)
#3
6
This is how I did it:
我是这样做的:
Your items (rows) must have unique ids so you can update them later. Set the tag of every view when the list is getting the view from adapter. (You can also use key tag if the default tag is used somewhere else)
您的项目(行)必须具有惟一的id,以便稍后更新它们。当列表从适配器获取视图时,设置每个视图的标记。(如果默认标记在其他地方使用,也可以使用key tag)
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View view = super.getView(position, convertView, parent);
view.setTag(getItemId(position));
return view;
}
For the update check every element of list, if a view with given id is there it's visible so we perform the update.
对于更新检查列表中的每个元素,如果有给定id的视图在那里,那么我们执行更新。
private void update(long id)
{
int c = list.getChildCount();
for (int i = 0; i < c; i++)
{
View view = list.getChildAt(i);
if ((Long)view.getTag() == id)
{
// update view
}
}
}
It's actually easier than other methods and better when you dealing with ids not positions! Also you must call update for items which get visible.
它实际上比其他方法更简单,当你处理id而不是位置时更好!还必须为可见的项调用update。
#4
2
The answers are clear and correct, I'll add an idea for CursorAdapter
case here.
答案是清晰和正确的,我将在这里为CursorAdapter case添加一个想法。
If youre subclassing CursorAdapter
(or ResourceCursorAdapter
, or SimpleCursorAdapter
), then you get to either implement ViewBinder
or override bindView()
and newView()
methods, these don't receive current list item index in arguments. Therefore, when some data arrives and you want to update relevant visible list items, how do you know their indices?
如果您正在子类化CursorAdapter(或者ResourceCursorAdapter,或SimpleCursorAdapter),那么您可以实现ViewBinder或override bindView()和newView()方法,这些方法不会在参数中接收当前列表项索引。因此,当一些数据到达并希望更新相关可见列表项时,您如何知道它们的索引?
My workaround was to:
我的解决方法是:
- keep a list of all created list item views, add items to this list from
newView()
- 保存所有创建的列表项视图的列表,从newView()向该列表添加项
- when data arrives, iterate them and see which one needs updating--better than doing
notifyDatasetChanged()
and refreshing all of them - 当数据到达时,迭代它们,看看哪个需要更新——比执行notifyDatasetChanged()和刷新所有它们要好
Due to view recycling the number of view references I'll need to store and iterate will be roughly equal the number of list items visible on screen.
由于视图回收,我需要存储和迭代的视图引用的数量将大致等于屏幕上可见的列表项的数量。
#5
2
get the model class first as global like this model class object
首先将模型类作为全局对象,如这个模型类对象。
SampleModel golbalmodel=new SchedulerModel();
and initialise it to global
并将其推广到全球
get the current row of the view by the model by initialising the it to global model
通过将it初始化为全局模型,通过模型获取视图的当前行
SampleModel data = (SchedulerModel) sampleList.get(position);
golbalmodel=data;
set the changed value to global model object method to be set and add the notifyDataSetChanged its works for me
将更改后的值设置为全局模型对象方法,并添加notifyDataSetChanged它对我的工作。
golbalmodel.setStartandenddate(changedate);
notifyDataSetChanged();
Here is a related question on this with good answers.
这里有一个相关的问题,有很好的答案。
#6
1
I used the code that provided Erik, works great, but i have a complex custom adapter for my listview and i was confronted with twice implementation of the code that updates the UI. I've tried to get the new view from my adapters getView method(the arraylist that holds the listview data has allready been updated/changed):
我使用了提供Erik的代码,效果很好,但是我的listview有一个复杂的自定义适配器,我遇到了两次更新UI的代码实现。我尝试从我的适配器getView方法中获取新的视图(保存listview数据的arraylist已经被更新/更改):
View cell = lvOptim.getChildAt(index - lvOptim.getFirstVisiblePosition());
if(cell!=null){
cell = adapter.getView(index, cell, lvOptim); //public View getView(final int position, View convertView, ViewGroup parent)
cell.startAnimation(animationLeftIn());
}
It's working well, but i dont know if this is a good practice. So i don't need to implement the code that updates the list item two times.
它运行得很好,但我不知道这是否是一个好的实践。所以我不需要实现两次更新列表项的代码。
#7
1
int wantedPosition = 25; // Whatever position you're looking for
int firstPosition = linearLayoutManager.findFirstVisibleItemPosition(); // This is the same as child #0
int wantedChild = wantedPosition - firstPosition;
if (wantedChild < 0 || wantedChild >= linearLayoutManager.getChildCount()) {
Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
return;
}
View wantedView = linearLayoutManager.getChildAt(wantedChild);
mlayoutOver =(LinearLayout)wantedView.findViewById(R.id.layout_over);
mlayoutPopup = (LinearLayout)wantedView.findViewById(R.id.layout_popup);
mlayoutOver.setVisibility(View.INVISIBLE);
mlayoutPopup.setVisibility(View.VISIBLE);
For RecycleView please use this code
请使用此代码
#8
0
My solution: If it is correct*, update the data and viewable items without re-drawing the whole list. Else notifyDataSetChanged.
我的解决方案:如果是正确的*,更新数据和可查看的项目,而不重新绘制整个列表。notifyDataSetChanged。
Correct - oldData size == new data size, and old data IDs and their order == new data IDs and order
正确的- oldData size ==新的数据大小,旧的数据id和它们的order ==新的数据id和顺序。
How:
怎样去:
/**
* A View can only be used (visible) once. This class creates a map from int (position) to view, where the mapping
* is one-to-one and on.
*
*/
private static class UniqueValueSparseArray extends SparseArray<View> {
private final HashMap<View,Integer> m_valueToKey = new HashMap<View,Integer>();
@Override
public void put(int key, View value) {
final Integer previousKey = m_valueToKey.put(value,key);
if(null != previousKey) {
remove(previousKey);//re-mapping
}
super.put(key, value);
}
}
@Override
public void setData(final List<? extends DBObject> data) {
// TODO Implement 'smarter' logic, for replacing just part of the data?
if (data == m_data) return;
List<? extends DBObject> oldData = m_data;
m_data = null == data ? Collections.EMPTY_LIST : data;
if (!updateExistingViews(oldData, data)) notifyDataSetChanged();
else if (DEBUG) Log.d(TAG, "Updated without notifyDataSetChanged");
}
/**
* See if we can update the data within existing layout, without re-drawing the list.
* @param oldData
* @param newData
* @return
*/
private boolean updateExistingViews(List<? extends DBObject> oldData, List<? extends DBObject> newData) {
/**
* Iterate over new data, compare to old. If IDs out of sync, stop and return false. Else - update visible
* items.
*/
final int oldDataSize = oldData.size();
if (oldDataSize != newData.size()) return false;
DBObject newObj;
int nVisibleViews = m_visibleViews.size();
if(nVisibleViews == 0) return false;
for (int position = 0; nVisibleViews > 0 && position < oldDataSize; position++) {
newObj = newData.get(position);
if (oldData.get(position).getId() != newObj.getId()) return false;
// iterate over visible objects and see if this ID is there.
final View view = m_visibleViews.get(position);
if (null != view) {
// this position has a visible view, let's update it!
bindView(position, view, false);
nVisibleViews--;
}
}
return true;
}
and of course:
当然:
@Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
final View result = createViewFromResource(position, convertView, parent);
m_visibleViews.put(position, result);
return result;
}
Ignore the last param to bindView (I use it to determine whether or not I need to recycle bitmaps for ImageDrawable).
忽略bindView的最后一个参数(我使用它来确定是否需要为ImageDrawable循环位图)。
As mentioned above, the total number of 'visible' views is roughly the amount that fits on the screen (ignoring orientation changes etc), so no biggie memory-wise.
如上所述,“可见”视图的总数大约是适合屏幕的数量(忽略方向变化等),所以没有大的内存。
#9
0
exactly I used this
我用这个
private void updateSetTopState(int index) {
View v = listview.getChildAt(index -
listview.getFirstVisiblePosition()+listview.getHeaderViewsCount());
if(v == null)
return;
TextView aa = (TextView) v.findViewById(R.id.aa);
aa.setVisibility(View.VISIBLE);
}
#10
0
I made up another solution, like RecyclyerView method void notifyItemChanged(int position)
, create CustomBaseAdapter class just like this:
我还创建了另一个解决方案,比如回收clyerview方法void notifyItemChanged(int position),创建CustomBaseAdapter类,如下所示:
public abstract class CustomBaseAdapter implements ListAdapter, SpinnerAdapter {
private final CustomDataSetObservable mDataSetObservable = new CustomDataSetObservable();
public boolean hasStableIds() {
return false;
}
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
public void notifyItemChanged(int position) {
mDataSetObservable.notifyItemChanged(position);
}
public void notifyDataSetInvalidated() {
mDataSetObservable.notifyInvalidated();
}
public boolean areAllItemsEnabled() {
return true;
}
public boolean isEnabled(int position) {
return true;
}
public View getDropDownView(int position, View convertView, ViewGroup parent) {
return getView(position, convertView, parent);
}
public int getItemViewType(int position) {
return 0;
}
public int getViewTypeCount() {
return 1;
}
public boolean isEmpty() {
return getCount() == 0;
} {
}
}
Don't forget to create a CustomDataSetObservable class too for mDataSetObservable
variable in CustomAdapterClass, like this:
不要忘记在CustomAdapterClass中为mDataSetObservable变量创建一个CustomDataSetObservable类,如下所示:
public class CustomDataSetObservable extends Observable<DataSetObserver> {
public void notifyChanged() {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onChanged();
}
}
}
public void notifyInvalidated() {
synchronized (mObservers) {
for (int i = mObservers.size() - 1; i >= 0; i--) {
mObservers.get(i).onInvalidated();
}
}
}
public void notifyItemChanged(int position) {
synchronized(mObservers) {
// since onChanged() is implemented by the app, it could do anything, including
// removing itself from {@link mObservers} - and that could cause problems if
// an iterator is used on the ArrayList {@link mObservers}.
// to avoid such problems, just march thru the list in the reverse order.
mObservers.get(position).onChanged();
}
}
}
on class CustomBaseAdapter there is a method notifyItemChanged(int position)
, and you can call that method when you want update a row wherever you want (from button click or anywhere you want call that method). And voila!, your single row will update instantly..
在类CustomBaseAdapter中有一个方法notifyItemChanged(int position),当您想要更新一行时(从按钮单击或您想要调用该方法的任何地方),您可以调用该方法。瞧!,你的单行会即时更新。