My app frequently throws exception like below:
E/WindowManager( 6282): android.view.WindowLeaked: Activity
com.myActivity has leaked window
com.android.internal.policy.impl.PhoneWindow$DecorView#4479b710 that
was originally added here
The app shows a progress dialog when the main activity starts and starts a task. When the task is done, it will dismiss the progress dialog.
My code is like below. Can someone help me?
public class MyActivity extends Activity {
private static int ID_DIALOG_PROGRESS = 2001;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
showDialog(ID_DIALOG_PROGRESS);
new MyTask().execute(null, null, null);
}
#Override
protected Dialog onCreateDialog(int id) {
if (id == ID_DIALOG_PROGRESS) {
ProgressDialog loadingDialog = new ProgressDialog(this);
loadingDialog.setTitle("");
loadingDialog.setMessage("");
loadingDialog.setIndeterminate(true);
loadingDialog.setCancelable(false);
return loadingDialog;
}
return super.onCreateDialog(id);
}
private class MyTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... arg0) {
/* Do something expensive here...*/
/* Start other activity*/
Intent intent = new Intent(MyActivity.this, OtherActivity.class);
startActivityForResult(intent, 1000);
}
return null;
}
protected void onPostExecute(Void arg0) {
dismissDialog(ID_DIALOG_PROGRESS);
}
}
}
Most of the time, the exception was thrown from showDialog() call. The other time, the exception was thrown from dismissDialog() call.
Thank you in advance!
You're starting a new activity in doInBackground() before you dismiss the dialog in onPostExecute(), which is probably what is causing the dialog to leak. I would move
Intent intent = new Intent(MyActivity.this, OtherActivity.class);
startActivityForResult(intent, 1000);
to onPostExecute() after the dismissDialog() call and see what happens.
It's also good practise to place a try...catch around
dismissDialog(ID_DIALOG_PROGRESS);
Otherwise you will probably receive random application crashes when under some circumstances the dialog is not available anymore e.g. after screen rotation.
Related
Everything is working fine, and the second Activity is running but My progress Dialog doesn't appear when I using Intent.
Is there an error in the code? , I can't find stack.
an idea ???
Please help me , Thanks!
public class StartActivity extends AppCompatActivity {
private Intent mIntent;
private final int totalProgressTime = 100;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
}
public void onClick(View view) {
new DownloadTask().execute();
mIntent = new Intent(this, MainActivity.class);
startActivity(mIntent);
}
private class DownloadTask extends AsyncTask<String,Void,Object>{
ProgressDialog mIndicator = new ProgressDialog(StartActivity.this);
#Override
protected void onPreExecute() {
super.onPreExecute();
mIndicator.setMessage("Wait..");
mIndicator.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mIndicator.setProgress(0);
mIndicator.setMax(totalProgressTime );
mIndicator.show();
new Thread(new Runnable() {
#Override
public void run(){
int counter = 0;
while(counter < totalProgressTime ){
try {
Thread.sleep(300);
counter ++;
mIndicator.setProgress(counter);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mIndicator.dismiss();
}
}).start();
}
#Override
protected Object doInBackground(String... params) {
return null;
}
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
mIndicator.dismiss();
}
}
}
Let's not talk about how wrong is to use AsyncTask as you used it here. I suppose you have some bigger picture, and this is just some test snippet.
So with
new DownloadTask().execute();
you started AsyncTask.
And just after that you started new activity:
mIntent = new Intent(this,MainActivity.class);
startActivity(mIntent);
So, AsyncTask continue to work in separate thread, but StartActivity is no longer active (probably not even visible), because MainActivity is in foreground now.
So, you want to see ProgressBar in StartActivity, but you are in MainActivity.
Try to wait AsyncTask to finish, than start MainActivity.
#Override
protected void onPostExecute(Object o) {
mIndicator.dismiss();
mIntent = new Intent(this, MainActivity.class);
startActivity(mIntent);
}
Please share how to use intent in doinbackground() or onpostexecute() methods Asynctask class.When I tried to use these codes it shows error.
Intent intent = new Intent(asynctask.this, home.class);
startActivity(intent);
finish();
private Class<Home> clazz;
public asynctask(Class<Home> clazz){
this.clazz = clazz;
}
Asynctask doInBackground() method:
protected Void doInBackground(Void... arg0) {
// TODO Auto-generated method stub
Intent intent = new Intent(this, clazz);
startActivity(intent);
finish();
Toast.makeText(cxt, "welcome", Toast.LENGTH_SHORT).show();
return null;
}
Try this way,hope this will help you to solve your problem.
How to asynctask class :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyCustomAsyncTask(this).execute();
}
MyCustomAsyncTask.java
public class MyCustomAsyncTask extends AsyncTask<Void,Void,Void> {
private Context context;
public MyCustomAsyncTask(Context context){
this.context=context;
}
#Override
protected void onPreExecute() {
// write show progress Dialog code here
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// write service code here
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(context, "welcome", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(context, home.class);
context.startActivity(intent);
((Activity)context).finish();
}
}
Move this Intent part in onPostExecute(...) method of AsynckTask
doInBackground(Void... arg0) should do only background task
you should put other code in onPostExecute(...) method. so that when background task is over move to other activity.
** Don't try to touch UI from doInBackground(....) your app may crash.
You cann't interact with UI in doInBackground(....). you can only interact with UI in onPostExecute(...). Just like thread you cann't interact with UI in Thread for UI we use Handler.
Always put intent in onPostExecute. This will ensure that your UI thread is in sync.
For example if your want to show that on receiving right credentials the user should move to next activity or else should be shown a message "Invalid credentials" in case they're wrong. Your onPostExecute should look like this:
protected void onPostExecute(final Boolean success) {
if(success){
Intent intent = new Intent(<CurrentActivity>.this, <NextActivity>.class);
startActivity(intent);
}
else{
Toast.makeText(LoginActivity.this, "Invalid Credentials", Toast.LENGTH_SHORT).show();
}
}
I am trying to implement an app in which I have to initially download a file, and only then can I proceed. So I don't want to make the screen idle for N number of seconds for the duration of downloads, I want to cover it with a splash screen. So basically downloading all the files, and it will be covered by the splash activity.
This is the code I generally use for splash activity, then jumping to the main activity after the delay.
The real problem is that I have the AsyncTask in the main_activity, I want to show the splash screen, while I can download the file in the AsyncTask . Then I can move to the main activity
new Handler().postDelayed(new Runnable() {
/*
* Showing splash screen with a timer. This will be useful when you
* want to show case your app logo / company
*/
#Override
public void run() {
// This method will be executed once the timer is over
// Start your app main activity
Intent i = new Intent(Splash_Screen.this, MainActivity.class);
startActivity(i);
// close this activity
finish();
}
}, 3000);
}
I recommande you to choose the AsyncTask, where you can do a task in the backGround in your example downloading the file, and in the post execution wich mean after your file is downloaded you can do what ever you want.
private class Asyn_DownLoadFile extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
//download your file here
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
/*this function is called automatically by the doInBackground when
it finish it's work*/
}
}
Just remenber AsyncTask must be subClassed, that's mean call implement the AsyncTask in the Splash screen Activity and in the onPostExecution do what you want
to start the AsyncTask use
new Asyn_DownLoadFile().execute(null,null,null);
EDIT:
here what you have to do:
suppose this your Splash class
public class SplashActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
context = this;
//.......................
new Asyn_DownLoadFile().execute(null,null,null);
}
//this is your function that downLoad the file
public void downLoadFile(){
//............................
}
private class Asyn_DownLoadFile extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
downLoadFile();
}
#Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
Intent i = new Intent (context, MainActivity.class)
startActivity(i);
}
}
}
Since the game requires TTS, and need quite a long time to load, I would like to implement Progress Dialog (PD), as either in the following ways:
Implement AsyncTask in Game Index Page:
This will show the PD, but the PD is freezed, i.e. the looping circle inside the PD is not looping.
buttonC.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
new initialize_game().execute();
}
});
private class initialize_game extends AsyncTask<String,Integer,String>
{
#Override
protected void onPreExecute()
{
dialog= new ProgressDialog(Index_game.this);
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setMessage("Loading!\nPlease wait...");
dialog.show();
}
#Override
protected String doInBackground(String... params)
{
buttonC.setBackgroundColor(getResources().getColor(R.color.tran_black));
Intent intent = new Intent(Index_game.this, Game_star_intro.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivityForResult(intent, 0);
overridePendingTransition(0, 0); // 0 for no animation
Index_game.this.finish();
return "Done!";
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
Log.i("result","" +result);
if(result!=null)
{
dialog.dismiss();
}
}
}
AsyncTask for TTS:
Once clicked from the Game Index Page, no PD is shown until the Game is loaded fully, and at that time then the PD pops up and off for a millisecond, i.e. even worse than that above.
private class MainFrameTask extends AsyncTask<String,Integer,String> implements OnInitListener, OnUtteranceCompletedListener
{
private Index_game_card_intro mainFrame = null;
public MainFrameTask(Index_game_card_intro mainFrame)
{
this.mainFrame = mainFrame;
}
#Override
protected void onCancelled()
{
stopProgressDialog();
super.onCancelled();
}
#Override
protected void onPreExecute()
{
startProgressDialog();
}
#Override
protected String doInBackground(String... params)
{
// setup TTS part 1.1
mTts = new TextToSpeech(Index_game_card_intro.this, this); // TextToSpeech.OnInitListener
return "Done!";
}
protected void onPostExecute(String result)
{
stopProgressDialog();
}
// setup TTS part 2
#Override
public void onUtteranceCompleted(String utteranceId)
{
Log.v(TAG, "Get completed message for the utteranceId " + utteranceId);
lastUtterance = Integer.parseInt(utteranceId);
}
// setup TTS part 3
#Override
public void onInit(int status)
{
if(status == TextToSpeech.SUCCESS)
{
int result = mTts.setLanguage(Locale.US); // <====== set speech location
mTts.setSpeechRate((float) 0.8);
mTts.setPitch(1.0f);
if(result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED)
{
// button_header.setEnabled(false);
}
else
{
// button_header.setEnabled(true);
mTts.setOnUtteranceCompletedListener(this);
}
}
}
}
// setup TTS part 4
private void speakText()
{
lastUtterance++;
if(lastUtterance >= loveArray.length)
{
lastUtterance = 0;
}
Log.v(TAG, "the begin utterance is " + lastUtterance);
for(int i = lastUtterance; i < loveArray.length; i++)
{
params.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, String.valueOf(i));
mTts.speak(loveArray[i], TextToSpeech.QUEUE_ADD, params);
mTts.playSilence(ttsilience, TextToSpeech.QUEUE_ADD, null);
}
}
Question:
I found that the Progress Dialog does not show out when Button C in the game index is pressed. However, when the Game_star_intro is finally loaded, the progress dialog pops up for a very very short time and then gone.
I would like to show the ProgressDialog when it is loading up the game, not after the game is loaded then the dialog pops for a millisecond.
In this way, I have also tried to put the load TTS in AsyncTask inside Game_star_intro, yet the result is the same: the dialog just pops up for a millisecond.
Actually how should the AsyncTask be coded?? I have followed some website like this http://karanbalkar.com/2012/10/tutorial-5-custom-progressdialog-with-asynctask/
Thanks for your time!
You shouldn't start your activity in background thread. Start it, for example, in your onClick() method. You should put only your expensive code in doInBackground(), separating it from the framework lifecycle stuff. I guess you should implement AsyncTask inside Game_star_intro class for this.
ProgressDialog is not showing probably because UI thread is freezed until the work is done.
Also, naming conventions in Java suggest name classes without underscores, i.e. GameStarIntro :)
If I understood correctly from your question, loading of the Game_star_intro activity takes a lot of time because you use TTS in creation of this activity. The code you use is wrong. ProgressDialog from Index_game won't be shown when another activity is running (or is being created). You should use AsyncTask in Game_star_intro activity and use TTS there. In Index_game just start Game_star_intro:
buttonC.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
Intent intent = new Intent(Index_game.this, Game_star_intro.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivityForResult(intent, 0);
}
});
And in Game_star_intro something like this
public void onCreate() {
...
new TTLTask().execute();
}
private class TTLTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute()
{
dialog= new ProgressDialog(Index_game.this);
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.setMessage("Loading!\nPlease wait...");
dialog.show();
}
#Override
protected String doInBackground(String... params)
{
//... TTS code
return null;
}
protected void onPostExecute(String result)
{
super.onPostExecute(result);
Log.i("result","" +result);
if(dialog.isShown())
{
dialog.dismiss();
}
}
}
I am using this simple code
public class Main extends Activity {
private ProgressDialog progressDialog;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//bouton Exemples de prix
findViewById(R.id.button1).setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
//start the progress dialog
runDialog(4);
Intent myIntent = new Intent(getBaseContext(), Exemple_prix.class);
startActivity(myIntent);
}
}
);
}
private void runDialog(final int seconds)
{
progressDialog = ProgressDialog.show(this, "", "Chargement...");
new Thread(new Runnable(){
public void run(){
try {
Thread.sleep(seconds * 1000);
progressDialog.dismiss();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
The progressDialog doesn't show but it works if I disable
//startActivity(myIntent);
Your progress dialog is tied to the activity, so it shows on top of the first activity, then immediately you're starting the new activity which covers both the old activity and the progress dialog. Is there a particular reason why you're showing the progress dialog? If it's related to work in the second activity, you should show it there instead.
On a side note, don't create a new thread just to sleep like that. Just use postDelayed.