I'm developing a relatively small 2D game for Android right now. To process the collision detections as efficient as possible, I've created multiple threads working on the calculations:
Thread #1: Main handling of the frames, limiting them to X per second, handling the Bitmaps (rotate, draw...)
Thread #2: Calculate some collisions
Thread #3: Calculate other collisions
What I need is some sort of synchronization, but I am unsure of what's the best way to achieve this. I thought of something like this:
Thread #1:
public class Thread1 imlements Runnable {
public static ArrayList<Boolean> ResponseList = new ArrayList<Boolean>();
static {
ResponseList.add(0, false); // index 0 -> thread 1
ResponseList.add(1, false); // index 1 -> thread 2
}
public void run() {
boolean notFinished;
while(!isInterrupted() && isRunning) {
notFinished = true;
// do thread-business, canvas stuff, etc, draw
while(notFinished) {
notFinished = false;
for(boolean cur: ResponseList) {
if(!cur) notFinished = true;
}
// maybe sleep 10ms or something
}
}
}
}
And in the other calculation threads something like:
public class CalcThread implements Runnable {
private static final INDEX = 0;
public void run() {
while(isRunning) {
ResponseList.set(INDEX, false);
executeCalculations();
ResponseList.set(INDEX, true);
}
}
}
Or would it be faster (as this is what I'm concerned about) to use a Looper/Handler combination? Just read about this, but I'm not sure yet how to implement this. Would look deeper into this is this would be the more efficient method.
I don't know if it is going to be faster, but it will be more reliable for sure. For example, you are using ArrayList from multiple threads without serialization and ArrayList is not thread-safe
Handler is just one of the available mechanisms, I would recommend you to study java.util.concurrent - there is no point in reinventing the wheel, many synchronization primitives are already available. Perhaps Future would work for you
A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation.
Related
Hey here's an interesting question. I am using in my Android project, lots of sql operations with sqlite. For this matter, I am using thread pool in order of reusing the existing resources. The thread pool look's like this:
final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor(NUMBER_OF_CORES*2,NUMBER_OF_CORES*2,1L, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(12,true),new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND),new RejectedThread(context));
public class PriorityThreadFactory implements ThreadFactory {
private final int mThreadPriority;
public PriorityThreadFactory(int threadPriority) {
mThreadPriority = threadPriority;
}
#Override
public Thread newThread(final Runnable runnable) {
Runnable wrapperRunnable = new Runnable() {
#Override
public void run() {
try {
android.os.Process.setThreadPriority(mThreadPriority);
} catch (Throwable t) {
}
runnable.run();
}
};
return new Thread(wrapperRunnable);
}
}
public class RejectedThread implements RejectedExecutionHandler {
MyLogger myLogger;
public RejectedThread(Context context) {
this.myLogger=new MyLogger(RejectedThread.class.getSimpleName(), context);
}
#Override
public void rejectedExecution(Runnable worker, ThreadPoolExecutor executor) {
this.myLogger.info("Execution rejected for: "+worker.toString());
}
}
And also I am creating a new Runnable for every CRUD (Create-Read-Update-Delete) operation that I make in the database (being executed by the thread pool above). Here is the questions, beside the threadpool for sql operations, I would need one more thread pool for executing logger operations, to log system behavior for the rest of my functions that I make. Is there a way to prevent any crush/(insufficient resources) because I am using two or more thread pool executors (allocated separated, using in different purposes and never executing a thread pool executor on another thread pool executor) ?
I think that in general your idea is very good, but your implementation is a bit inefficient.
Try to answer these questions to yourself:
Why do you need two thread pools?
Do you REALLY need two thread pools?
Why do you set CORE size to NUMBER_OF_CORES*2?
Why do you set MAX size to NUMBER_OF_CORES*2?
Do you REALLY need to overwrite threads priorities?
In my experience, none of the above complications are really necessary.
For example, in all my apps I use a single instance of BackgroundThreadPoster class in order to offload work to background threads. The class is very simple:
/**
* A single instance of this class should be used whenever we need to post anything to a (random) background thread.
*/
public class BackgroundThreadPoster {
ExecutorService mExecutorService = Executors.newCachedThreadPool();
public void post(Runnable runnable) {
mExecutorService.execute(runnable);
}
}
Default pre-configured implementation returned by Executors.newCachedThreadPool() works like magic and I've never encountered any need to customize its parameters.
A full tutorial application that uses this approach can be found here: https://github.com/techyourchance/android_mvc_tutorial
Maybe this can work for you too?
I want to optimize my code. I can see in my sample camera app, I am creating thread for takePicture. Something like:
WAY 1
private void takePicture() {
mTakePictureThread = new Thread() {
run() {
camera.takePicture(cb, cb, ..);
}
}
mTakePictureThread.start();
}
Now I can do same thing with Handler too as below:
WAY 2
//consider mTakePictureThread is started in onCreate()
//and mTakePictureHandler is global variable
private void takePicture() {
mTakePictureHandler.sendMessage(1);
}
private class TakePictureThread extends Thread {
#override
public void run() {
Looper.prepare();
mTakePictureHandler = new Handler() {
public void handlerMessage(Message msg) {
int what = msg.what;
switch(what) {
case 1:
camera.takePicture(...);
break;
default:
break;
}
}
}
Looper.loop();
}
}
Considering takePicture is called many times. So in case 1, new thread will be created as many time as takePicture is called means every time new thread will be created.
But in second case, I can always hold one handler and call takePicture just by passing a message through handler.
So my query is, which one is better considering I am calling takePicture many time. In terms of performance and memory.
I have seen people using WAY 1 always(couldn't get satisfied reply why). So can anyone explain Pros and Cons of both approach and when should I follow which approach?
The second way queries your messages and will only use one thread to take the pictures. So if your camera.takePicture(..) is not a blocking call this will result in unneccessary waiting times for your threads.
The first way can handle different query counts in the same time if your camera can broadcast the actual image.
You can find a good explanation of loopers in the answer on this question looper purpose. A looper is better if you want one thread to handle messages in a sequential manner.
In a sort-of-working application I see this monstrous code:
class SomeUglyClass extends Thread {
ArrayList<SomeData> someDataStructure = new ArrayList<SomeData>();
Handler mHandler = new Handler() {
// a lot
// writing to someDataStructure
}
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
} // end of run(), total 500 lines of code
} // end of SomeUglyClass, total 4K lines of code
Maybe you already see the problems with this code. If not, here they are:
mHandler is attached to the UI thread (because it is created by the thread that loads the class, which is the main thread)
there's no looper (which is fact is the bug)
the thread wastes CPU time and drains the battery
someDataStructure is not thread-safe, but synchronizing elementary access operations will not help; synchronizing large blocks of code in a endless loop will likely block the guarded resource and make it unavailable for other threads; finally, it is not only someDataStructure, the whole class is based on the assumption that only one thread can run its code.
I cannot just add the looper, because the endless loop in run() has to be run, while Looper.loop(); also is an infinite loop. One thread cannot run two infinite loops.
Despite this epic architectural fail, the code is really doing something, it cannot be re-written at once, it is 4K lines of code, and often I can only guess what the code really does.
I need to refactor it. It should be a sequence of small steps preserving the functionality.
How do I refactor this terrific code?
You should try separation of concerns: try first to divide the whole class into many smallest one, each one responsible for doing/dealing with exactly one thing.
You may have something for data Access (read/write data), service (isolated business logic), and the UI. You may use event bus to decouple between objects (consider otto) and may be dependency injection (consider Dagger).
This process of separation will help you understand what each piece of code is doing and also the dependencies between the different parts, thus making writing unit/integration tests much easier.
Add lots of tests, use version control and then work as slowly as you need to.
The 1st step has been to change:
public void run() {
int some_count, ...;
while(true) {
// a lot
// r/w access to someDataStructure
try {
Thread.sleep(1, 0);
} catch (Exception e) {
break;
}
}
}
to:
#Override
public void run() {
Looper.prepare();
mHandler = new MyHandler();
mHandler.post(run_step);
Looper.loop();
}
Runnable run_step = new Runnable() {
int some_count, ...;
#Override
public void run()
{
//while(true) {
// a lot
// r/w access to someDataStructure
mIntoThreadHandler.postDelayed(this, 1);
//}
}
}
This preserves the functionality but still wastes CPU time. The urgent bug has been fixed, and the issue has been closed; I could not sell "must refactor to kill monstrous code" to my management, but I could sell "this can work faster if I refactor," so a new separate issue has been opened. UGH!
PS no chance to sell "lots of tests".
I am trying to calibrate an accelerometer, but I can't obtain the 6 sample values at 6 different acceleration readings required for the calibration. PreliminaryW is a double[6][3] array made to fill those sample values. It is 6 by 3 because each acceleration reading has an x, y, and a z component.
I am planning to sample them by pressing a button at the 6 different acceleration readings. This button makes "calibrate" true.
I ofcourse, first make "calibrating" true to start this thread.
For some unfathomable reason, preliminaryW[i] = currentAcc seems to be filling up from 0 to i with the same value instead of just i. I made sure that the currentAcc is different every time I press the "calibrate" button.
What is wrong with my code?
public synchronized void run() {
Log.d(TAG, "+ in Calibrator thread +");
int i = -1;
while (calibrating) {
if (calibrate) {
i = i + 1;
calibrate = false;
preliminaryW[i] = currentAcc;
if (i == 5) {
calibrating = false;
}
}
}
}
I'm not very familiar with the inner-workings of the accelerometer, and it's hard to decide why it's not working without seeing more of the code. For example, can you be sure that there's only one instance of the Thread, or are you creating multiple instances?
Why does this need to be in a Thread?
Looping like that is not good practice either, you should use wait/notify if you absolutely need a Thread. (more info at http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
I've drafted a class that does approximately what you want, but doesn't use threading. You could create a Calibrator and then call performCalibration() with each new value:
class Calibrator{
int count = 0;
double[][] preliminaryW = new double[6][3];
public void performCalibration(double[] currentAcc){
preliminaryW[count] = currentAcc;
count++;
}
}
without the Thread and "busy loop", you might be able to omit those flags for 'calibrate' and 'calibrating' which would certainly help debugging as well.
Good Luck!
I use functions for canvas like drawCircle and drawPoint in android.
This works fine.
But the problem now is to draw these different items with a delay, so it looks like an animation.
What kind of mechanism should I use? Have tried with async but I dont like that way of doing it.
Should I use some kind of timer that just draw with an interval or is there other clever ways to do this?
I use this strategy, first I declare a Handler and a Runnable that way:
private final Observable mObservable = new Observable();
private final static int TIME_STEP_MS = 5;
private final Handler mHandler = new Handler();
private final Runnable mTimeManager = new Runnable()
{
public void run()
{
mObservable.notifyObservers(TIME_STEP_MS);
mHandler.postDelayed(mTimeManager, TIME_STEP_MS);
}
};
Then when I want to start my time manager I just call the mTimeManager.run() and it will start to notify my Observer s (previously added) periodically.
If you need for some reason stop the timer or something you just do that:
mHandler.removeCallbacks(mTimeManager);
[ EDIT - More complete code ]
Ok than let's make it clearer, first I made a custom Observable object like that [that's optional]:
private final Observable mObservable = new Observable()
{
public void notifyObservers()
{
setChanged();
super.notifyObservers();
};
#Override
public void notifyObservers(Object data)
{
setChanged();
super.notifyObservers(data);
};
};
the reason for that is just because I can't call setChanged() outside Observable class - it's protected, if it's not changed it doesn't notify any observer.
The other declarations keep the same as shown before, now I need to start this TimeManager somewhere, my app is a LiveWallpaper and I make all rendering stuff into a class that extends a Thread but you don't need that necessarily, I made a method called resumeDrawing(), this one is called right after super.start(); at my #Override of public synchronized void start() from Thread class, the method looks like that:
public void resumeDrawing()
{
if (!mTimeManagerRunning) // just a boolean field in my class
{
System.err.println("Resuming renderer."); // just for debug
mTimeManager.run();
mTimeManagerRunning = true;
}
else
{
System.err.println("Renderer already running."); // just for debug
}
}
and it's dual:
public void pauseDrawing()
{
if (mTimeManagerRunning)
{
System.err.println("Pausing renderer.");
mHandler.removeCallbacks(mTimeManager);
mTimeManagerRunning = false;
}
else
{
System.err.println("Renderer already paused.");
}
}
Ok, now we can start and stop the time manager, but who's listening? Nobody! so let's add'em: On the constructor of my Renderer I add some Observer s to my mObservable object, one of those is the Renderer itself, so my renderer extends Thread and implements Observer:
#Override // from Observer interface
public void update(Observable arg0, Object arg1)
{
mElapsedMsRedraw += (Integer) arg1;
if (mElapsedMsRedraw >= mDrawingMsPerFrame)
{
mElapsedMsRedraw = 0;
drawEm(); // refresh the canvas and stuff
}
}
to add observers you simply do mObservable.addObserver(THE_OBJECT - Implements Observer)
you can see that I don't re-render my stuff each time I'm notified, that's because I use this TimeManager for other thinks than just refresh the Canvas like updating the position of the objects I want to draw just internally.
So, what you need to slow down the drawing is to change the way your objects change internally while the time passes, I mean your circles and points etc, or you can chance your time step, I recommend the first one.
Was it clearer? I hope it helps.
I would use a timer, or create Animations. You can create Animations that will do all sorts of things including changing transparency over time.
Here's the Android Documentation for Animation Resources
I believe there may be sophisticated ways of doing this, but for my needs I used a simple method that has a lot of advantages:
I first create records of coordinates (and any other data needed) for every point of the drawing -- instead of drawing the points on the spot -- and then reproduce them using a timer (Android handler, preferably). This also offers a lot of possibilities while actual drawing: pause, go faster/slower, go backwards, ...
I don't know if this method can be used for complicated drawings, but it is fine for drawing shapes, curves, surfaces, etc.