Android SurfaceView/Thread for update games states - android

I'm developing a small game on Android and I have a question. I want my main game loop to be the thread that is called from the SurfaceView but every time I want to call a method of another class from this thread I get the "stopped unexpectedly" message.
To be more clear:
#Override
public void run() { //Game Loop
Canvas canvas = null;
while (mRun) {
canvas = mHolder.lockCanvas();
if (canvas != null) {
grub.updateGrubber(); //here I want to update state.
mPanel.doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
}
}
the line grub.updateGrubber(); show the error that I mention before. I tried different methods from that class and all of them gives me the same error.
Any help will be appreciated.

If my guess is correct, you are trying to update the UI thread directly. You can't call UI methods from threads other than the main thread. Try:
Runnable action = new Runnable() {
#Override
public void run() {
grub.updateGrubber();
} };
this.post(action);
instead of your `grub.updateGrubber();` line.

I'm actually tested what you suggested and is not a bad idea, but the problem in my code was that I never really created a Grubber object (I miss the = new Grubber(); part).
Probably a mistake related with the enormous amount of code writing and testing that I've done in the past few weeks, sorry about that. Anyway I'm going to use as main game loop the thread that is created to update the canvas in the surfaceview according to what i've read here.

Related

Why is Fragment.onResume() not displaying my GUI until after onResume finishes completely?

I am writing an Android application that interfaces with the Motorola EMDK, and I am running into an issue with timing/threading. I have an activity that adds a fragment to perform a very specific function using the EMDK, displays a screen that tells the user what is happening and then is cleaned up by the activity after about 15 seconds.
I am noticing a 1-2 second delay between when the EMDK action occurs, in this case the device cradle is being unlocked, and when the GUI is displayed that says "The cradle is now unlocked."
I have done some research about how Android handles drawing to the screen for fragments, and everything I can find says that onResume is called "when the fragment becomes visible." This does not match my experience, however. According to how I understand the code below should work, the screen should be drawn and then the EMDKManager.getEMDKManager() method is called, which constructs a pointer to the EMDK service and creates a new thread to perform the unlock:
#Override
public void onResume() {
super.onResume();
EMDKManager.getEMDKManager(getActivity().getApplicationContext(), this);
}
It looks more like the screen is drawn to only once onResume() completes in entirety, ie EMDKManager.getEMDKManager() finishes its call as well.
As the fragment is the EMDKListener object that is required for the second parameter for the method, I am struggling finding a way to thread this correctly. I need the GUI to be drawn first or at the same time that the cradle unlock occurs.
Are there any other methods that can be overridden or interfaced with to get the equivalent to an onViewDrawn() event for the fragment?
Thank you very much.
All the lifecycle method onCreate(), onResume() onStop() etc. are called by the main thread, which is also responsible for drawing the UI.
By preforming a long operation in those method, you block the UI thread from handling touch input as well as drawing the app
you can start your long operation on another thread by doing so:
new Thread(new Runnable() {
#Override
public void run() {
// do long operations here
}
}.start();
note that if that operation wants to update the UI components it MUST be done on the UI thread, you can do so by passing a runnable to the activity
activity.runOnUiThread(new Runnable() {
public void run() {
// do UI updating but, do not block it here
}
});
(or you can create an handler if it's a Service or you want to delay those runnables)
Although I have huge concerns about memory use/leaks, I did this in order to get the timing right:
private EMDKManager.EMDKListener getThis() {
return this;
}
private Runnable initEMDK = new Runnable() {
#Override
public void run() {
EMDKManager.getEMDKManager(getActivity().getApplicationContext(), getThis());
}
};
#Override
public void onResume() {
super.onResume();
Log.v(LOGTAG, "Starting");
new Thread(initEMDK).start();
}
I feel like there is a standard way of doing the getThis() method. If you know it, I would love to know.
Thank you.

How to correctly use a Workerthread?

I've been writing android apps for some months now, and I'm at the point where I'm building an actual needed app.
As I want that to work nice and fast, I made a Workerthread to do all kinds of tasks in the background while the UI can...build up and work and stuff.
It's based on the Android Studio Drawer app blueprint.
In Main.onCreate I got my operator=new Operator(), which extends Thread.
Now, when loading a new Fragment, it sometimes calls MainActivity.operator.someMethod() (I made operator static so I can use it from anywhere), and after some time I realized, the only tasks actually running in background are those in the operators run() method and an Asynctask my login Fragment runs. Everything else the UI waits for to complete and therefore gets executed by the UI thread.
So I thought: no problem! My operator gets a handler which is built in run(), and I change those tasks:
public void run() {
Looper.prepare(); //Android crashed and said I had to call this
OpHandler = new Handler();
LoadLoginData();
[...Load up some Arrays with hardcoded stuff and compute for later use...]
}
public void LoadLoginData() {
OpHandler.post(LoadLoginDataRunnable);
}
private Runnable LoadLoginDataRunnable = new Runnable() {
#Override
public void run() {
if(sharedPreferences==null)
sharedPreferences= PreferenceManager.getDefaultSharedPreferences(context);
sessionID=sharedPreferences.getString("sessionID", null);
if(sessionID!=null) {
postenID = sharedPreferences.getString("postenID", PID_STANDARD);
postenName = sharedPreferences.getString("postenName", PID_STANDARD);
context.QuickToast(sessionID, postenName, postenID);
}
}
};
context is my MainActivity, I gave the operator a reference so I could send Toasts for Debugging.
But now, the Runnables seem to not run or complete, any Log.e or Log.d stuff doesn't arrive in the console.
After some googeling and stackoverflowing, everyone is just always explaining what the difference is between Handlers, Asynctask, and Threads. And the multitask examples always only show something like new Thread(new Runnable{run(task1)}).start times 3 with different tasks.
And so became my big question:
How to correctly, over a longer time (~lifecycle of the MainActivity), with different tasks, use a background thread?
Edit: to clarify, I would also like a direct solution to my special problem.
Edit 2: after reading nikis comment (thank you), the simple answer seems to be "use HandlerThread instead of thread". Will try that as soon as I get home.
Trying a HandlerThread now. It seems my OpHandler, initialized in run(), gets destroyed or something after run() has finished, not sure whats up here (this is btw another mystery of the kind I hoped would get answered here). I get a NullpointerException as soon as I try to use it after run() has finished.
Make your worker thread own a queue of tasks. In the run() method, just pop a task from the queue and execute it. If the queue is empty, wait for it to fill.
class Operator extends Thread
{
private Deque<Runnable> tasks;
private boolean hasToStop=false;
void run()
{
boolean stop=false;
while(!stop)
{
sychronized(this)
{
stop=hasToStop;
}
Runnable task=null;
synchronized(tasks)
{
if(!tasks.isEmpty())
task=tasks.poll();
}
if(task!=null)
task.run();
}
}
void addTask(Runnable task)
{
synchronized(tasks)
{
tasks.add(task);
}
}
public synchronized void stop()
{
hasToStop=true;
}
}

Android UI Thread blocked in new Activity

I'm working on a small Android game that handles canvas drawing on a working thread. After the game is over this thread should start the next activity, but somehow the UI thread seems to get blocked by starting a new function.
This is my games Main-Loop:
while(true)
// Perform Ticks until the player makes a mistake
c = _surfaceHolder.lockCanvas();
if ((toDraw = rh.performTick()) == null) {
lose();
break;
}
_surfaceHolder.unlockCanvasAndPost(draw(toDraw,c));
}
The function performTick() processes the game logic and returns null when the game ends. draw()does the rendering. Both Functions work perfect - the problem is lose(), which does nothing than starting a new Activity:
protected void lose() {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
Intent intent = new Intent(_context, MainMenu.class);
_context.startActivity(intent);
}
});
}
When the Game ends, the new Activiy (MainMenu) starts normally but does not react on any touch events. There is no LogCat output and no Exception occuring. Even worse, lose()works normal when its called BEFORE the main loop starts.
I've been working on this for days now. I tried to start the Activity directly from the working Thread (without using a Handler in lose()) and searched the Internet for hours - nothing helps. It seems like the UI Thread is somehow blocked or caught in an infinite loop, and i have no idea how to fix this.
Everything is debugged on a Nexus 4 device.
Btw: MainMenu.onCreate() works normal when started another way.
Please help,
MA3o
You don't unlock the canvas when the if statement is true. Break will get you out of the while, leaving the canvas locked.
while(true)
// Perform Ticks until the player makes a mistake
c = _surfaceHolder.lockCanvas();
if ((toDraw = rh.performTick()) == null) {
lose();
break;
}
// this line won't be executed whether the if statement above is true
_surfaceHolder.unlockCanvasAndPost(draw(toDraw,c));
}
You should unlock inside the if statement also (before or after lose()).
Instead if While(true) you could have While(myVar) where myVar is a boolean that is true while game should be running and set to false when you call lose() In your case you continued to draw although you did not need to.

