I'm writing a simple tilting game. Make a ball roll over the screen in the direction you tilt your phone.
So I downloaded an example on how to get the sensor data and that works fine (I use a rotation matrix to avoid the Euler angle problem). But then I tried to put it into a bigger app and I have some trouble getting it to work.
My first idea was to run the tilt sensor in a separate thread but
my class: public class TiltSensor extends Thread implements SensorEventListener
is not working to well.
I get one round of values then it stops.
How would you implement this app?
I don't want to block the UI thread so I'm thinking I need a separate thread (GameHandler) to run the game and then I call runOnUithread and from there invalidate the View. I'd also separate the board representation from the View so I'd represent the screen as a matrix and then the view would use that matrix to know how the screen should look.
But I am unsure what the best way to implement the TiltSensor. Should it run in a separate thread or the same thread as the GameHandler? How do I make sure the SensorManager actually calls the onSensorChanged in the GameHandler thread?
In my humble experience, you should:
A) Register your SensorListener on your main thread normally, but make it spawn two (or as needed) WorkerThreads on its constructor.
B) Get the looper reference of both threads, to keep them alive waiting for future requests.
B) Listen to your onSensorChanged on your main thread normally, but do NOTHING OTHER (this is important) then delegate a copy of the values to a new runnable object that will process your game logic.
C) Enqueue your new runnable object on your WorkerThread looper reference accordingly.
D) Make the runnables (that are already off your main thread) do what they have to do and synchronize changes to a singleton that may be consulted by who is interested in updating your views.
Related
I would like to make use of the universal tween engine in my pure android app, and understand that I will need to put a loop somewhere which will update the tweenmanager every frame. I have used this before in game projects where i have access to the game loop provided but in the case of a pure android application, where would I create this loop and what is the best way to handle this as my app is opened/closed/paused/resumed etc?
Am I best creating a new thread in the onResume method for each activity and starting the loop there and ending the loop in the onPause method? or is it better to create a class that acts as a sort of "Activity manager" and is always available? if so how would I do this?
I found some useful documentation on this at https://code.google.com/archive/p/java-universal-tween-engine/wikis/AndroidUI.wiki and It seems the 'correct' way to achieve this is to create a new loop for each activity in onResume() and end the loop in onPause()
There is an API available starting in API level 16 called Choreographer. This is the thing that keeps the main thread pumping events at 60 frames per second. You can register a callback to be executed with the next frame, then within that callback, register to run it again at the next frame. This is the most reliable way to get called at every frame with near-perfect timing (as long as the main thread is not being blocked in a way that would case frame loss).
Your callbacks will all be called on the main thread, so be careful yourself about blocking the main thread. So keep your work super fast.
Situation: Android
class GLRenderer implements GLSurfaceView.Renderer
..
void onDrawFrame(GL10 gl) {..}
class MainGLSurfaceView extends GLSurfaceView
..
setRenderer(new GLRenderer());
class MainActivity ..
..
boolean onTouchEvent(MotionEvent event) {..}
MainActivity.onTouchEvent receives and processes events, some of which change state used by onDrawFrame(gl).
Q 1: Is there a way to "put the message queue on hold" until onDrawFrame returns?
NOTE: my onDrawFrame might take up to ~1/3 second on a slow phone. If necessary, I can probably change it so that if it doesn't have information it needs, it can start fetching it in the background, return promptly, and then draw the new frame on a later draw request (triggered by a timer).
Q 1B: Perhaps the events are only interrupting the draw, because of something I'm doing to fetch data. Can events interrupt at any moment (in the middle of onDrawFrame), or is it only when my custom onDrawFrame logic makes certain (system?) calls?
A 1B: Unfortunately, with a breakpoint I caught the event interrupting in the middle of a computation (a VM "init" of a new instance of a small class used to hold a temporary value was all that was required, to be "interruptible"; something almost any java code might do). So I will need to cope with interrupting events, can't side-step them.
Q 2: Or would it be better to examine incoming messages, and somehow decide which ones should be handled immediately, and then ?do what? with other messages, to process them after onDrawFrame returns?
Q 3: I've made an attempt at Q 2, putting messages on to an internal queue. Then I tried processing them at end of the onDrawFrame method. This worked okay until a message which tried to open a confirmation dialog. Result: RuntimeException: Can't create handler inside thread that has not called Looper.prepare(). Yeah, I didn't think I should be doing it that way. Can i somehow shove those messages back on to the main message queue?
(I didn't want to create yet another thread, so at end of onDrawFrame I tried "new Handler().postDelayed(new Runnable() .." inside of which I was going to do something with those events. Oops - that has the same problem - can't create handler on the thread that onDrawFrame is running on.)
So the basic idea is that I seek a way to not pull the rug out from under the current draw frame. I'd rather not have to make all the event-triggered logic work on one set of data, then "freeze" that data (copy it), so that draw frame can work on a frozen set.
Q&A's that I looked at before asking this:
Message queue in android
This talks about creating a looper and a handler, including a link to another article. I might adapt this to create a handler attached to the main thread's looper. So instead of having to inject back into the MessageQueue, I just need to pass my secondary queue to this handler, and start it running. But I'm on the wrong thread at the time I want to start the handler, so not sure how to proceed. Hmm, maybe make a custom event, that I somehow trigger on the main thread?
How to pause the activity?
shows how to use a flag to pause a worker thread. Since I have multiple types of events I wish to defer, instead of that approach, it is easier to hold (copies of) those events on a separate queue. Then I just need to know how to "inject" them back into the main MessageQueue. I'm trying to avoid creating another thread, to minimize system resources.
How to pause a Thread's Message Queue in Android?
Alternate approaches (not using looper) when creating one's own thread, e.g. a worker thread. Doesn't help for my situation, which is UI events coming in to existing looper.
And in case there is some completely different way to tackle this:
isn't this a situation that everyone who uses GLSurfaceView rendering would encounter eventually?
Is there any example of a robust way to deal with gl drawing and asynchronous GUI events?
The final piece to my solution to "Q 3":
public class MainActivity ...
// Call this, if not already on UI thread.
public static void processQueuedEventsOnUIThread() {
try {
Runnable runnable = new Runnable() {
#Override
public void run() {
... process the deferred UI events, which I have stored on a private queue ...
}
};
MainActivity.mMainActivity.runOnUiThread(runnable);
} catch (Exception e) {
Log.e("MainActivity", "processQueuedEventsOnUIThread", e);
}
}
The last statement in my GLRenderer.onDrawFrame() is now
MainActivity.processQueuedEventsOnUIThread();
The exceptions no longer occur, even if the processed events cause a dialog window (with its own handler) to open. activity.runOnUiThread(runnable) is the essential step.
My app acquires data from accelerometer and the UI is not so responsive as it should be.
I suppose this is because SensorEventListener is called in the UI thread.
So I tried to create a new thread, with an inner class which implements the event listener and in the thread I registered the accelerometer.
Nevertheless the code was executed in the UI thread. So: how would you make onSensorChanged not slowing UI?
Don't do a lot inside the callback. When you are executing your code, you cannot get another update.
For example, when you have a sleep(500) in the onSensorChanged, you will not receive a new update for the comming 500 mili sec.
So start a new thread inside the onSensorChanged and do your stuff in there.
I have create a screen with two kind of views : normal view (buttons to receive up/down action ) and surfaceview. The SurfaceView implements SurfaceHolder.Callback and run on another thread and have a method name Tick().
When those buttons receive action, they will call method Tick(), and I want this method will run same thread with SurfaceView (for synchronize purpose), but don't know how to.
Please give me some idea for my issues.
Thanks :)
If you really want to run Tick() method in separate thread which also draws on the surface you can use HandlerThread for it. So you will be able to create Handler for it and post runnables which will be executed in this thread. But this also will put some restrictions on your drawing routine - you need to prevent it from sleeping or waiting because thread need to process message queue.
But actually I suppose any other reasonable way of synchronization will be easier than running this method on the same thread.
I am using Eclipse to develop an Android application that plots Bluetooth data.
I am using open source code, which has an existing solution that I want to extend and not replace to solve my development problem as stated above.
The open source code has a very nice and solid background thread that among other things continually logs BluetoothData to logcat even when I switch to a new activity.
Currently I have a solution which I am concerned about: I simply leverage a background thread method that writes to logcat to call a static plotData() method in my Plotting Activity. The result seems good. I get a nice plot. It clips along in real-time. Looks like an oscilloscope.
But I have received negative feedback about using the existing background thread coupled with a static method to plot the BluetoothDate. It has been suggested that I use a new thread, or add a handler, or use Async Task, or AIDL to solve my problem.
I have looked at all these solutions without success. Nothing seems to work like my static plotData() method. That is to say the existing background thread calls my static plotData() method which results in a real-time plot that looks great.
But I am still concerned about the negative feedback. I simply want to extend my existing background thread solution which I have done by having it call a static method to plot the data.
What are the problems I might face with this approach? Thread safety? Deadlock? I don't know.
Why do people keep suggesting that I create a new thread, handler, Async Task, or Service to solve my problem when extending my existing thread to call a static method seems to work just fine?
Any suggestions? What are the problems with extending the existing thread to use a static method to plot the data in real-time?
Anyone who says that you should use AIDL for this is a loon who should not be listened to. :) Also someone saying you need a Service if you don't want to have your background thread running when the user is not viewing your activity.
I'm not sure what you mean by "writes to logcat to call a static plotData()." You should write to logcat only for testing. Writing to logcat doesn't cause a call to any Java method.
If you are calling a static plotData() method on your Activity, you need to be extremely careful with this: first because it is difficult to figure out what activity instance should be called from there (it may go away at any time from the user finishing it, or be recreated as a new instance when the configuration changes, etc); and second because you can't touch your app's UI/view hierarchy from a background thread without risking that you corrupt its state (since the view hierarchy is single threaded).
The general model one does for this kind of thing is to have a background thread doing some work, generating the next data to display. Once it is done with the work you send a message to the main thread to have it display the new data. AsyncTask can be a simple way to do this, it takes care of the underlying message sending and threading. You can also implement this yourself, at some point having a Handler that you post a Runnable on or send a Message to that once executed on the UI thread will update your view state.
(Of course if you are using a SurfaceView, the whole point of that is to allow drawing to it outside of the main UI loop, so your background thread could just draw directly on to it as needed. Basically that is like writing a game.)