I have a class with a thread and a progress dialog. When the thread stops, the dialog must dismiss. But if the thread stops, the app crashes :S Has anyone an idea whats wrong?
public class Main extends Activity {
public static ProgressDialog LoadingDialog = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LoadingDialog.show(AndroidRSSReader.this, "Laden...", "Even geduld aub...", true);
setContentView(R.layout.main);
startUp();
new Thread(new Runnable(){
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LoadingDialog.dismiss();
}
}).start();
}
LoadingDialog is still null when you call dismiss. You need to make sure and assign it to something (like your progress bar).
LoadingDialog = ProgressDialog.show(AndroidRSSReader.this, "Laden...", "Even geduld aub...", true);
Seems you have problems in dismissing a dialog try using a Handler to perform an action on UI thread :
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// perform logic
if(LoadingDialog!=null)//first check if dialog is not null.This might be a reason for crashing
LoadingDialog.dismiss();
LoadingDialog=null
}
};
& then call it in your activity by simply calling handler.sendEmptyMessage(0);
&you are done.
Additional advice :also have a look at AsyncTask to perform async operation.
Related
Why i can't force Android ANR with this code?
No log messages or pop up. The application is just launched lazily.
[UPDATE]
I can't get it even sleeping a View.setOnClickListener or BroadcastReceiver.onReceive!
Is there a trick?
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
Log.e("Test", "", e);
}
}
}
I'm using Samsung GT-6200L with stock Android 3.2
Try it in onTouchEvent. In onCreate your activity is not fully running
#Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG,"onTouchEvent");
while(true) {}
}
The ANR-WatchDog project has a test app that produces ANRs in a reliable manner (as reliable as ANRs can be): the app hangs because of a deadlock.
The gist of it:
Prepare a lock object as a private field in your activity:
final Object mutex = new Object();
Have a thread that performs some work in a critical section, and an android.os.Handler that posts work depending on the same lock.
new Thread(new Runnable() {
#Override
public void run() {
synchronized (mutex) {
while (true) {
try {
Thread.sleep(60000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
synchronized (mutex) {
// Shouldn't happen
throw new IllegalStateException();
}
}
}, 1000);
Putting the above code snippet inside a button click handler, for example, should do the trick.
I've been facing the same issue yesterday, and I've found out that using a plain debug build ANR dialogs simply won't show up. (Although the UI thread was completely hanged.)
But after exporting and properly signing the application the dialogs were popped up properly (in every cases mentioned above). However I am still not sure what really prevents to pop up ANR messages, maybe someone else can clarify this later...
Try using:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int a=0;
while(true) {
a++;
}
}
Your code probably didn't work because it got setup too early, and the Activity probably wasn't fully initialized and created yet. With the above code, launch the activity and touch/swipe on the screen and wait for the ANR dialog to popup.
Make a button in your activity.
public void onBtn1(View v) {
int a = 0;
while(true) {
a++;
}
}
Make the button execute the above code.
Spam click the button with your finger =)
I used this code for force ANR
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void force(View view){
while(true) {}
}
I just created a simple button in the xml file and set android:onClick=force
I have a .lrc file and I need to go over every line with a CountDownTimer. I have tried using AsyncTask to do so but I get the error:
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
On line new CountDownTimer... I tried doing it with runnable but I still get the same error. My goal is to get it to go over every line in .lrc file which looks like this:
[00:04.15]Help me, it's like the walls are caving in
[00:10.46]Sometimes I feel like giving up
[00:13.63]But I just can't
...
I am not sure how efficient it is to do it the way I am trying to do. I am thinking of going through every line in the doInBackground(). If there is a better way to do it then let me know. But to begin with, why am I getting the EXCEPTION ?
Just to note.. I have simplified the code as much as I could so it would be easier to understand what I am trying to do.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyView myView = new
myView.play();
}
}
public class MyView{
public void play() {
new CustomAsync().execute();
}
}
class CustomAsync extends AsyncTask<Lyric, Void, Void> {
protected Void doInBackground(Lyric... param) {
startLyricCountDownTimer(param);
return null;
}
protected void onPostExecute(Void param) {
//Print Toast or open dialog
}
private void startLyricCountDownTimer(Lyric lyric){
new CountDownTimer(30000, 10) { //This is where it throws the error
public void onTick(long millisUntilFinished) {
//Do the thing
}
public void onFinish() {
}
}.start();
}
}
EDIT
Is it better to go with the AsyncTask and do like Son Truong suggested or to use the following code for each and every lrc line?
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
new CountDownTimer(millisInFuture,countDownInterval) {
#Override
public void onTick(
CountDownTimer uses a Handler to post messages to a Message Queue of a Thread which has a Looper. onTick and onFinish will be called on which thread based on where you create CountDownTimer instance.
In your case because you create CountDownTimer instance in doInBackground method of AsyncTask so these two methods will be call on AsyncTask thread.
In constructor of CountDownTimer, it will create Handler instance as well. The Handler will check whether or not current thread has a Looper, if not it will throw a RuntimeException with message.
Can't create handler inside thread that has not called
Looper.prepare()
Because AsyncTask uses a thread which has no Looper, that why your app crashes.
My suggestion is in doInBackground method you open a connection to .lrc file and read each line, for each line read, use runOnUIThread to send the line to UI thread (then you can process the line read there by display a Toast on screen, etc).
Update: I will demo how to read line by line from a file then display it on a text view each 3 seconds.
First write a class which read from an inputstream line by line
static class ReadLyricTask extends AsyncTask<InputStream, String, Void> {
WeakReference<MainActivity> mMainActivity;
ReadLyricTask(MainActivity activity) {
mMainActivity = new WeakReference<>(activity);
}
#Override
protected Void doInBackground(InputStream... inputStreams) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStreams[0]));
String line;
try {
while ((line = reader.readLine()) != null) {
publishProgress(line);
}
} catch (IOException e) {
// Do nothing.
} finally {
try {
inputStreams[0].close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
#Override
protected void onProgressUpdate(String... values) {
MainActivity activity = mMainActivity.get();
if (activity != null) {
activity.displayLyricLineOnTextView(values[0]);
}
}
}
Then just use it in MainActivity
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_LYRIC_TEXT_INTERVAL = 3000; // Change lyric text each 3 seconds.
private int mCurrentInterval = 0;
private TextView mLyricTextView;
private Handler mHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLyricTextView = findViewById(R.id.lyricText);
// I put a file named lyric.lrc in raw folder, for your case just open an input stream from a file.
InputStream inputStream = getResources().openRawResource(R.raw.lyric);
new ReadLyricTask(this).execute(inputStream);
}
private void displayLyricLineOnTextView(final String lyricLine) {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
mLyricTextView.setText(lyricLine);
}
}, mCurrentInterval);
mCurrentInterval += UPDATE_LYRIC_TEXT_INTERVAL;
}
}
CountDownTimer runs in separate thread and no need of asynctask to run a timer.Best solution would be create a service and make service to trigger a timer.
As timer run on non ui thread, while updating ui make sure you update from UI thread.You could use UI handler or runOnUithread method to update view.
I want my activity to show a screen for 3 seconds, then go back to previous screen. But when i use
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome_layout);
TextView tvResult = (TextView)findViewById(R.id.textView1)
Thread.sleep(3000);
Intent i = new Intent(this,myActivity.class);
startActivity(i);
But unfortunately, this does not work. This doesent show the activity waits 3 seconds and goes back. However, i want it to show its contents before going back. How can i do it ?
You should remove this Thread.sleep(3000); which block the ui thread. You should never block the ui thred. You can use a Handler postDelayed with a delay and then startActivtiy.
Handler handler = new Handler();
handler.postDelayed(new Runnable(){
#Override
public void run(){
// do something
}
}, 3000);
To go back to previous Activity you can call finish().
Also if you need to go back to the previous activity for 3 seconds why do you need
Intent i = new Intent(this,myActivity.class);
startActivity(i);
Calling finish() will do the job
This is not the recommended way to do this.
Using Thread.sleep you're blocking the main UI thread for 3000 milliseconds. This means that nothing in the activity will work until 3 seconds are passed.
Instead, you could do this:
edited: now it works well.
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.welcome_layout);
TextView tvResult = (TextView)findViewById(R.id.textView1)
new Thread(new Runnable()
{
#Override
public void run()
{
try
{
Thread.sleep(3000);
Intent i = new Intent(getApplicationContext(), myActivity.class);
startActivity(i);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
Can someone explain to me 2 things about the thread code that I finally made almost working the way it should. I want to do a periodic task in the background every x seconds and be able to stop and start it at will. I coded that based on the examples I found, but I'm not sure if I made it in the right way. For the purpose of debugging, the task is displaying a time with custom showTime().
public class LoopExampleActivity extends Activity {
TextView Napis, Napis2;
Button button1,button_start,button_stop;
Handler handler = new Handler();
Boolean tread1_running = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Napis = (TextView) findViewById(R.id.textView1);
Napis2 = (TextView) findViewById(R.id.textView2);
button1 = (Button) findViewById(R.id.button1);
button_stop = (Button) findViewById(R.id.button_stop);
button_start = (Button) findViewById(R.id.button_start);
button_stop.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
tread1_running = false;
}
});
button_start.setOnClickListener(new OnClickListener() {
#Override
public void onClick (View v) {
tread1_running = true;
}
});
thread.start();
}// endof onCreate
final Runnable r = new Runnable()
{
public void run()
{
handler.postDelayed(this, 1000);
showTime(Napis2);
}
};
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(tread1_running) {
sleep(1000);
handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
}
Now the questions are:
1)Will my thread quit forever if I stop it with the stop button?
2)Why can't I start it again with the start_button? If I add the tread.start() in a button, will it crash?
3) I tried a second version when I let the thread run and put a condition into the handler. The only way I can get it to work is to loop conditionaly in the handler by adding an
if (thread1_running) {
handler.postDelayed(this, 2000);
showTime(Napis2);
}
And changing the condition in a thread start to while (true) but then I have an open thread that is running all the time and I start and stop it in a handler, and it posts more and more handlers.
So, finally I get to the point it looks like that:
final Runnable r = new Runnable()
{
public void run()
{
if (thread1_running) handler.postDelayed(this, 1000);
showTime(Napis2);
}
};
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
if (thread1_running) handler.post(r);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Is the proper way to do that is to start and stop a whole thread? Or that is the best way?
The best way to achieve something like that would be, in my humble opinion, to postDelayed(Runnable, long).
You could do something like this. Class definition:
private Handler mMessageHandler = new Handler();
private Runnable mUpdaterRunnable = new Runnable() {
public void run() {
doStuff();
showTime(Napis2);
mMessageHandler.postDelayed(mUpdaterRunnable, 1000);
}
};
And control true run/stop like this:
To start:
mMessageHandler.postDelayed(mUpdaterRunnable, 1000);
And to stop:
mMessageHandler.removeCallbacks(mUpdaterRunnable);
It's much much simpler, in my humble opinion.
Threads a described by a state machine in java.
When a thread get outs of its run method, it enters in the stopped state and can't be restarted.
You should always stop a thread by getting it out of its run method as you do, it s the proper way to do it.
If you want to "restart the thread", start a new instance of your thread class.
You should better encapsulate your thread and its running field. It should be inside your thread class and the class should offer a public method to swich the boolean. No one cares about your datastructure, hide them. :)
You should consider using runOnUIThread for your runnable, its much easier to use than handlers.
My application has a ViewFlipper with 3 ViewGroups in it. Each ViewGroup interaction is dependent on data from a database. I'm using an AsyncTask to read from a database and return a Cursor when it's done. Before the AsyncTask is executed, I just want to display a single View in the ViewFlipper saying "Loading data, please wait.", is this possible somehow?
Show the progress dialog in your onPreExecute() and dismiss it in the onPostExecute(). Something like this,
private class MyAsyncTask extends AsyncTask<Integer, Integer, Integer[]> {
private ProgressDialog myWait = null;
// This is on the UI thread itself
protected void onPreExecute() {
myWait = new ProgressDialog(MainActivity.this);
myWait.setMessage("Loading data, please wait");
myWait.setCancelable(false);
myWait.show();
}
// Separate worker thread is used here
protected Integer[] doInBackground(Integer...params) {
//do the database loading
return <your result - goes to onPostExecute>;
}
// This is on the UI thread itself
protected void onPostExecute(Integer[] resultCell) {
if (myWait != null) {
myWait.dismiss();
}
}
}
yes you can make use of progressDialog. Do it like this,
progressDiaolg=ProgressDialog.show(Activity.this,"","Loading Images...");
final Thread t= new Thread(new Runnable() {
public void run() {
Log.i("Inside Thread", "Downloading Images...");
downloadImages();
handler.sendEmptyMessage(0);
}
});
t.start();
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
progressDiaolg.dismiss();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
};
I don't have idea with Asynctask. So try modifying this snippet accordingly.