Android Thread Allocation - growing heap? - java

Hi everyone out there,
i am developing an android application against API 7 at the moment in which i use an activity which need to be restarted. Lets say my activity looks like this:
public class AllocActivity extends Activity implements OnClickListener{
Button but;
private Handler hand = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_alloc);
but = (Button) findViewById(R.id.button);
but.setText("RELOAD");
but.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0){
Intent intent = getIntent();
startActivity(intent);
finish();
}
});
}
#Override
protected void onDestroy(){
super.onDestroy();
System.gc();
}
/****** THREADS AND RUNNABLES ******/
final Runnable fullAnim = new Thread(new Runnable(){
#Override
public void run(){
try{
hand.post(anim1);
Thread.sleep(2000);
hand.post(anim2);
Thread.sleep(1000);
// and so on
}catch(InterruptedException ie){ie.printStackTrace();}
}
});
final Runnable anim1 = new Runnable() {
#Override
public void run(){
// non-static method findViewById
ImageView sky = (ImageView)findViewById(R.id.sky);
}
};
}
The problem is that the gc doesnt seem to free the fullAnim thread so that the heap is growing by ~100K at every restart - till it slows down and crashes. Declaring fullAnim as static does solve this problem - but as i use non static references this doesnt work out for me.
So at this point i am kindof lost - and i hope u can advice me where to go next. Is there something i might be doing wrong or is there a tool i can use to manage threads to drop and free heap after restart.
kindly regards
UPDATE
thanks to everyone who answered - helped alot. using TimerTask did the trick in the end. i did the following change:
/****** THREADS AND RUNNABLES ******/
final TimerTask fullAnim = new TimerTask(){
#Override
public void run(){
try{
hand.post(anim1);
Thread.sleep(2000);
hand.post(anim2);
Thread.sleep(1000);
// and so on
}catch(InterruptedException ie){ie.printStackTrace();}
}
};
as the activity was more than 6k loc long this was a pretty decent solution without facing bigger impacts. KUDOS!
i dont use a Timer to shedule the task - dont know if its bad practice but
the animation is called like this:
Thread t = new Thread(fullAnim);
t.start();

A running Thread is never garbage collected.
A Thread is not stopped automatically if your Activity stops or is destroyed. It could run forever.
Every non-static inner class keeps a reference to the enclosing instance. E.g. hand.post(anim1); works inside that inner class because it has an implicit reference to AllocActivity.this.
So what you effectively do is to keep a reference to your Activity alive for longer than it is supposed to be alive, i.e. until after onDestroy.
Make sure to stop threads manually if you don't want them anymore.

Because final variable have low priority for GC. So you need to explicitly release the runneable objects in onPause() method because there is not ensurence onDestory() will call immediate after finish() call .
#Override
protected void onPause(){
super.onPause();
//cancel timer to stop animations
if(t!=null){
t.cancel();
}
System.gc();
}
UPDATE
use timer to achieve this
boolean isFirstAnim=true;
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
if(isFirstAnim){
// play your first animation at every
}else{
// play your second animation at every
}
}
}, 0, 3000);

What happens when all activities of an application finishes?
"When you call finish() this doesn't mean the Activity instance is
garbage collected. You're telling Android you want to close the
Activity (do not show it anymore). It will still be present until
Android decides to kill the process (and thus terminate the DVM) or
the instance is garbage-collected."
You need to implement your own stop method to stop the running thread, you can make a call to it in onDestroy
refer this Stopping a runnable
Alternatively
you can perform your operation in an asynctask and use onProgressUpdate() to publish progress on UI thread and use cancel(true) in combination with check in doInBackground() whether cancel has been called to stop the task.

Related

Updating Destroyed Activity UI from Handler Runnable

