【问题标题】:Threading UI updates in Android在 Android 中线程化 UI 更新
【发布时间】:2011-04-14 07:26:13
【问题描述】:

我刚开始进行 android 开发,更新 UI 真的很困扰我:/

这就是我到目前为止所做的工作 -

打包项目。移动; 导入android.os.Bundle; 导入android.view.View; 导入android.app.Activity; 导入android.content.Context; 导入android.graphics.Canvas; 导入android.graphics.Paint; 导入android.graphics.Color; 公共类移动扩展活动{ 私人浮动 y = 0; 私人多头现在= 0; 私人浮动延迟= 75; 私人油漆油漆=新油漆(); @覆盖 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new SimpleMotion(this)); 油漆.setColor(颜色。黑色); } 私有类 SimpleMotion 扩展视图 { 公共 SimpleMotion(上下文上下文){ 超级(上下文); } @Override protected void onDraw(Canvas canvas) { 浮动 x = canvas.getWidth() / 2; canvas.drawColor(Color.WHITE); canvas.drawCircle(x, y, 30, 油漆); if(System.currentTimeMillis() - 现在 > 延迟) y++; 无效(); } } }

它工作得很好,但是每个人都说在主线程中做你的图形,所以我正在尝试(并且失败)将它传递给另一个线程。麻烦的是,我完全不知道为什么我从来没有使用过线程。

Google 提供的关于使用 Threads 的示例似乎不是很清楚,我无法真正按照自己的意愿去做。我可以请这里的人给我一个最基本的例子,说明如何使用 Threads 有效地做我正在做的事情吗?

提前致谢:)

【问题讨论】:

    标签: java android multithreading user-interface


    【解决方案1】:

    嗯,我想这里发生了一些混乱。您必须从主线程(也称为 GUI 线程)进行 GUI 更新 - 否则您会得到类似“异常,blabla 已泄露视图”之类的信息。

    我想有什么误解是昂贵的操作,比如网络,应该在与主线程不同的线程中完成。如果您想从网络线程更新 GUI,您可以按照 ArtWorkAD 所说(或他的链接所说)进行操作。

    因此,对于您想要做的事情,您可以通过将 SimpleMotion 类替换为以下内容来实现:

    private class SimpleMotion extends View {
    
            public SimpleMotion(Context context) {
                super(context);
    
                new Thread(new Runnable() {
                    public void run() {
                        while(true){
                            try {
                                Thread.sleep(75);
                                y++;
                                postInvalidate();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                  }).start();
            }
    
            @Override protected void onDraw(Canvas canvas) {
    
                float x = canvas.getWidth() / 2;
                canvas.drawColor(Color.WHITE);
                canvas.drawCircle(x, y, 30, paint);  
    //            if(System.currentTimeMillis() - now > delay) y++;    
    //            invalidate();
            }
        }
    

    使用您在onDraw() 中包含invalidate() 的旧代码,即使没有对其进行任何更改,您也将不断重绘gui。

    新代码的重要部分是postInvalidate()。这使得可以告诉 GUI 线程 - 从另一个线程 - 重绘 GUI。

    【讨论】:

    • 顺便说一句,由于您是线程新手,因此您应该阅读它们。并确保在不需要它们运行时停止它们。否则即使按“返回”或“主页”,它也会在后台继续运行。
    • 谢谢,正是我想要的。我可以假设 postInvalidate() 函数总是引用主 UI 线程,所以无论您在项目中调用它的任何位置,它都会调用主 UI 的 onDraw() 函数?
    • 编辑时间到了:经过一番思考,显然它不能一直引用主 UI 线程。那么如何让它引用另一个类中的视图呢?
    • 嗯,我的回答有些模糊。但是 invalidate 只会使特定的 View 无效。视图可以是按钮、复选框或在您的情况下是自定义视图。一个活动可以存在多个视图。因此,要从另一个线程更新(或更确切地说是无效)特定视图,您首先会获得类似“Button btn = (Button) findViewById(R.id.button);”的视图,然后调用 btn.postInvalidate();
    【解决方案2】:

    您可以使用 AsyncTask 进行线程处理,基础:painless threading,例如:Multithreading For Performance

    要使用更新处理程序更新 UI,请查看 this。每次您想更新 UI 时,您都会从线程向主 ui 线程发送一条消息。

    【讨论】:

      【解决方案3】:

      第一个问题是——为什么要在单独的线程中制作图形?因为除非您正在做一些特定的事情(主要是在游戏或媒体领域),否则如果您尝试这样做,您会发现自己陷入了很多痛苦之中。

      【讨论】:

        【解决方案4】:

        您最终可能会使用您提供的代码对 invalidate() 进行大量不必要的调用(并因此重绘)。最好使用处理程序触发 y 参数(和无效)的更改,您也可以延迟触发。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-14
          • 1970-01-01
          相关资源
          最近更新 更多