Android: обновление gridview несколько раз через x секунд

У меня проблема с обновлением представления в Android каждые x секунд.

Чтобы узнать, как работает Android, я пишу небольшую игру. Он имеет GameController, который содержит игровой цикл. Внутри цикла выполняется логика, после чего графический интерфейс будет проинформирован об изменениях.

Проблема в том, что изменения не видны в представлении. Вид остается неизменным до тех пор, пока игровой цикл не завершится и не обновится только один раз.

Вот мой код (важные части):

GameController.java:

IGui gui;

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

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

GameActivity.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
}

TextAdapter.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, и если они работают в одном потоке, логика блокирует представление. Любая помощь будет принята с благодарностью.

// редактировать:

Если я попробую новый поток (с).start(); LogCat sais: java.lang.RuntimeException: не может создать обработчик внутри потока, который не вызвал Looper.prepare()

И если я добавлю Looper.prepare();: java.lang.RuntimeException: невозможно запустить действие ComponentInfo{GameActivity}: java.lang.RuntimeException: только один лупер может быть создан для потока

Если я попробую this.runOnUiThread(c); нет ошибок

3 ответа

Решение

Во-первых, это не похоже на способ создания игры, вам нужно будет использовать SurfaceView, или же GLSurfaceView лучше делать то, что ты хочешь. Вы также можете найти Cocos2d для 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...
            }
        }
    };

Это относится ко всему, что требует интенсивной обработки / сетевого взаимодействия, которое не должно блокировать ваш поток пользовательского интерфейса.

Надеюсь это поможет.

Не уверен, что вы пытаетесь достичь, обновляя listView каждые несколько секунд. В любом случае, если вы пишете 2d игры, вы должны использовать SurfaceView, который специально предназначен для постоянного освежения.

Была такая же проблема и решена с помощью довольно простого кода.

Подсказки:

  • GridView должен обновляться потоком пользовательского интерфейса
  • Чтобы отобразить каждое изменение, вы должны держать цикл и метод Sleep подальше от потока пользовательского интерфейса.


Решение:

  • Метод обновления сетки (добавьте в свою активность то, что вы создаете GridView на первом месте или где бы то ни было)

    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();
    

    }

  • Создайте не-пользовательский поток, который делает работу

открытый класс 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();
        }
    }

}

}

Другие вопросы по тегам