The following code updates a TextView till a certain condition evaluates to false and then the Handler postDelayed is not called further.
However if the activity is destroyed, it'll try to update a null TextView, what is the right way to handle this? I know I could put a defensive null check on TextView but that is still not truly thread safe.
#Override
protected void onCreate(Bundle savedInstanceState) {
Handler durationHandler = new Handler();
durationHandler.postDelayed(updateSeekBarTime, 50);
}
private Runnable updateSeekBarTime = new Runnable() {
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
};
In other words the updateSeekBarTime can at any execution point try to access data members of an already destroyed activity, how to prevent that?
Start your handler in onResume().
In onPause() stop the handler with
handler.removeCallbacksAndMessages(null); //null removes everything
I'm building my own Music Player app and I use
durationHandler.removeCallbacks(updateSeekBarTime);
in onStop(). It works for me.
EDIT:
The above line is helped by the fact that I prevent the Activity from being destroyed by using
#Override
public void onBackPressed() {
moveTaskToBack(true);
}
This ensures that the Activity is minimized instead of destroyed so that when opened again, it's very snappy.
EDIT 2:
private Runnable updateSeekBarTime = new MyRunnable();
private class MyRunnable extends Runnable {
private boolean dontWriteText = false;
#Override
public void run() {
timeElapsed = mediaPlayer.getCurrentPosition();
double timeRemaining = finalTime - timeElapsed;
if(!dontWriteText)
timeLeft.setText(String.format("%d", TimeUnit.MILLISECONDS.toSeconds((long) timeRemaining)));
if (timeRemaining >= 1000)
durationHandler.postDelayed(this, 200);
}
public void dontWriteText() {
dontWriteText = true;
}
};
Then call updateSeekBarTime.dontWriteText() in onDestroy() or onStop(). I'd prefer onStop().
So after some code searching and reading blogs I found the answer in sample code of Communicating with the UI Thread
Even though you can and should be removing callbacks from handler:
handler.removeCallbacksAndMessages(null)
But the above does not prevent the existing running Thread from accessing a destroyed Activity or its views.
The answer I was looking for is WeakReference.
Create a weak reference to the TextView or UI element that you'll
access. The weak reference prevents memory leaks and crashes, because
it automatically tracks the "state" of the variable it backs. If the
reference becomes invalid, the weak reference is garbage-collected.
This technique is important for referring to objects that are part of
a component lifecycle. Using a hard reference may cause memory leaks
as the value continues to change; even worse, it can cause crashes if
the underlying component is destroyed. Using a weak reference to a
View ensures that the reference is more transitory in nature.
You should still check for null reference but now the view will be set to null by the active thread/runnable so you will not face a race-condition.

Android Thread explanation?

