what is a good way to stop a thread in android - java

I am trying to passthrough the input obtained from the microphone to the speaker (the goal is to be able to perform audio processing in real time in the future). This is the code:
public class MainActivity extends Activity {
AudioManager am = null;
AudioRecord record =null;
AudioTrack track =null;
final int SAMPLE_FREQUENCY = 44100;
final int SIZE_OF_RECORD_ARRAY = 1024; // 1024 ORIGINAL
final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
int i= 0;
boolean isPlaying = true;
class MyThread extends Thread{
#Override
public void run(){
recordAndPlay();
}
}
MyThread newThread;
private void init() {
int min = AudioRecord.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, min);
int maxJitter = AudioTrack.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, maxJitter, AudioTrack.MODE_STREAM);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
init();
newThread = new MyThread();
newThread.start();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void recordAndPlay() {
short[] lin = new short[SIZE_OF_RECORD_ARRAY];
int num = 0;
am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
record.startRecording();
track.play();
while (true) {
num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
for(i=0;i<lin.length;i++)
lin[i] *= WAV_SAMPLE_MULTIPLICATION_FACTOR;
track.write(lin, 0, num);
}
}
public void passStop(View view){
Button playBtn = (Button) findViewById(R.id.playBtn);
// /*
if(!isPlaying){
record.startRecording();
track.play();
isPlaying = true;
playBtn.setText("Pause");
}
else{
record.stop();
track.pause();
isPlaying=false;
playBtn.setText("Pass through");
}
// */
}
/*
#SuppressWarnings("deprecation")
#Override
public void onDestroy(){
newThread.stop();
}
*/
#Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
}
Brief overview:
The while(true) {} infinite loop in recordAndPlay() function continuously reads raw audio samples from the microphone and outputs the raw samples to the speaker. recordAndPlay() is called from a Thread started in the onCreate() function. So it starts sending the input on the microphone to the speaker as soon as the program starts (well actually after a few seconds lag but I think this latency in unavoidable). I also have a button that can pause and resume this pass through. Now if the Thread is not stopped, the pass through continues even when I exit the application or the application looses focus (so even when the phone is on the desktop it keeps doing the passthrough).
#SuppressWarnings("deprecation")
#Override
public void onDestroy(){
newThread.stop();
}
This code causes the app to crash on exit (Why?) so I used
#Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
that I found somewhere in stackoverflow (I forgot where). It seems to do what I want for now, but I want know if this is the proper way to stop the Thread or not. It does what I need, that is, it stops the passthrough when I exit the application, but I am not sure what exactly the killProcess() function does to my application overall, and if it is the best way to stop a Thread that I started myself.
Also, I can get the same effect if I exit my application (or loose focus to it) while the passthrough is being paused. But I assume this means the Thread is still running which means the infinite loop is also continuously running as well. Is it a good idea to do this, that is, just leave the Thread running, as long as my overall program is behaving as I want it to? What if I have lots of Threads or other background processes running? Can this practice cause memory problems in the future if the app grows too big?

Threads should periodically check for some shouldTerminate flag in their loop, then just set this flag from UI thread and (optionally) wait until thread terminate gracefully. Don't forget volatile or proper field synchronization.

Please remember to call super.onDestroy after releasing your memory or finishing the thread. Otherwise it will throw Exception:
#Override
protected void onDestroy() {
// You code here to finish the thread
super.onDestroy(); // Please call THIS too
}
Hope this helps.

Change your Thread class to something like this:
class MyThread extends Thread {
private volatile boolean finished = false;
#Override
public void run() {
while (!finished) {
// do stuff on thread
}
}
public void stopThread() {
finished = true;
}
}
In your onDestroy method call stopThread().
#Override
protected void onDestroy() {
newThread.stopThread();
super.onDestroy();
}
If you wish, you can also wait for thread to stop, by using this method:
private void joinThread(Thread thread) {
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// to be handled as you wish
}
}
}
Put this method in your activity and call it after newThread.stopThread().

