调用onClick时更改ImageButton的图像

Mur*_*PAY 1 android android-widget

我有一个ImageButton,它在单击时执行长时间运行的操作.所以我试图做的不成功的是在onClick调用开始时更改图像并在结束时将其更改回来.

我已经尝试了下面的代码,但我发现在onClick完成后android重绘了按钮图像,所以没用.

如果可能的话,我也愿意采取其他方式来做到这一点.

下面是我使用的代码片段.Thread.sleep表示长时间运行的操作.我想在执行到达睡眠状态时看到图像更改,而不是在onClick完成后.

btnTest = (ImageButton) findViewById(R.id.btnTest);
btnTest.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
    System.out.println("start");
    btnTest.setImageResource(R.drawable.add);
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
    }

    System.out.println("end");
    btnTest.setImageResource(R.drawable.del);
}
});
Run Code Online (Sandbox Code Playgroud)

cla*_*ker 6

您的问题是您sleep()(或以其他方式阻止)UI线程.请理解main/UI线程负责重绘和所有事件处理.如果你在那里睡觉(onClick()在UI线程上执行),那么Android将无法做任何与用户界面相关的事情.

背景是多线程GUI效率极低.大多数与UI相关的调用,例如setBackground,简单地设置一些数据,甚至调度一些更多的活动,都没有立竿见影的效果,并且只有在控件返回到主UI线程控制循环时才会产生结果,例如用于协调重绘.试想一下,如果你一个接一个地发布了几个布局变化并且每一个都会被立即处理会发生什么 - 这会导致大量的计算在下一刻变得无效.

所以主线程只不过是处理各种回调的巨大循环,包括Activity生命周期方法,事件监听器回调等.所以如果你愿意,UI是单线程的.

您需要做的是在AsyncTask或线程上执行长时间运行的操作.对于初学者,我会尝试一下AsyncTask.在onPostExecute()再次在UI线程上运行的AsyncTask 方法中,您可以根据需要操作用户界面.

为了快速成功,您还可以使用线程:

@Override
public void onClick(View v) {
    // on UI thread
    btnTest.setImageResource(R.drawable.add);
    // launch concurrent thread
    (new Thread(new Runnable() {
            @Override
            // the code of this method will run concurrently
            public void run() {
                System.out.println("start");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {}
                System.out.println("end");
                // at this point, we need to get back to the UI thread
                // for simplicity, we use the view's convenience method for that
                v.post(new Runnable() {
                    @Override
                    // the code of this method will run on the UI thread
                    public void run() {
                       btnTest.setImageResource(R.drawable.del);
                    }
                })
            }
        })
    ).start();
}
Run Code Online (Sandbox Code Playgroud)

AsyncTask 看起来更好,但它不容易创建和即时使用.

请注意,上面的代码创建了一个Thread将运行,直到它离开其run()方法,或Android杀死托管您的应用程序的Linux进程.

另请注意,此Thread保存对代码中许多对象的引用,因为它可以从其周围的范围访问所有内容.

结论是,如果您的Thread确实运行了很长时间,它可以保存对View甚至不再可见的引用,因此僵尸内存对象可能会恶化应用程序的资源消耗.

另外,你提到你在那里进行长时间的操作.问题是,该操作是等待还是计算某些东西.如果它计算某些东西,你可能会发现它现在需要十倍的时间,除非你按照这里描述调整AsyncTask/ Thread优先级.