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