There is already a provided flag for interuption.
Correct your while loop to the following.
And just call interupt(); in onDestroy or wherever.
private class thrd extends Thread {
#Override
public void run() {
super.run();
while (!isInterrupted()) {
//TODO
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
thrd.interupt();
}

Related

Temporary threads leaking things they reference (target java.lang.thread)

I have an android app with a non-UI thread that needs to be responsive, but which needs to occasionally perform a long running task. To do this, I make it spawn a thread to run the task. This thread takes a reference to an object. This object appears to leak. I run out of memory amazingly fast.
I anticipate lots of people telling me to use AsyncTask. I find AsyncTask irritating and harder to use than a plain ol' thread, and I am not in the UI thread here. I will listen to advice, but I'd appreciate it if the advice explained why!
I have written a very simple program to demonstrate the problem, which runs a thread that, every second, updates a textview with the value of an integer. Having done so, it spawns a thread which increments the integer by one. The thread also, for no good reason, takes a reference to an object called "BigFatBlob". It leaks like a sieve. I don't understand why. After the program code I have attached a screen shot of part of the MAT analysis of the heap showing the leak and the incoming references.
The function to look at below is "increment()". If anyone can tell me why my program is leaking I'd be very grateful - I'm a bit lost here.
public class MainActivity extends Activity {
TextView text_;
int value_;
boolean ready_;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text_ = (TextView)findViewById(R.id.textView);
value_ = 0;
ready_ = false;
watcher();
increment(new BigFatBlob());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
/** Updates the text view object to show the current value */
public void updateText() {
Runnable r = new Runnable() {
#Override
public void run() {
text_.setText("" + value_);
}
};
runOnUiThread(r);
}
/** runs forever, checking for new values every second */
private void watcher() {
Runnable r = new Runnable() {
#Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
if (pollReady()) {
updateText();
increment(new BigFatBlob());
}
}
}
};
Thread t = new Thread(r);
t.start();
}
/** runs once - increments the value by 1 and flags "ready" */
public void increment(final BigFatBlob junk) {
Runnable r = new Runnable() {
private BigFatBlob j;
#Override
public void run() {
setJ(junk);
++value_;
setReady(true);
}
public BigFatBlob getJ() {
return j;
}
public void setJ(BigFatBlob j) {
this.j = j;
}
};
Thread t = new Thread(r);
t.start();
}
/** ready is synchronized */
private synchronized void setReady(boolean state) {
ready_ = state;
}
/** get the ready value and, if it was true, make it false again */
private synchronized boolean pollReady() {
if (ready_) {
ready_ = false;
return true;
}
return false;
}
}
public class BigFatBlob {
byte[] blob_;
public BigFatBlob() {
blob_ = new byte[1000];
}
}
I'm sorry I asked. If I can answer it myself in less than 24 hours from asking I wasn't trying hard enough :(
While I am debugging my test app (in Eclipse) it leaks and leaks and leaks and eventually crashes.
If I disconnect the debugger before the crash all the leaked memory suddenly becomes available again and it stops leaking.
I am not 100% sure that a memory analyzer that works over a connection that itself causes my data to leak all over my heap is all that useful.
In fact, it may be the opposite of useful. If this question saves someone else a couple of hours of banging their head on the same artificial wall maybe it was worth asking anyway? Anyone want to shed any more light on this before I close it?

android activity create multiple instance of my thread

i need to check a variable for change, if the change happens i will update a textview.
so i created a new thread with a while loop for this purpose. i check the variable every 1 second, via Thread.sleep()
this thread created and started in onCreate(). so it's one time.
the problem is every time i flip my phone (from vertical to horizontal or ...) a new thread will be created.
here is my code:
public class HomeActivity extends Activity
{
private final static int LOAD_SUCCESSFULL = 1;
private final long LOCATION_THREAD_SLEEP = 1000;
private boolean flag = false;
static TextView lat;
static TextView lon;
static Location currentLocation = null;
Thread locationThread;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.new_home2);
this.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.new_home_titlebar);
lat = (TextView)findViewById(R.id.t2rt3);
lon = (TextView)findViewById(R.id.t2rt4);
/* FindLocation class is a helper class that find location via simcard or gps in separate thread,
same problem happen with this thread also, it create multiple thread, for ease of work i
commented this part.
*/
//FindLocation fn = new FindLocation(this);
locationThread = new Thread(null, loadLocation, "loadLocationHomePage");
locationUpdater();
}
private static Handler locationUpdateHandler = new Handler()
{
public void handleMessage(Message msg)
{
switch(msg.what)
{
case LOAD_SUCCESSFULL:
lat.setText(Double.toString(currentLocation.getLatitude()));
lon.setText(Double.toString(currentLocation.getLongitude()));
//stopThread();
break;
}
}
};
private Runnable loadLocation = new Runnable()
{
public void run()
{
//boolean flag = false;
while(!flag)
{
if(Data.currLocation != null)
{
currentLocation = new Location(Data.currLocation);
Message msg = locationUpdateHandler.obtainMessage(LOAD_SUCCESSFULL);
locationUpdateHandler.sendMessage(msg);
//return;
flag = true;
//return;
}
else
{
try
{
Thread.sleep(LOCATION_THREAD_SLEEP);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
};
public void locationUpdater()
{
//Thread locationThread = new Thread(null, loadLocation, "loadLocationHomePage");
locationThread.start();
}
so how i can solve this?
Actually the problem is that EveryTime you flip the phone a new instance of Activity is created and because of this you on every rotation you get a call on onCreate() where you are blindly creating a new Thread and Starting the new Thread.
This is the default behavior of every Activity but we can change this re-creation of Activity by stating an attribute in AndroidManifest file for the Activity
<activity
android:name="yourPackage.ActivityName"
android:configChanges="keyboardHidden|orientation|screenSize"
</activity>
This will prevent from creation of Activity on orientation change.
You will also get these orientation event if you override
#Override
public void onConfigurationChanged(Configuration newConfig) {}
Hope this will solve this problem without implementing such a complex logic which may broke in some other uses case.
I think you aren't perhaps going about this in the most efficient way possible.
But if your question is simply, how do i prevent multiple worker threads from being spawned, you should look into a UIless fragment.
http://www.vogella.com/articles/AndroidFragments/article.html#headlessfragments1
i don't know why android doing this. if i putted my code in onResume(), then this behavior make sence but in my case, i don't know.
anyway i found a dirty solution. the idea is finding list of all thread and search them for mine, if it existed prevent to create another.
public boolean checkThreadExist()
{
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for(int i = 0; i < threadArray.length ; i++)
{
if(threadArray[i].getName().equalsIgnoreCase("loadLocationHomePage"))
return true;
}
return false;
}
updated onCreate() :
if(checkThreadExist())
{
}
else
{
locationThread = new Thread(null, loadLocation, "loadLocationHomePage");
locationUpdater();
}

Android SDK: Handler causing crash on some devices

I have a handler used to display images in a specified interval loop, on reaching the last image, it goes back to the first image which is the correct. However, i'm having problems with it as it's causing some devices to crash and makes the CPU usage go up significantly, i'm just wondering what is wrong with the code?
I instantiate it like the following at the top of the fragment:
final public static Handler handler = new Handler();
boolean isRunning = false;
Then in the onPostExecute part of an AsyncTask, I have this code:
#Override
protected void onPostExecute(Void v) {
if(!isRunning) {
Runnable runnable = new Runnable() {
#Override
public void run() {
anImageView.setVisibility(View.VISIBLE);
isRunning = true;
counter++;
//imageDownloader.download(data.get(i).getImageURL(), anmageView);
if(TabsViewPagerFragmentActivity.theImages !=null && TabsViewPagerFragmentActivity.theImages.size() > 0){
Bitmap anImage = TabsViewPagerFragmentActivity.theImages.get(i);
anImageView.setImageBitmap(anImage);
}
i++;
if(i>TabsViewPagerFragmentActivity.theImages.size()-1)
{
i=0;
}
handler.postDelayed(this, 1500);
}
};
handler.postDelayed(runnable, 0);
}
}
The above AsyncTask is called within the onCreate() method.
Secondly, I have a refresh button which re-downloads these images in order to get the latest ones as they change periodically. Therefore I have an onClick() event attached to the refresh button. This also works fine but here is the code which is called:
#Override
protected void onPostExecute(Void v) {
for(int i=0;i<data.size()-1;i++) {
Bitmap anImage = getBitmapFromURL(data.get(i).getImageURL());
theImagesRefreshed.add(anImage);
}
if(!isRunning) {
Runnable runnable = new Runnable() {
#Override
public void run() {
anImageView.setVisibility(View.VISIBLE);
isRunning = true;
counter++;
//imageDownloader.download(data.get(i).getImageURL(), anImageView);
if(theImagesRefreshed !=null && theImagesRefreshed.size() > 0){
Bitmap anImage = theImagesRefreshed.get(i);
anImageView.setImageBitmap(anImage);
}
i++;
if(i>theImagesRefreshed.size()-1)
{
i=0;
}
handler.postDelayed(this, 1500);
}
};
handler.postDelayed(runnable, 0);
}
}
I think that the handler is not setup right and is causing the performance issues. Can anyone see anything wrong with this code?
Thanks in advance!
You need to call Looper.prepare() while using handlers in threads .So write Looper.prepare() after you are creating instance of Runnable

How to intent to another page on android/pop up a message from idle time?

Halo, the first i want to know the idle time at my android application. after that, i will do something if it is a idle time mode.
I follow this link.
Application idle time
my program work properly, but suddenly the problem show up. I can't move to the other page (for example to the login page) or pop up a message using alertdialog because its in a thread. Do you have any solutions?
public class ControlActivity extends Activity {
private static final String TAG=ControlActivity.class.getName();
/**
* Gets reference to global Application
* #return must always be type of ControlApplication! See AndroidManifest.xml
*/
public ControlApplication getApp()
{
return (ControlApplication )this.getApplication();
}
#Override
public void onUserInteraction()
{
super.onUserInteraction();
getApp().touch();
Log.d(TAG, "User interaction to "+this.toString());
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}}
here is my ControlApplication.java
public class ControlApplication extends Application {
private static final String TAG=ControlApplication.class.getName();
private Waiter waiter;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "Starting application"+this.toString());
//setContentView(R.layout.activity_main);
waiter=new Waiter(5*60*1000); //5 mins
waiter.start();
Toast.makeText(ControlApplication.this, "start", Toast.LENGTH_LONG).show();
}
public void touch()
{
waiter.touch();
Toast.makeText(ControlApplication.this, "touch", Toast.LENGTH_LONG).show();
} }
here is the Waiter.java
public class Waiter extends Thread implements Runnable{
private static final String TAG=Waiter.class.getName();
private long lastUsed;
private long period;
private boolean stop;
Context activity;
public Waiter(long period)
{
this.period=period;
stop=false;
}
#SuppressLint("ParserError")
public void run()
{
long idle=0;
this.touch();
do
{
idle=System.currentTimeMillis()-lastUsed;
Log.d(TAG, "Application is idle for "+idle +" ms");
try
{
Thread.sleep(5000); //check every 5 seconds
}
catch (InterruptedException e)
{
Log.d(TAG, "Waiter interrupted!");
}
if(idle > period)
{
idle=0;
//do something here - e.g. call popup or so
//Toast.makeText(activity, "Hello", Toast.LENGTH_LONG).show();
stopCounter();
}
}
while(!stop);
Log.d(TAG, "Finishing Waiter thread");
}
public synchronized void touch()
{
lastUsed=System.currentTimeMillis();
}
public synchronized void forceInterrupt()
{
this.interrupt();
}
//soft stopping of thread
public synchronized void stopCounter()
{
stop=true;
}
public synchronized void setPeriod(long period)
{
this.period=period;
}}
I tried to create a new class and call a method to intent. Its also fail. tried to pop up a message from that method its also fail.
do you guys have any other solutions for idle time? thanks.
Regards,
Alfred Angkasa
In you active activity, instead of this thread, do:
public class Graph extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
while(idle = 0) {
idle = System.currentTimeMillis()-lastUsed;
if(idle != period) {
Intent goNextActivity = new Intent(com.package.theactivity);
else {
idle == 0;
}
}
}
}
I just found by myself the answer by search on google and try for 5 hours.. :D
I hope my answer will help you too.
First, I mix the ControlApplication and Waiter with ControlActivity. Thats mean I don't need both files. My ControlActivity will extends the activity (its use for me to intent to the other page if in idle mode), and i will implements runnable(its use for me to run the thread).
after that i have a method called onUserInteraction(), this method help me to get the user interaction, whenever the user touch or click something.
in the onCreate, i initiate all the variable including lastUsed, period, and stop.
why should I initiate that? because you need to know how many seconds to know that your apps is on idle mode or not. that was period use. Stop variable is use for me to iterate and searching every 5 seconds(you can also make it every second to check idle or not) my apps is idle or not. I initiate lastUsed by calling method touch. I copied touch method from ControlApplication into my ControlActivity. By calling touch method, I can know when is my lastused. After that I start my thread.
in my run method, i set idle = 0. and do some looping to check. i check every 5 seconds to know my apps is on idle mode or not.
idle = System.System.currentTimeMillis()-lastUsed -> i used this to know if the idle is already suite with the period or not using if method.
if the idle is greater than period, my apps must be in idle mode. after that i stop the iteration and using handler to manage it.
i set handler.sendEmptyMessage(0), and create Handler. At handler i move to the other page.
this is my full code.
public class MainActivity extends Activity implements Runnable {
private static final String TAG= MainActivity.class.getName();
private long lastUsed;
private int period;
private boolean stop;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
period = 10000;
stop=false;
touch();
Thread currentThread = new Thread(this);
currentThread.start();
Toast.makeText(getApplicationContext(), "Start", Toast.LENGTH_SHORT).show();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
public void onUserInteraction()
{
super.onUserInteraction();
touch();
Log.d(TAG, "User interaction to "+this.toString());
}
public synchronized void touch()
{
lastUsed=System.currentTimeMillis();
Toast.makeText(getApplicationContext(), "touch", Toast.LENGTH_SHORT).show();
}
public void moveIntent() {
Intent intent = new Intent(this, AfterIdle.class);
startActivity(intent);
}
public void validate(View view) {
switch (view.getId()) {
case R.id.button1 :
Intent intent = new Intent(this, AfterIdle.class);
startActivity(intent);
break;
}
}
#Override
public void run() {
// TODO Auto-generated method stub
long idle;
while (!stop) {
idle=System.currentTimeMillis()-lastUsed;
try
{
Thread.sleep(5000); //check every 5 seconds
}
catch (InterruptedException e)
{
Log.d(TAG, "Waiter interrupted!");
}
if (idle > period) {
idle = 0;
stop = true;
}
}
handler.sendEmptyMessage(0);
}
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
moveIntent();
}
};}
I hope this code will help another people if they have the same problem that i faced last time. I wish someone would correct the answer for me if my answer is wrong.
thanks.
Regards,
Alfred Angkasa

