使用Thread的Android While-Loop

时间:2014-07-23 11:24:41

标签: android multithreading loops user-interface while-loop

我试图创建一个将运行While循环的线程,并在while-loop中执行将会更改UI的操作:

public void GameHandler()
{
    layout = (RelativeLayout) findViewById(R.id.MyLayout);
    params=new RelativeLayout.LayoutParams(30,40);
    btn1 = (Button) findViewById(R.id.MovingObj);
    xBounds=new int[2];
    yBounds=new int[2];
    xBounds[0]=0;
    xBounds[1]=layout.getWidth();
    yBounds[0]=0; //will change once i set up the screen settings !
    yBounds[1]=layout.getHeight();
    selectFlyingObject();

    Runnable myRunnable = new Runnable() {
        @Override
        public void run() {
            while (CurrentXLocation <= xBounds[1] + 10) {
                CurrentXLocation = CurrentXLocation + 1;
                params.leftMargin = CurrentXLocation;
                params.topMargin = 50;
                btn1.setLayoutParams(params);
                SystemClock.sleep(1000 - SpeedRate);
            }
        }
    };
    Thread myThread = new Thread(myRunnable);
    myThread.start();
}

但是我的第一个问题是发生以下错误:

 Only the original thread that created a view hierarchy can touch its views.

并且第二个问题是我听说在后台使用线程将消耗太多的设备CPU,这可能导致我的应用程序崩溃。这样的事情确实发生了吗? 谢谢你的回答

2 个答案:

答案 0 :(得分:2)

首先,我建议您阅读this article,因为您正在使用的当前构造有点......脏......

无论如何,为了回应您正在接收的实际错误,很明显您无法从后台线程更新UI线程。 为什么?因为如果可以的话,想象一下10个不同的线程同时更新UI。那会给出看起来很漂亮的应用程序,不是吗? 此外,它还意味着需要锁定,同步每个UI元素,以便提供或多或少的一致行为。这将使线程执行“艰苦工作”的目的失败,他们将依赖于UI。

(如果有人能够给出明确的理由/参考指南和/或理由发表评论,我会调整答案)

因此,在Android中,您可以获得主Looper,一个用于按顺序执行任务的实用程序,在指定的线程上执行。 我们在此做的,实际上是将我们的操作排队在主线程上执行。

public class GameHandler implements Runnable {

    Handler mHandler = new Handler(Looper.getMainLooper());

    Layout mLayout;
    View mView;
    int currentX, mSpeedRate;

    public GameHandler(Layout layout, View viewToAnimate, int speedRate) {
        mLayout = layout;
        mView = viewToAnimate;
        mSpeedRate = speedRate;
    }

    public void handleGame() {


        final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(30, 40);

        int[] xBounds = new int[2];
        int[] yBounds = new int[2];
        xBounds[0] = 0;
        xBounds[1] = mView.getWidth();
        yBounds[0] = 0; //will change once i set up the screen settings !
        yBounds[1] = mView.getHeight();
        selectFlyingObject();

        while ( currentX <= xBounds[1] + 10 ) {
            currentX = currentX + 1;
            params.leftMargin = currentX;
            params.topMargin = 50;
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mView.setLayoutParams(params);
                }
            });
            SystemClock.sleep(1000 - mSpeedRate);
        }
    }

    void selectFlyingObject() {
        // No idea what you're doing here, but keep in mind you're still working on the
        // background thread if you call this method from somewhere not wrapped in the mHandler
    }

    @Override
    public void run() {
        handleGame();
    }
}

免责声明,此代码未经测试且从我的头脑中开始。如果它没有做你认为它应该做的事情,请随意提及。

结构已经过调整,您现在要做的就是在尝试时启动线程,或者使用Executor

Thread myThread = new Thread(new GameHandler());
myThread.start();

如果我对该主题不够清楚,这些链接仅供参考:

答案 1 :(得分:0)

&#34;我听说过......&#34;不是一个特别可靠的信息来源。使用后台线程在Android中绝对没问题。每秒产生不朽的线程会导致应用程序崩溃,就像制作一个无限循环一样 - 并且使用来自其他开发者的相同评论。

你的问题&#34;是不言自明的 - 因为UI工具箱中的每个Java并发教程都指出 - 不要从背景线更新UI 。使用众多机制之一向UI线程发送信号来执行此操作。在你的情况下 - Timer很适合(它会每隔x秒唤醒并执行一次运行)。