notifyDataSetChanged只刷新一次GridView,尽管被多次调用

时间:2011-11-02 23:57:12

标签: android

我将尝试按如下方式汇总我的代码:

  • 我有一个TileAdapter,它从BaseAdapter扩展到填充GridView
  • 我的TileAdapter包含一组用于维护状态的Tiles
  • 我的TileUpdate类执行以下操作:
    1. 将Tile A的颜色更改为绿色
    2. 调用TileAdapter.notifyDataSetChanged()
    3. 将Tile B的颜色更改为黄色
    4. 调用TileAdapter.notifyDataSetChanged()
    5. 将Tile B的颜色更改为红色
    6. 调用TileAdapter.notifyDataSetChanged()

我希望看到我的GridView刷新3次,每次调用notifyDataSetChanged()一次。

但是,我只看到它在第6步之后刷新,当时并且从未看到Tile B变黄。

这里发生了什么?我认为有一些我不知道的API。

由于

更新

即使在研究了下面描述的Handler方法之后,我仍未成功实现这一点。 所以在我的UI线程中,我创建了一个新的GridOperationQueue类,它从Thread:

扩展而来
public class GridOperationQueue extends Thread {
private Handler handler;

@Override
public void run() {
    Looper.prepare();

    handler = new Handler();

    Looper.loop();  

}

public void addTaskToQueue(final GridUpdateTask task)
{
    Log.d(this.getClass().toString(), "Current thread is ID " + Thread.currentThread().getId());
    handler.post(new Runnable()
    {
        @Override
        public void run() {
            Log.d(this.getClass().toString(), " Handler task's current thread is ID " + Thread.currentThread().getId());
            task.run();
        }

    });
}

public void clearQueue(){
    handler.removeCallbacksAndMessages(null);
}

}

所以我的UI线程调用addTaskToQueue提供一个新的Task对象。我们的想法是,任务的处理将在一个单独的线程上执行,并在完成后在UI线程上调用notifyDataSetChanged()。 但是,我添加了一些日志记录,似乎当我的任务运行时,它们仍然在主线程上运行......这将是什么?请参阅以下日志记录:

GridOperationQueue(4393): Current thread is ID 1
GridOperationQueue(4393): Current thread is ID 1
GridOperationQueue(4393): Current thread is ID 1
GridOperationQueue$1(4393):  Handler task's current thread is ID 9
TileOperationService$1(4393): Current thread is ID 9
MyActivity(4393): Current thread is ID 9
GridOperationQueue$1(4393):  Handler task's current thread is ID 9
TileOperationService$2(4393): Current thread is ID 9
MyActivity(4393): Current thread is ID 9
GridOperationQueue$1(4393):  Handler task's current thread is ID 9
TileOperationService$3(4393): Current thread is ID 9
MyActivity(4393): Current thread is ID 9

为什么任务仍然在主线程上运行?

3 个答案:

答案 0 :(得分:2)

我假设您在onClick方法中进行了所有这些更改。 onClick方法在UI线程中运行...因此,当onClick中的代码正在运行时,UI线程无法更改并且因为它忙碌而平铺颜色。事实上,notifyDataSetChanged只是设置一个标志,告诉Android更新视图的更改; notifyDataSetChanged不强制更新,但简单告诉android一个是必需的。因此,你只是告诉android它需要更新视图三次...但是,当android实际上可以进行更新时,这是在你的onClick方法完成之后,它只能看到最近对tile的更改颜色。

你如何解决这个问题?那么,这取决于你真正想做的事情。例如,如果您希望在单击视图时将图块颜色A更改为图块颜色B,然后在500毫秒后更改为图块颜色C,请执行以下操作

Handler handler; // instance var
public onCreate(Bundle savedInstanceState) {
  ...
  handler = new Handler();
}

// in your onClick method, wherever it may be (pseudocode)
public void onClick(View v) {
  1) set tile color to color B
  2) call notifyDataSetChanged
  3) schedule a color change in 500 ms:
     handler.postDelayed(new Runnable() {
       public void run() {
         1) set tile color to color C
         2) call notifyDataSetChanged
       }
     }), 500);

答案 1 :(得分:1)

你应该看看Updating the UI from a Timer。麻烦的是,当你调用notifyDataSetChanged()时,你只会触发GUI的标志。当适配器获得重绘时,它会检查标志是否已设置并执行操作。当您致电通知时, 不会直接采取任何行动。

如果您想直接更新GUI,您应该了解类Handler(请参阅上一个链接),以便您可以将更新发布到界面。

答案 2 :(得分:0)

也许我误解了你的问题,但似乎你正在更新两次Tile B的颜色(在你的问题上完全相同的步骤3和5)。如果是这种情况,当然只能看到最后一种颜色(红色)和黄色。

或者,您在步骤5中的意思是“Tile C”。如果是这种情况,则以下注释可能有所帮助:

即使用户界面正在改变3次,您也可能会在每次通话时覆盖每种颜色。

1)所以你的三个瓷砖是'默认'颜色

2)您将Tile A更新为绿色

3)调用notifyDataSetChanged()

(您的网格视图已正确更新)

4)您将Tile B更新为黄色

5)调用notifyDataSetChanged()

(您的网格视图会将标题B更新为黄色,但会将标题A更改为“默认”颜色。

6)您将Tile C更新为红色

7)调用notifyDataSetChanged()

(您的网格视图会将标题C更新为红色,但会将标题A和B重写为“默认”颜色。

这可能就是问题所在。

另外,请记住,正如其他人提到的那样,notifyDataSetChanged()没有直接做任何事情。它仅表示在满足理想条件时刷新UI。