Sorry everyone this has been asked a few times but I just do not understand any of the answers because most are about timed UI updates. So I have a backgroundTasks thread that is called when my app first starts(Does network connections so..I think that's how you do it?)
public class MainActivity extends ActionBarActivity {
String data[][];
int arrayPosition = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
runBackgroundTask();
}
Here is my thread..
public void runBackgroundTask(){
new Thread(new Runnable() {
public void run() {
data = pullSchedule(data);
updateUI(data,arrayPosition);
}
}).start();
}
All it does is call a method pullSchedule which updates a 2D array with a webcrawler. So my problem comes when I call the updateUI method which is also used by two buttons to cycle through the array data which work perfectly fine. It's just when the thread first runs if I try to update the UI I get an error.
public void upDateUI(String data[][], int arrayPosition){
TextView gameTime =(TextView)findViewById(R.id.txtDate);
//more but deleted to save space :)
}
I have researched why I cannot update the UI from the background thread but I don't understand how to fix this? I thought about putting that entire method into the runOnUiThread(new Runnable()but then I believe my data and arrayPosition have to be declared final because of an inner class..First Android app just lost. Thanks for any help.
you can use asyntask for this from which you can update ui
public myAsyn extends AsyncTask<Void,Void,Void>
{
#Override
protected String doInBackground(Void... params) {
data = pullSchedule(data);
return null;
}
#Override
protected void onPostExecute(String result) {
updateUI(data,arrayPosition);
}
}
doInBackground runs on seperate thread whereas onPostExecute runs on Ui thread therefore you can update UI from there.
You are on the right track. The reason your app is crashing is because you are attempting to update a UI element off of the UI thread. To avoid this, you can either do as RichS suggested, and use an AsyncTask which will execute onPostExecute() on the UI thread, or surround your updateUI() call in your background thread with runOnUiThread(new Runnable() {....

Sleep() in Android Java

I am following this tutorial to have a loading screen in my program. The tutorial says my activity should Sleep() using the Sleep() command, however it does not recognize Sleep() as a function and provides me with an error, asking if I would like to create a method called Sleep().
Here is the code sample:
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 2500;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
new Handler().postDelayed(new Runnable(){
#Override
public void run() {
//Simulating a long running task
this.Sleep(1000);
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
}
You can use one of the folllowing methods:
Thread.sleep(timeInMills);
or
SystemClock.sleep(timeInMills);
SystemClock.sleep(milliseconds) is a utility function very similar to Thread.sleep(milliseconds), but it ignores InterruptedException. Use this function for delays if you do not use Thread.interrupt(), as it will preserve the interrupted state of the thread.
The function is Thread.sleep(long).
Note, however, that you should not perform a sleep on the UI thread.
The code you posted is horrible. Please don't use that on an actual device. You will get an "Application Not Responding" error if you run something similar to this.
If you're using Handlers, keep in mind that a Handler is created on the thread where it runs. So calling new Handler().post(... on the UI thread will execute the runnable on the UI thread, including this "long running operation". The advantage is that you can create a Handler to the UI Thread which you can use later, as shown below.
To put the long running operation into a background thread, you need to create a Thread around the runnable, as shown below. Now if you want to update the UI once the long running operation is complete, you need to post that to the UI Thread, using a Handler.
Note that this functionality is a perfect fit for an AsyncTask which will make this look a lot cleaner than the pattern below. However, I included this to show how Handlers, Threads and Runnables relate.
public class LoadingScreenActivity extends Activity {
//Introduce a delay
private final int WAIT_TIME = 2500;
private Handler uiHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHandler = new Handler(); // anything posted to this handler will run on the UI Thread
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
Runnable onUi = new Runnable() {
#Override
public void run() {
// this will run on the main UI thread
Intent mainIntent = new Intent(LoadingScreenActivity.this,ProfileData.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
};
Runnable background = new Runnable() {
#Override
public void run() {
// This is the delay
Thread.Sleep( WAIT_TIME );
// This will run on a background thread
//Simulating a long running task
Thread.Sleep(1000);
System.out.println("Going to Profile Data");
uiHandler.post( onUi );
}
};
new Thread( background ).start();
}
use Thread.sleep(1000);
1000 is the number of milliseconds that the program will pause.
try
{
Thread.sleep(1000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
Keep in mind: Using this code is not recommended, because it is a delay of time but without control and may need more or less time.

Easiest way of creating a timer in android?

Im trying to make a timer for a game, and I'm stuck atm.
This is my code so far. I made a new activity for the intent, cause I read somewhere that's one way to do it.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//Timer timer = new Timer();
//task = new TimerTask() {
Button b1 = (Button) findViewById(R.id.button1);
b1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v){
startActivity(new Intent("com.loltimer.Timer"));
}
});
};
}
When I press the first button I want to have a timer that goes from 5minutes down to 0. And at 0 I want a sound to be played.
Thanks in advance!
Has got to be the Android count down timer class: http://developer.android.com/reference/android/os/CountDownTimer.html
Timing operations are best handled by a Handler in Android.
http://developer.android.com/reference/android/os/Handler.html
You can wrap the operation you want to run in the future as a Runnable and pass it to postDelayed(). If the operation needs to run repeatedly on that interval, you can call postDelayed() at the end of the Runnable to schedule the next run.
CountdownTimer can also be useful if you need to run some code a finite number of times on a regular interval. This class is actually just a thin wrapper around Handler.

Access a thread to notify it from another method (Android application)

I'm developping an android application and trying to deal with threads without really knowing a lot about them... (Yeah bit stupid of me, I know)
I'll try to explain it properly and quite quickly.
In the onCreate method of my activity, I'm calling an AlertDialog to make the user choose to either load data from the internet or directly access the application using the data previously stored in database.
For that, in the onCreate, I call my method to raise the AlertDialog, positive button should start the worker thread to download, and negative button should call intent to move to next activity. So far, I got this :
by not calling wait() anywhere, my AlertDialog appears but the thread starts anyway
by calling wait() at the first line of my thread, I have to declare it static to access it from the listeners of my AlertDialog and be able to notify() it or interrupt(), I receive the error: object not locked by thread before wait().
worker = new Thread(new Runnable() {
public void run() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
[rest of my run method]
private void miseAJourDesDonnes() {
confirmInscrip = new AlertDialog.Builder(this).setMessage(
"Voulez-vous mettre à jour l'intégralité des données de l'application? (Connexion internet requise").setPositiveButton("Mettre à jour",
okListener).setNegativeButton("Continuer sans", nonListener);
confirmInscrip.create();
confirmInscrip.show();
}
OnClickListener okListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Toast.makeText(AccueilSplash.this, "Mise à jour en cours", Toast.LENGTH_SHORT).show();
worker.notify();
return;
}
};
OnClickListener nonListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Toast.makeText(AccueilSplash.this, "Accès direct à l'application", Toast.LENGTH_SHORT).show();
worker.interrupt();
Intent entre = new Intent(AccueilSplash.this, Androt.class);
startActivity(entre);
}
};
worker is my instance of Thread (the bbackground one)
Am I just being dumb or Is there a subtility I havent grasped?
thanks for any answer...
Below is a quick explanation of how wait() and notify() works but might I suggest that you just don't create the worker thread unless the user clicks ok? You may still want to cancel the thread later if they want to stop the download but creating the thread before you even know if it going to be used doesn't seem like the best approach.
In order to call wait(), notify(), or notifyAll() on an object you must first own the monitor of the object you wish to call the method on, so in you case within the runnable this would be how you would need to do it:
Runnable runnable = new Runnable() {
public void run() {
// wait(); This call wouldn't work
syncronized (this) {
wait(); // This call will work
}
}
};
To notify that runnable you would also have to have the monitor
// runnable.notifyAll(); this call will not work
syncronized (runnable) {
runnable.notifyAll(); // this call will work
}
For more information about threads and concurrency in Java I would suggest Java Concurrency in Practice
There may be some built in framework for background tasks in Android that I don't know about but using pure java the easiest approach to this seems like it would be something like this:
private Thread downloadThread;
OnClickListener okListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
Runnable download = new Runnable() {
public void run() {
// Create your input streams and such
boolean downloadComplete = false;
while(!downloadComplete && !Thread.currentThread().isInterruped()) {
// Do some downloading
}
if (!Thread.currentThread().isInterruped()) {
// Alert user of success.
}
}
};
downloadThread = new Thread(download);
downloadThread.start();
}
};
OnClickListener cancelListener = new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
downloadThread.interrupt();
}
};
I'm new to using threads as well, but you could try reading this example to give you a good starting point. It's about progress dialogs, but it illustrates how to manage threads and start them up at the right time. The really useful code is collapsed under the 'see more about Progress Dialgos with a second Thread' section.
Going to your code, I think your mistake is in how you declare your thread. Try instead creating is as a class extending Thread. e.g.
private class Worker extends Thread{
Handled mHandler; //See the example linked above for how to use handlers
int progress;
//and whatever other variables it might need
worker(Handled h){
mHandler = h;
//and any other initialisation you need
}
public void run(){
//and all your code here
}
}
Then nothing happens with this Thread until you instantiate it with the following, in your onClickListeners.
Worker worker = new Worker(handler)
Even after that it won't actually start until you call worker.start(). Define your handler along the lines of
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
int progress = msg.getData().getInt("progress");
loadingDialog.setProgress(progress);
if (progress >= 100){
dismissDialog(LOADING_DIALOG);
}
}
};
Hope that helps you get started! Do read the link above, as I imagine you'll want some kind of progress dialog as well when it's actually doing the loading from the website. Or perhaps it would be done in a background service, but I couldn't help you with that.

Categories