Why does my app force close when I setText in an update method?

I have an android app I am just experimenting things on and I cannot seem to figure out why my app force closes when I update a TextView via a while loop. When I comment out the updateText method it runs fine.
public class GameThread extends Thread {
Thread t;
private int i;
private boolean running;
private long sleepTime;
GameView gv;
public GameThread() {
t = new Thread(this);
t.start();
i = 0;
sleepTime = 1000;
}
public void initView(GameView v) {
this.gv = v;
}
public void setRunning(boolean b) {
this.running = b;
}
public boolean getRunning() {
return running;
}
public void run() {
while(running) {
i++;
update();
try {
t.sleep(sleepTime);
} catch(InterruptedException e) {
}
}
}
public void update() {
gv.setText(i); // when this is uncommented, it causes force close
Log.v("Semajhan", "i = " + i);
}
public class GameView extends LinearLayout {
public TextView tv;
public GameView(Context c) {
super(c);
this.setBackgroundColor(Color.WHITE);
tv = new TextView(c);
tv.setTextColor(Color.BLACK);
tv.setTextSize(20);
this.addView(tv);
}
public void setText(int i) {
tv.setText("i count: " + i);
}
public class Exp extends Activity {
GameThread t;
GameView v;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
v = new GameView(this);
setContentView(v);
t = new GameThread();
t.setRunning(true);
t.initView(v);
}
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (t.getRunning() == true) {
t.setRunning(false);
Log.v("Semajhan", "STOPPED");
} else {
t.setRunning(true);
Log.v("Semajhan", "RESTART");
}
}
return true;
}
protected void onDestroy() {
Log.v("Semajhan", "DESTROYING");
super.onDestroy();
}
protected void onStop() {
Log.v("Semajhan", "Stopping");
super.onStop();
}
I though i'd post the whole app since it is relatively small and so that I could get some help without confusion.
First, when you get a Force Close dialog, use adb logcat, DDMS, or the DDMS perspective in Eclipse to examine LogCat and look at the stack trace associated with your crash.
In this case, your exception will be something to the effect of "Cannot modify the user interface from a non-UI thread". You are attempting to call setText() from a background thread, which is not supported.
Using a GameThread makes sense if you are using 2D/3D graphics. It is not an appropriate pattern for widget-based applications. There are many, many, many, many examples that demonstrate how to create widget-based applications without the use of a GameThread.
You have to call it from the UI thread.
For more info check: Painless Threading .
If you decide to use a Handler, the easiest solution for you will be to:
Extend a View, override it's onDraw , in it draw the game objects, after you have calculated the game data for them first of course
The Handler: (in your Activity)
private Handler playHandler = new Handler() {
public void handleMessage(Message msg) {
gameView.postInvalidate(); // gameView is the View that you extended
}
};
The game thread has a simple
Message.obtain(playHandler).sendToTarget();
In 2 words, the View is responsible for the drawing (you can move the calculations in a separate class, and call it before the onDraw), the thread is responsible only for scheduled calls to the Handler, and the Handler is responsible only to tell the View to redraw itself.
You cannot update the UI of your app outside of the UI Thread, which is the 'main' thread you start in. In onCreate(Context) of you app, you are creating the game thread object, which is what is doing the updating of your UI.
You should use a Handler:
http://developer.android.com/reference/android/os/Handler.html

Categories

Resources