我将尝试如下总结我的代码:
- 我有一个TileAdapter从BaseAdapter扩展到填充GridView
- My TileAdapter包含一个tile数组,用于维护状态 我的TileUpdate类执行以下操作:
- 将Tile A的颜色更改为绿色
- 调用TileAdapter.notifyDataSetChanged ()
- 将Tile B的颜色改为黄色
- 调用TileAdapter.notifyDataSetChanged ()
- 将Tile B的颜色更改为红色
- 调用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提供一个新的任务对象。这个想法是,任务的处理将在一个单独的线程上执行,并在它完成后调用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
为什么任务还在主线程上运行?
我假设您在onClick方法中进行了所有这些更改。onClick方法在UI线程中运行…因此,当onClick中的代码正在运行时,UI线程不能更改和平铺颜色,因为它很忙。事实上,notifyDataSetChanged只是设置了一个标志,告诉Android在它可以时更新对视图的更改;notifyDataSetChanged不强制更新,但简单地告诉android一个需要。因此,你只是告诉android它需要更新视图三次…但是,在你的onClick方法完成之后,android实际上可以进行更新,它只能看到最近的瓷砖颜色变化。
你怎么解决这个问题?嗯,这取决于你真正想做什么。例如,如果您希望在单击视图时将颜色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);
你应该看看从计时器更新UI。问题是,当您调用notifyDataSetChanged()
时,您只会触发GUI的标志。当适配器获得重新绘制时,它检查是否设置了标志并采取行动。当你调用notify时,不直接采取任何动作。
如果你想直接更新GUI,你应该了解类Handler(见前面的链接),这样你就可以发布更新到接口。
也许我误解了你的问题,但似乎你正在更新两倍的颜色Tile B(相同的步骤3和5在你的问题)。如果是这种情况,您将只看到最后一种颜色(红色),当然,黄色将永远不会显示。
或者,你指的是步骤5中的"Tile C"。如果是这种情况,那么下面的注释可能会有所帮助:
即使UI改变了3次,你也可能在每次调用中重写每种颜色。
1)所以你的三个贴图是'默认'颜色
2)你将贴图A更新为绿色
3) notifyDataSetChanged()调用
(你的网格视图更新正确)
4)你将Tile B更新为黄色
5) notifyDataSetChanged()被调用(你的网格视图更新标题B为黄色,但覆盖标题A为'默认'颜色。
6)你将C块更新为红色
7) notifyDataSetChanged()被调用(你的网格视图更新标题C为红色,但覆盖标题A和B为'默认'的颜色。
这可能就是问题所在。
另外,请记住,正如其他人提到的,notifyDataSetChanged()不直接做任何事情。它仅在满足理想条件时才通知UI刷新。