2

我正在开发一个 Android 应用程序,其中有一些列表。它比我在这里解释的要复杂,但我发布的场景也表现出意外。
我一直在 Stack Overflow 中浏览几个问题,但我发现没有一个可以解决这个问题。

所以,为了这个问题,我已经建立了这个场景。我有一个带有字符串数组的活动,如下所示:

public class TestViewlazyloadActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        String[] items = { "lorem", "ipsum", "dolor", "sit", "amet" };

        ListView list = (ListView) findViewById(R.id.testListView);
        TestAdapter adapter = new TestAdapter(this, R.layout.list_item, items);

        list.setAdapter(adapter);
    }
}

以这种方式成为我的两种布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
       android:orientation="vertical" >

    <ListView
        android:id="@+id/testListView"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >
    </ListView>

</LinearLayout>

这样:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/testTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

很简单。然后我用ViewHolder的思想实现了一个ArrayAdapter类,getView()方法如下:

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    String item = this.getItem(position);

    if(convertView == null) {
        LayoutInflater inflater = ((Activity) this.getContext()).getLayoutInflater();
        convertView = inflater.inflate(R.layout.list_item, null);

        holder = new ViewHolder();
        holder.textView = (TextView) convertView.findViewById(R.id.testTextView);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }

    final ViewHolder auxHolder = holder;
    LoadingService.capitalizeItemWithDelay(item, new LoadedCallback() {
        public void onItemLoaded(String item) {
            auxHolder.textView.setText(item);
        }
    });

    return convertView;
}

作为LoadedCallback与 just 的接口onItemLoaded。并且LoadingService.capitalizeItemWithDelay()只是启动一个随机休眠的线程(以模拟延迟加载)并使用大写字符串调用此回调。

正常行为应该是用户正在查看包含 5 个空白行的列表。一段时间后,项目开始在各自的行中生成,即使在给定随机睡眠计时器的情况下也是随机顺序。

真正发生的是,项目被一个接一个地加载到第一行,最终它们中的一些被设置在它们的真实位置。这就像auxHolder在其 TextView 中保留对第一个元素的引用,这很奇怪。我知道这要么是因为视图被回收,要么是因为auxHolder存在final.

有任何想法吗?提前致谢。

4

2 回答 2

1

摆脱final你的ViewHolder变量并ViewHolder auxHolder进入内部类。

尝试这个:

   ... 
    LoadingService.capitalizeItemWithDelay(item, new LoadedCallback() {
        ViewHolder auxHolder = holder;
        public void onItemLoaded(String item) {
            auxHolder.textView.setText(item);

当您将final关键字与局部变量(例如)一起使用时auxHolder,您是在说您给它的值是它将具有的最后一个值。这就是您遇到问题的原因。这是一个可以更好地解释的链接:http ://www.javapractices.com/topic/TopicAction.do?Id=23

于 2012-08-14T13:04:57.187 回答
0

您可能没有在 UI 线程上进行更新。我会尝试在帖子中执行您的加载操作,看看是否可以解决所有问题。尝试做这样的事情

convertView.post(new Runnable() {
    @Override
    public void run() {
        LoadingService.capitalizeItemWithDelay(item, new LoadedCallback() {
            ViewHolder auxHolder = holder;
            public void onItemLoaded(String item) {
                auxHolder.textView.setText(item);
            }
        }
   }
});
于 2012-08-14T13:31:16.597 回答