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

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?

Related

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

what is a good way to stop a thread in android

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

Taking heavy computation off the Android UI Thread

My Android app employs a particularly big computation which keeps crashing the system because it is on the UI thread in the Activity.
I have little confidence in multithreading and so I want to get some tips on how to do it correctly.
This is what I have
class ActivtyName extends Activity{
boolean threadcomplete = false;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//stuff
Runnable newthread = new Runnable(){
#Override
public void run() {
doBigComputation();
threadcomplete=true;
}
};
newthread.run();
boolean b = true;
while(b){
if(threadcomplete){
b=false;
startTheApp();
}
}
}
}
Now, I am pretty sure what I have done is not "correct". (It seems to work though. The sistem doesn't crash). Basically, I'm not sure how the UI thread can be told that newthread has finished the computation without this boolean, threadcomplete. Is there a "correct" way to do this?
Just to expand a bit on Marek Sebera's comment, here's the framework on how you would accomplish that in an AsyncTask.
private class BigComputationTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
// Runs on UI thread
Log.d(TAG, "About to start...");
}
#Override
protected Void doInBackground(Void... params) {
// Runs on the background thread
doBigComputation();
}
#Override
protected void onPostExecute(Void res) {
// Runs on the UI thread
Log.d(TAG, "Big computation finished");
startTheApp();
}
}
And to call it:
BigComputationTask t = new BigComputationTask();
t.execute();
In addition to Marvin's answer, there's a good article on the Android developer site about precisely this.
That's not the correct way to start a thread. You need to do:
Runnable newthread = new Runnable(){
#Override
public void run() {
doBigComputation();
threadcomplete=true;
}
};
Thread t = new Thread(newthread);
newthread.start();
boolean b = true;
while(b){
if(threadcomplete){
b=false;
startTheApp();
}
}
When i want to use threads, I've almost a big while loop. I put a boolean condition who's always true, except when I want to stop it.
I use Thread (http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Thread.html) and I reimplement the stop method because it's deprecated. So in my stop method I can put a false value to the loop variable.
To terminate the thread, I use t.stop(). So you can di that in your activity.
If you want to know when a Thead stops, you can use t.isAlive(). If the thread t is started, isAlive will return true.

Android: Updating gridview multiple times after x seconds

I am having a problem updating the view in android every x seconds.
To get to know how android works I am writing a small game.
It has a GameController which holds the game loop. Inside the loop, the logic is executed and afterwards the gui will be informed about the changes.
The problem is that the changes cannot be seen in the view. The view stays the same until the game loop finishes and updates then only once.
Here is my code (the important parts):
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
}
}
I googled a lot and tried a lot as well (and I do know that similar questions where asked here already, but they did not help me either), but somehow it just does not work.
I cannot get it do work that the view and logic run on different theads in android, and if they run on the same thread the logic blocks the view.
Any help would be greatly appreciated.
// edit:
If I try new Thread(c).start(); LogCat sais:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
And if I add Looper.prepare(); :
java.lang.RuntimeException: Unable to start activity ComponentInfo{GameActivity}: java.lang.RuntimeException: Only one Looper may be created per thread
If I try this.runOnUiThread(c); there are no errors.
First, this doesn't seems like the way to crate a game, you will need to use SurfaceView, or GLSurfaceView to better do what you want.
You can also look for Cocos2d for android, it's a 2D platform (that was ported from iPhone) that makes you life easier:
http://code.google.com/p/cocos2d-android/
I muse warn you though, I tried it a couple months back, and it was not production grade yet, it did crash from time to time.
Anyway, if you still want to continue heading your way I'll try answering your question:
I think you are messing too much with the way these stuff should work. try understanding first how handlers work with threads.
Do anything you want on your thread:
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
calculateGameChangesHere();
handler.sendEmptyMessage(SUCCESS);
}
catch (Exception e)
{
handler.sendEmptyMessage(FAILURE);
}
}
}).start();
When your data is ready, tell the handler to put it in a view and show it:
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...
}
}
};
This goes to everything that requires heavy processing/networking that shouldn't block your UI thread.
Hope this helps.
Not sure what you are trying to achieve by refreshing a listView every few seconds. Anyways if you are writing some 2d games, you have to use SurfaceView , which is especially meant for continuous refreshing.
Had the same problem and solved it using a pretty simple code.
Tips:
GridView must be refreshed by the UI thread
To display every change you must keep the loop and the Sleep method away from the UI thread
Solution:
Method to update the grid (put on your Activity that you build your GridView at the first place or wherever)
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();
}
Build the non UI Thread that does the work
public class DataReceiver implements 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();
}
}
}
}

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