Im trying to call a function from within a doInBackground of an AsyncTask that fades in a progressBar. Everytime i call this function the progressbar fades in as required then disappears. I added a check at the end which tells me that the visibility of the progressbar has returned back to GONE as soon as the runOnUIThread method completes:
Reset Prog To Gone
Why is this and how can I make it so the progressbar remains visible?
I have been using the following:
#TargetApi(12)
private void fadeInProgressBar(final int time, ProgressBar prog){
System.out.println("MainActivity: Fading In ProgressBar");
runOnUiThread(new Runnable(){
#Override
public void run() {
if(usingHigherApiThan(12)&&prog.getVisibility()==View.GONE){
prog.setVisibility(View.VISIBLE);
if(prog.getAlpha()<1){
prog.animate().setDuration(time).alpha(1);
}
}else if(prog.getVisibility()==View.GONE){
prog.setVisibility(View.VISIBLE);
final AlphaAnimation animation = new AlphaAnimation(0F, 1F);
animation.setDuration(time);
animation.setFillAfter(true);
prog.startAnimation(animation);
}
}
});
if(prog.getVisibility()==View.VISIBLE){
System.out.println("Left Prog Visible");
}else{
System.out.println("Reset Prog To Gone");
}
}
note usingHigherApiThan(12) just checks the build version is 12 or greater and this problem occurs for both above 12 and below 11.
You don't need to, and probably shouldn't, do it this way. AsyncTask has methods that run on the UI thread already (all but doInBackground())
Put your code that you want to run on the UI into onPostExecute() to run when doInBackground() has finished.
Or if it suits your needs better you can also put the code in onProgressUpdate() and call this function when needed with publishProgress().
Alternatively, if you only need it to run when the task starts then you can just put it in onPreExecute(). All of these run on the UI Thread. There's no need to add extra steps with runOnUiThread().
AsyncTask Docs
Related
I am just starting to learn Android, Java and need help.
I have an activity with the countdowntimer, which works fine. However, I want it to be displayed in the fragment. What is the best way to do it?
I tried calling Timer.getCountdowntimer, I tried calling Timer.getUserTime (userTime is the user selected time for the countdowntimer), but the textview in my fragment doesn't display the timer.
thanks in advance!
If you are coding in Java purely, and want to use the android SDK to do it, I would recommend:-
//Create a handler that runs on main loop so we can update UX
final android.os.Handler handler = new android.os.Handler(Looper.getMainLooper());
//Get a callback in 1 second
handler.postDelayed(new Runnable() {
int timer;
#Override
public void run() {
timer += 1;
myTextView.setText(String.valueOf(timer));
//Recursively get another callback in a second
handler.postDelayed(this, 1000);
}
}, 1000);
Make sure you add some logic to stop the timer when you want, and also onPause/onResume
I need to add an artificial pause before my AI plays its turn on the tic tac toe board. However, when I try to use something like Thread.sleep, in the location where I have the comment, the entire onClick function lags. What I mean by lagging is that the ((Button) v).setText("0") does not set the button text to 0 for the amount of time I use the sleep function and the moment that the timer is up, everything happens immediately. It is like the lag happens in the beginning of the function rather than the middle where the comment is. Is there anyway to address this problem or explain why the sleep function isn't lagging where it is suppose to be?
public void onClick(View v) {
if(!((Button) v).getText().toString().equals("")){
return;
}
((Button) v).setText("0");
turn();
// Need a pause before tictacAI does anything
tictacAI("0", "X").setText("X");
turn();
if(won){
resetBoard();
won = false;
}
}
When using Thread.sleep in onClick, you are actually blocking the entire UI Thread, This will prevent Android Framework redraw your view, so your change to View's property will not be displayed.
In order to delay the execution, you should use View.postDelayed, which will post your action to a message queue and execute it later.
public void onClick(View v) {
if(!((Button) v).getText().toString().equals("")){
return;
}
((Button) v).setText("0");
turn();
// Need a pause before tictacAI does anything
v.postDelayed(new Runnable() {
#Override
public void run() {
tictacAI("0", "X").setText("X");
turn();
if(won){
resetBoard();
won = false;
}
}
}, 1000L); //wait 1 second
}
If you are using Java 1.8, you can use lambda instead of anonymous class.
Another note:
this Runnable will not be garbage collected until executed, so a long interval may cause your entire view leaked, which is very bad. Consider using View.removeCallbacks when this callback is not needed anymore(like activity's onDestroy, for example)
In my app, I am showing a dialog during a long-running background process which is modal.
This dialog is dismissed when android returns from the background task.
final ProgressDialog progressDialog = ProgressDialog.show(activity, "", "Doing something long running", true, true);
new Thread(new Runnable() {
public void run() {
someLongRunningCode(); // (not using AsyncTask!)
activity.runOnUiThread(new Runnable() {
public void run() {
progressDialog.dismiss();
}
});
}
}).start();
Now, however, when the user rotates his device while the background process is still running the activity is recreated and thus, the progressdialog gets detached from the activity.
When the long running process is done, android obviously tries to hide the (now detached) progress dialog which then results in an exception: java.lang.IllegalArgumentException: View not attached to window manager.
Is there any way to check if it is safe to dismiss the dialog?
Edit: Or better still, is there any way to attach the existing dialog to the newly created activity?
A new, cloned dialog would be fine aswell.
Just catch the exception and ignore it. Android's decision to restart the activity on rotation makes threads have a few odd exceptions like that. But the end result you want is no dialog box displayed. If you just catch the exception, no dialog box is displayed. So you're good.
If you aren't using a separate layout/drawables for landscape and portrait, you can just override configChange in your manifest for the activity so it doesn't destroy the activity (it will still correctly rotate and resize everything for you). That way the same dialog will be up and you shouldn't get the exception. The other option would require a lot of work around onSaveInstanceState and onRestoreInstanceState, and you'd need to be very careful of timing issues if the thread actually finishes during that time. The whole recreate activity on rotation idea doesn't work well with multithreading.
if (progressDialog != null) {
progressDialog.dismiss();
}
I've faced this issue before and solved using the below code.
private boolean isDialogViewAttachedToWindowManager() {
if (dialog.getWindow() == null) return false;
View decorView = progressDialog.getWindow().getDecorView();
return decorView != null && decorView.getParent() != null;
}
I'm making a little game and in it I have to check if a value is zero every second. When it is zero the game should stop and show a dialog instead.
As from now the game never ever shoud work until the app is reinstalled.
So, I have an timer with an timertask which executes a runOnUiThread.
Timer:
private void update(){
Timer timer = new Timer();
timer.schedule(new TimerTask(){
#Override
public void run() {
onChange();
}
},0,(1000* getResources().getInteger(R.integer.remove_speed_inSecond)));
}
runOnUiThread: (with try/catch to catch the exeption at this point but i want to fix and not just ignore it.)
private void onChange(){
runOnUiThread(new Runnable() {
#Override
public void run() {
try{
checkupifexpire();
}
catch (Exception ex) {
}
}
});
}
The Method where i show the dialog:
private void checkupifexpire() {
if(eat == 0 || drink == 0 || wash == 0 || care == 0){
dialog = new Dialog(this, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener()
{
#Override
public void onCancel(DialogInterface dialog)
{
GameEngine.this.finish();
}
});
dialog.setContentView(R.layout.activity_rip);
dialog.show();
}
}
Always when I press the back button or just the home button then the App crashes.
Any Idea how to fix this?
So, the logcat tells us that is crashes on line 306 of GameEngine.java, in the method checkupifexpire, which looks like it is the dialog.show() line.
I'm not 100% sure, but from what you've said, it would seem to me that when back or home is pressed, the app will lose its UI thread. This means that checkuponexpire cannot do what it does.
To solve your crash problem, there are three obvious options:
You could use onPause in your main activity to catch when the app loses the screen. At this point you need to either stop the timer, or switch it to using Toast to communicate information.
Only use Toast in checkuponexpire
Decide that when the back or home is pressed the game is over anyway and cancel the Timer.
To Actually get the dialog, it may also be helpful to change the context you use to create the dialog with. Although it should be used sparingly, it may be that getApplicationContext() is what you need here (possibly this.getApplicationContext()).
Thanks to Neil Townsend and WELLCZECH. :)
My problem was the Lifecycles.
Mostly i had the App running in the onCreat() and had no onStart() method.
Just didn't know that thies methods were as much important as they are.
Also i didn't need a dialog shown. Instead i just have to start a new activity and cancel the old one.
The example is pretty straightforward: i want to let the user know about what the app is doing by just showing a text (canvas.drawText()). Then, my first message appears, but not the other ones. I mean, i have a "setText" method but it doesn't updates.
onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(splash); // splash is the view class
loadResources();
splash.setText("this");
boundWebService();
splash.setText("that"):
etc();
splash.setText("so on");
}
The view's text drawing works by doing just a drawText in onDraw();, so setText changes the text but doesn't show it.
Someone recommended me replacing the view with a SurfaceView, but it would be alot of trouble for just a couple of updates, SO... how the heck can i update the view dinamically at runtime?
It should be quite simple, just showing a text for say 2 seconds and then the main thread doing his stuff and then updating the text...
Thanks!
Update:
I tried implementing handler.onPost(), but is the same story all over again. Let me put you the code:
public class ThreadViewTestActivity extends Activity {
Thread t;
Splash splash;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
splash = new Splash(this);
t = new Thread(splash);
t.start();
splash.setTextow("OA");
try { Thread.sleep(4000); } catch (InterruptedException e) { }
splash.setTextow("LALA");
}
}
And:
public class Splash implements Runnable {
Activity activity;
final Handler myHandler = new Handler();
public Splash(Activity activity) {
this.activity=activity;
}
#Override
public void run() {
// TODO Auto-generated method stub
}
public synchronized void setTextow(final String textow) {
// Wrap DownloadTask into another Runnable to track the statistics
myHandler.post(new Runnable() {
#Override
public void run() {
TextView t = (TextView)activity.findViewById(R.id.testo);
t.setText(textow);
t.invalidate();
}
});
}
}
Although splash is in other thread, i put a sleep on the main thread, i use the handler to manage UI and everything, it doesn't changes a thing, it only shows the last update.
I haven't hit this yet, but I think the usual pattern is to do lengthy initialization in a background thread, and use Handler.post() to update the UI. See http://developer.android.com/reference/android/widget/ProgressBar.html for a different, but possibly related, example.
Also see this answer, especially the first paragraph:
The problem is most likely that you
are running the splash screen (some
sort of Dialog such as ProgressDialog
I assume) in the same thread as all
the work being done. This will keep
the view of the splash screen from
being updated, which can keep it from
even getting displayed to the screen.
You need to display the splash screen,
kick off an instance of AsyncTask to
go download all your data, then hide
the splash screen once the task is
complete.
Update (based on your update and your comment): You are not supposed to update the UI in any thread except the one where your Activity is created. Why is it impossible for you to load your resources in a background thread?
First: onCreate is executed on main UI thread of application so no UI updates until you leave it. Basically you need one thread to execute long running tasks and some mechanism to push updates into the UI.
Most usual approach is to extend AsyncTask see this link for further info
i suppose that your view is an extended view and you call onDraw for drawing the view, so, maybe the view isnĀ“t 'refresh' their state, so try this
onCreate(Bundle bundle) {
setContentView(splash); // splash is the view class
loadResources();
splash.setText("this");
splash.invalidate();
boundWebService();
splash.setText("that"):
splash.invalidate();
etc();
splash.setText("so on");
splash.invalidate();
}