1

我在每 x 秒更新一次 android 中的视图时遇到问题。

为了了解 android 的工作原理,我正在编写一个小游戏。它有一个保存游戏循环的 GameController。在循环内部,逻辑被执行,之后 gui 将被告知更改。

问题是在视图中看不到更改。视图保持不变,直到游戏循环完成并且只更新一次。

这是我的代码(重要部分):

游戏控制器.java:

IGui gui;

public void play() {
    while (playing) {
        getAndProcessInput();
        updateGui();
        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
        }
    }
}

private void updateGui() {
    gui.setPlayer(x, y);
    // ...
}

游戏活动.java:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    GridView gridview = (GridView) findViewById(R.id.GridView1);
    TextAdapter = new TextAdapter(this);
    gridview.setAdapter(textAdapter);

    GameController c = new GameController();

    // here, the game loop shoud start.
    // what i tried:

    // new Thread(c).start();   <-- causes crash

    // c.play();     <-- causes view to frease until game loop is done

    this.runOnUiThread(c);  <-- causes view to frease until game loop is done
}

文本适配器.java:

public class TextAdapter extends BaseAdapter implements IGui {

    private final Context context;
    private final String[] texts;

    public TextAdapter(Context context) {
        this.context = context;
        texts = new String[height * width];
        for (int i = 0; i < texts.length; i++) {
            texts[i] = " ";
        }
    }

    public int getCount() {
        return height * width;
    }

    public Object getItem(int position) {
        return null;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        TextView tv;
        if (convertView == null) {
            tv = new TextView(context);
            tv.setLayoutParams(new GridView.LayoutParams(25, 25));
        } else {
            tv = (TextView) convertView;
        }

        tv.setText(texts[position]);
        return tv; // <-- this happens only when game loop is done, not everytime something changed
    }

    @Override 
    public void setPlayer(int x, int y) {
        texts[width * y + x] = "X";
        // this.notifyDataSetChanged();  <-- this does not help (view still freases) 
        //                                   gridview.invalidateViews(); does not help either
    }
}

我用谷歌搜索了很多,也尝试了很多(我确实知道这里已经问过类似的问题,但他们也没有帮助我),但不知何故它不起作用。我无法让视图和逻辑在 android 的不同线程上运行,如果它们在同一个线程上运行,逻辑会阻塞视图。任何帮助将不胜感激。

// 编辑:

如果我尝试 new Thread(c).start(); LogCat sais:java.lang.RuntimeException:无法在未调用 Looper.prepare() 的线程内创建处理程序

如果我添加 Looper.prepare(); : java.lang.RuntimeException: 无法启动活动 ComponentInfo{GameActivity}: java.lang.RuntimeException: 每个线程只能创建一个 Looper

如果我尝试 this.runOnUiThread(c); 没有错误。

4

3 回答 3

2

首先,这似乎不是创建游戏的方式,您需要使用SurfaceView,或者GLSurfaceView更好地做您想做的事情。你也可以寻找 Cocos2d for android,它是一个 2D 平台(从 iPhone 移植而来),让你的生活更轻松: http ://code.google.com/p/cocos2d-android/ 不过我想警告你,我试过了几个月前,它还不是生产级,它确实不时崩溃。

无论如何,如果您仍想继续前进,我将尝试回答您的问题:我认为您对这些东西的工作方式太混乱了。尝试首先了解处理程序如何与线程一起工作。

在你的线程上做任何你想做的事情:

   new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    try
                    {
                        calculateGameChangesHere();
                        handler.sendEmptyMessage(SUCCESS);
                    }
                    catch (Exception e)
                    {
                        handler.sendEmptyMessage(FAILURE);
                    }
                }
            }).start();

当你的数据准备好后,告诉处理程序把它放在一个视图中并显示它:

protected Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            if (msg.what == SUCCESS)
            {
                setCalculatedDataToaView(); // the data you calculated from your thread can now be shown in one of your views.
            }
            else if (msg.what == FAILURE)
            {
                errorHandlerHere();//could be your toasts or any other error handling...
            }
        }
    };

这适用于需要大量处理/网络且不应阻塞您的 UI 线程的所有内容。

希望这可以帮助。

于 2012-01-20T21:39:14.083 回答
0

listView通过每隔几秒钟刷新一次,不确定您要达到什么目的。无论如何,如果您正在编写一些 2d 游戏,则必须使用SurfaceView,这尤其适用于持续刷新。

于 2012-01-20T21:31:31.487 回答
0

有同样的问题并使用非常简单的代码解决了它。

尖端:

  • GridView 必须由 UI 线程刷新
  • 要显示每个更改,您必须使循环和 Sleep 方法远离 UI 线程


解决方案:

  • 更新网格的方法(放在您在第一个地方或任何地方构建 GridView 的 Activity 上)

    public void UpdateGrid(){
    //your logic
    
    //your way to change grid values (there are tones of other ways)
    CustomGridAdapter cga = new CustomGridAdapter(this, values);
    
    gridView.setAdapter(cga);
    gridView.invalidateViews();
    

    }

  • 构建完成工作的非 UI 线程

公共类 DataReceiver 实现 Runnable {

private MainActivity mainActivity;

public DataReceiver(MainActivity ma) {
    mainActivity = ma;
}

@Override
public void run() {

    for (int i = 0; i < 100; i++) {

        mainActivity.runOnUiThread(new Runnable() {
            public void run() {
                                   //update the grid here
                mainActivity.UpdateGrid();

            }
        });
                      //sleep here
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

}

于 2014-05-17T17:39:37.890 回答