Implementing a while loop in android

I can't understand the implementation of a while loop in android.
Whenever I implement a while loop inside the onCreate() bundle, (code shown below)
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView=(TextView)findViewById(R.id.TextView);
while (testByte == 0)
updateAuto();
}
nothing boots up, and the program enters a "hanging" state after a while and I can't understand why. Testbyte is as follows:
byte testByte == 0;
and updateAuto() is supposed to update the code per 1 second and display inside the textView portion. I've been using setText inside updateAuto() as shown below and everything works fine, but once i implement the while loop all i see is a black screen and then an option to force close after a few seconds due to it "not responding".
TextView.setText(updateWords);
I've changed it to a button format (meaning i have to click on the button to update itself for now), but i want it to update itself instead of manually clicking it.
Am i implementing the while loop in a wrong way?
I've also tried calling the while loop in a seperate function but it still gives me the black screen of nothingness.
I've been reading something about a Handler service... what does it do? Can the Handler service update my TextView in a safer or memory efficient way?
Many thanks if anyone would give some pointers on what i should do on this.
Brace yourself. And try to follow closely, this will be invaluable as a dev.
While loops really should only be implemented in a separate Thread. A separate thread is like a second process running in your app. The reason why it force closed is because you ran the loop in the UI thread, making the UI unable to do anything except for going through that loop. You have to place that loop into the second Thread so the UI Thread can be free to run. When threading, you can't update the GUI unless you are in the UI Thread. Here is how it would be done in this case.
First, you create a Runnable, which will contain the code that loops in it's run method. In that Runnable, you will have to make a second Runnable that posts to the UI thread. For example:
TextView myTextView = (TextView) findViewById(R.id.myTextView); //grab your tv
Runnable myRunnable = new Runnable() {
#Override
public void run() {
while (testByte == 0) {
Thread.sleep(1000); // Waits for 1 second (1000 milliseconds)
String updateWords = updateAuto(); // make updateAuto() return a string
myTextView.post(new Runnable() {
#Override
public void run() {
myTextView.setText(updateWords);
});
}
}
};
Next just create your thread using the Runnable and start it.
Thread myThread = new Thread(myRunnable);
myThread.start();
You should now see your app looping with no force closes.
You can create a new Thread for a while loop.
This code will create a new thread to wait for a boolean value to change its state.
private volatile boolean isClickable = false;
new Thread() {
#Override
public void run() {
super.run();
while (!isClickable) {
// boolean is still false, thread is still running
}
// do your stuff here after the loop is finished
}
}.start();

Task not finishing and forbidding TextView to be updated

I am now working on an android app in which I need to display a text after some processing is done.
I'm using a Thread to run a process in the back while my progress dialog is being displayed to the user. The Thread works properly and I've followed it step by step and, apparently, it also ends fine; however, the method in which I call it does not seem to come to an end (at least, during a normal cycle) because the text I am setting afterward does display immediately, I have to wait and do some other action (like in order for it to display
Below is the piece of code I'm having trouble with:
private OnClickListener saldoDisp = new OnClickListener(){
public void onClick(View v){
int x = s2.getSelectedItemPosition();
branchSel = arrSucsId[x];
mainProc();
saldoAdminTex.setText(strSaldo); //The late one
}
};
public void mainProc(){
chekP = new Thread (null,doProc,"Background");
chekP.start();
mProgress =ProgressDialog.show(SivetaAsaldo.this, "","Obteniendo saldo...",true, false);
}
private Runnable doProc = new Runnable(){
public void run(){
if(getSaldoAdmin(levelSel,branchSel))
{
mProgress.dismis();
Log.i(TAG,"Task completed properly");
}else
handler.post(tosti);
}
};
So I do get the "Task completed properly" but seems like it still waits for something else, any clues guys?
Thanks for taking a bit of your time to check it out =).
saldoAdminTex.setText(strSaldo); //The late one
is going to get called immediately. It doesn't wait until after the Thread started in mainProc ends. You also cannot dismiss the Progress Dialog in your runnable. You can only do UI related things on the main UI thread.
It would help you to read the article on Painless Threading on the Android Dev site.
About your ProgressDialog, please see this answer about how to use a AsyncTask with a ProgressDialog.
Looking at your code, this:
saldoAdminTex.setText(strSaldo);
would potentially be executed before your thread finishes as the thread will be running in parallel to that line.
An alternative way would be to do this:
public void mainProc(){
mProgress =ProgressDialog.show(SivetaAsaldo.this, "","Obteniendo saldo...",true,false);
handler.post(new Runable(){
public void run(){
if(getSaldoAdmin(levelSel,branchSel))
{
mProgress.dismis();
saldoAdminTex.setText(strSaldo);
Log.i(TAG,"Task completed properly");
}else
handler.post(tosti);
}
});
}

Categories

Resources