I tried to get the width of a LinearLayout.
Here is the code of the MainActivity.java:
public class MainActivity extends AppCompatActivity {
BoardClass board;
private int widthareagame;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final LinearLayout gamearea;
ImageView im1 ;
Button abutton;
abutton = (Button) findViewById(R.id.buttonnew);
gamearea = ( LinearLayout) findViewById(R.id.boardarea);
gamearea.post(new Runnable(){
public void run(){
widthareagame = gamearea.getWidth();
}
});
board = new BoardClass(this,widthareagame);
gamearea.addView(board);
}
The value of widthareagame at new BoardClass(this,widthareagame); is still Zero.
Thanks
Here is what documentation says about View#post():
Causes the Runnable to be added to the message queue. The runnable
will be run on the user interface thread.
Your task, of modifying the value of widthareagame variable, has been pushed to the message queue of the view. It doesn't guarantee that it will get executed at the very same instance. The control then proceeds to the next line, where you still get the unmodified value.
You can try something like this, to ensure that you are able to use the modified value:
gamearea.post(new Runnable(){
public void run(){
widthareagame = gamearea.getWidth();
board = new BoardClass(this,widthareagame);
gamearea.addView(board);
}
});
This is because post method call queued the setting of widthareagame where as your view is rendering.You didn't guarantee the order of execution.
You have to make sure the statements inside the run method execute first and then new Board(.. is invoked.For that you can do something like this
final AtomicBoolean done = new AtomicBoolean(false);
run(){
//inside run method
done.set(true);
notify();
}
then do something like this
synchronized(task) {
while(!done.get()) {
task.wait();
}
new Board(..
}
where task is your runnable task defined something like this
final Runnable task = new Runnable() {
#Override
public void run() {
The reason is zero is because within the onCreate the LinearLayout has not been measured yet.
And the reason it only works when within the Runnable is because since this one has been posted then it will run on the next execution cycle, which is after the onCreate and the rest of the Activity lifecycle methods (onStart, onResume, etc.) and even onAttachedToWindow have been called, at which point will be already measured and give the correct size.
Said all that, a safer way to get your layout metrics with certainty would be to listen when the layout state changes.
gamearea.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remove the listener here unless you want to get this callback for
// "every" layout pass, which can get you into an infinite loop if you
// modify the layout from within this method
gamearea.getViewTreeObserver().removeGlobalOnLayoutListener(this);
// A this point you can get the width and height
widthareagame = gamearea.getWidth();
}
});
Related
I am creating like a Whack a Molee type of game, and I am creating imageviews at random positions on the screen.
The thing is, I am adding a postdelayed to a var I am creating every two seconds ( the var is the imageview) but it only acts to the last imageview created. It happens because every two seconds that var is replaced with a new instance of imageview.
How can I add an independent postdelayed or something that detects when 2 seconds has passed and removing that specific imageview.
Thanks!
mv = new ImageView(this);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
mv.setVisibility(View.GONE);
}
}, 2000);
I tried this, but only removes the very last imageview.
public void createImage() {
final ImageView mv = new ImageView(this);
// Do all your positioning and sizing (layout params) setting stuff here
new Handler(getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
mv.setVisibility(View.GONE);
}
}, 2000);
}
Simply don't override the value every time, by using a local varaible inside a method.
This way the mv instance will be the same in the runnable which is executed by the handler.
(And also don't create a handler every time)
(You could also draw the entire thing on a canvas)
I'm new to Android.
I want to modify the TextView of my activity after a few seconds (it says "hey hey!" at first; I want it to say "hello!" after a few seconds), so I have:
protected void onResume() {
super.onResume();
final TextView t = (TextView)findViewById(R.id.hello);
Runnable changeTextTask = new Runnable() {
public void run() {
t.setText("hello!");
}
};
Handler h = new Handler();
h.postDelayed(changeTextTask, 3000);
}
Which works. However, when I declare the Runnable at the beginning of the class, like so:
public class MainActivity extends ActionBarActivity {
final TextView t = (TextView)findViewById(R.id.hello);
Runnable changeTextTask = new Runnable() {
public void run() {
t.setText("hello!");
}
};
.
.
.
protected void onResume() {
super.onResume();
Handler h = new Handler();
h.postDelayed(changeTextTask, 3000);
}
the app crashes upon starting. Can anyone explain why this happens/what I'm doing wrong?
what I'm doing wrong?
First, use LogCat to examine the Java stack trace of your crash.
Second, do not call inherited methods on your Activity, like findViewById(), until inside of onCreate(), and usually after the super.onCreate() call. onResume() is called after onCreate() completes, which is why your first edition survives better.
Third, specifically with findViewById(), you need to call that after the widget already exists. That will not occur until setContentView() or equivalent means of setting up your UI.
Mixing Sotirios Delimanolis' and CommonsWare's responses here:
LogCat reveals findViewByID() caused a NullPointerException because it was called before onCreate() (where the resource with the TextView is loaded) as soon as the activity starts.
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() {....
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.
I'm designing a music player app for Android that will feature pop-up controls. I'm currently trying to get these controls to close after a certain period of inactivity but there doesn't seem to be a clearly documented method of doing this. So far I have managed to cobble the following solution together using a few suggestions both from this site and others.
private Timer originalTimer = new Timer();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.playcontrols);
View exitButton = findViewById(R.id.controls_exit_pane);
exitButton.setOnClickListener(this);
View volUpButton = findViewById(R.id.controls_vol_up);
volUpButton.setOnClickListener(this);
View playButton = findViewById(R.id.controls_play);
playButton.setOnClickListener(this);
View volDownButton = findViewById(R.id.controls_vol_down);
volDownButton.setOnClickListener(this);
musicPlayback();
originalTimer.schedule(closeWindow, 5*1000); //Closes activity after 10 seconds of inactivity
}
And the code that should close the window
//Closes activity after 10 seconds of inactivity
public void onUserInteraction(){
closeWindow.cancel(); //not sure if this is required?
originalTimer.cancel();
originalTimer.schedule(closeWindow, 5*1000);
}
private TimerTask closeWindow = new TimerTask() {
#Override
public void run() {
finish();
}
};
The above code makes perfect sense to me but it force closes upon any user interaction. It does however close normally if untouched and won't close after interaction if I remove the second schedule, so this seems to be the problem. Also note that I imagine I will be moving this timing task to another thread to help keep the UI snappy. I need to get it working first though :D. If there's any more info I need to supply please ask and thanks for any help...Ye guys are brilliant!
Based on #CommonsWare's suggestion, switched to a Handler. Works perfectly. Thanks very much!
private final int delayTime = 3000;
private Handler myHandler = new Handler();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.playcontrols);
View exitButton = findViewById(R.id.controls_exit_pane);
exitButton.setOnClickListener(this);
View volUpButton = findViewById(R.id.controls_vol_up);
volUpButton.setOnClickListener(this);
View playButton = findViewById(R.id.controls_play);
playButton.setOnClickListener(this);
View volDownButton = findViewById(R.id.controls_vol_down);
volDownButton.setOnClickListener(this);
musicPlayback();
myHandler.postDelayed(closeControls, delayTime);
}
and the other methods...
//Closes activity after 10 seconds of inactivity
public void onUserInteraction(){
myHandler.removeCallbacks(closeControls);
myHandler.postDelayed(closeControls, delayTime);
}
private Runnable closeControls = new Runnable() {
public void run() {
finish();
overridePendingTransition(R.anim.fadein, R.anim.fadeout);
}
};
To complete the answer above, note that the Activity.onUserInteraction() is adequate only if you care about clicks.
The documentation at http://developer.android.com/reference/android/app/Activity.html#onUserInteraction%28%29 states: "Note that this callback will be invoked for the touch down action that begins a touch gesture, but may not be invoked for the touch-moved and touch-up actions that follow."
Actual implementation proved it indeed ignores all movements on the tablet, which means the clock is never reset while, say, drawing without releasing the finger. On the other hand, it also means that the clock is not reset too often, which limits the overhead.