I honestly can't figure it out - I've heard that thread.stop() is not a good thing to use. It also isn't working for me. How to get threads/handlers to stop running?
Threads should be terminated in a "polite" way. You should build in some mechanism for your thread to stop. You can have a volatile boolean parameter that is checked on every loop of your thread (assuming you have loops in there) like so:
while (!threadStop) {
// Do stuff
}
And then you can set the boolean value to false from another thread (make sure you handle all synchronization issues though) and your thread will stop in it's next iteration.
Ok the answer to stop threads have been done. To stop handler you have to use this following method :
removeCallbacksAndMessages from Handler class like this
myHandler.removeCallbacksAndMessages(null);
you can use it like this..
Thread mythread=new Thread();
if(!mythread){
Thread dummy=mythread;
mythread=null;
dummy.interrupt();
}
or
you can use
mythread.setDeamon(true);
The correct way of stopping a handler is:
handler.getLooper().quit();
I usually implement this by sending a quit message to handler which terminates itself.
The correct way of stopping a generic Thread is:
thread.interrupt();
The thread that is being stopped needs to handle the interrupt:
if(isInterrupted())
return;
This can be put in a loop if you wish:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
try {
while(!isInterrupted() && (line = br.readLine()) != null) {
// Do stuff with the line
}
}
catch(IOException e) {
// Handle IOException
}
catch(InterruptedException e) {
// Someone called interrupt on the thread
return;
}
Related
I am new to threading and i went through many post in stack overflow and find many solution for my problem but i am not sure which one is best for which condition.
First thing first, my problem is that i want to update one JSON file
when all threads are done with the bitmap generation at a specific path so
that i can get that all those image and update JSON file. So in
simple word my i want to run some code when all thread are done with it
execution and major requirement is that i don't want my main to be blocked because of this.
What i have found out
thread. join
excutorServive
android-priority-jobQueue (link)
Mutex in threadpool ( also let me know if any other is there)
I am confused which one is the best way to tackle my problem. if any
android expert out there can summarise that for following the two
scenerio what is the best available in android.
wait till when all thread completes
don't wait and get informed when all completes
You can have counter for your threads, after each thread is complete check how many have already completed, if not all completed, increment the number of completed threads and the last thread to complete will then run the piece of code.
You can do it like this.
In your thread:
private Runnable runnableThread= new Runnable() {
#Override
public void run() {
try {
if (lastThreadDone){
handler.sendEmptyMessage("SUCCESS");
}
}
catch (Exception ex) {
throws ex;
}
}
};
lastThreadDone is boolean which will become true if the process is done, this is base on how you implement it.
then in you handler:
#SuppressLint("HandlerLeak")
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
try {
switch (msg.what) {
case "SUCCESS": {
// your code here
break;
}
case "FAIL":
break;
default:
break;
}
}
catch (Exception ex) {
throw ex;
}
super.handleMessage(msg);
}
};
I would use a completion service and then poll until all tasks are finished. When they are done, the json file gets updated. The problem is that you need to do this async or you risk to block the ui. Therefore I would encapsulate the work with the completion service inside an intent service. If you need to update the ui you then can post local broadcasts from the intent service.
Furthermore for you cases
wait till when all thread completes
only do this when you are already on a background thread like intent service or async task
don't wait and get informed when all completes
implies the case above. Do the work async and notify the ui or some listening component with broadcasts, content observers, handlers or the 'onPostExecute' if you are using async task.
I have a problem with a looper. I call looper.prepare(), and after doing something it all works fine. But if I rotate the device I get an exception on the prepare.
07-12 16:40:09.760: E/activity(15809): java.lang.RuntimeException: Only one Looper may be created per thread
I'm trying to quit the looper, but it doesn't do anything.
Here is my AsyncTask:
#Override
protected String doInBackground(String... args) {
try{Looper.prepare(); //here start the exception
try {
URL url = new URL(link);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
utente.measure(0, 0);
bmImg = decodeSampledBitmapFromResource(is,(int) utente.getMeasuredWidth(), utente.getMeasuredHeight(), link);
if(bmImg!=null){
try{
getCroppedBitmap();
}catch(Exception e){
System.out.println(e);
}
}
}
catch (IOException e)
{
Log.e("lele", "errore qui");
e.printStackTrace();
}
Looper.myLooper().quit(); //do nothings
}catch(Exception e){
Log.e("canta tu", " "+e);
}
Looper.myLooper().quit(); //do nothings
return null;
}
#Override
protected void onPostExecute(String args) {
//Looper.myLooper().quit(); //generathed an error, main thread can't stop looper
if(bmImg!=null){
try{
utente.setImageBitmap(bmImg);
ellisse.setVisibility(View.VISIBLE);
}catch(Exception e){
Log.e("lele",""+e);
Log.e("lele","errore probabile out of bound");
}
}
else {
Toast.makeText(getApplicationContext(), "Modifica la foto da \"profilo\"", Toast.LENGTH_LONG).show();
}
Ideas?
There are two cases to consider:
(1) looper threads you want to live the entire life of the app, and do not hold strong reference to a view (even not implicitly)
Quoting Google engineer, Christopher Tate - you can just leave the looper there until your app is destroyed, and it will go down with it. You don't need to worry about it.
"Speaking very generally, never quit() your looper threads. That method exists mostly for historical and testing reasons. In Real Lifeā¢, I recommend that you continue to reuse the same looper thread(s) for the life of the process rather than creating/quitting them."
I use such a looper thread as a multi purpose HandlerThread, and send Runnables to it whenever I want something to run outside the main thread (UI).
(2) looper threads that have reference to a view
This one falls out of the recommendation of Christopher Tate, because it will cause memory leak, for example if you rotate the screen.
(You better make the handler thread static and use weak reference - and you'll be back with option #1)
To kill it you must quit the loop. To do that, you need to run the quit command on the context of that thread.
So create a message with some whatever int as your msg.what, and in your handleMessage wait for this int, and when it arrives - call:
Looper myLooper = Looper.myLooper();
if (myLooper!=null) {
myLooper.quit();
}
And don't forget to null all reference to views and activities.
Send this kill message to the handler from your activity onDestroy()
Looper.prepare() associates a Looper-instance with the thread that it is called on, but Looper.quit() does not remove this association (it merely stops the message dispatch mechanism). So, when you get a second call to Looper.prepare a RuntimeException is thrown.
The general recommendation is to not associate Looper-instances with AsyncTask-threads. The Looper is intended for passing messages between threads, but this is already handled internally in the AsyncTask, so that data can be sent between onPreExecute (UI thread) -> doInBackground (Worker thread) -> onPostExecute (UI thread).
I need to destroy a thread before application suspend. This is my code:
public class MyThread extends Thread
{
public boolean mRun = false;;
#Override
public void run()
{
while (mRun)
{
.....
}
}
}
Activity:
#Override
public void onPause() {
if (mThread != null)
{
mThread.mRun = false;
try { mThread.join(); }
catch (InterruptedException e) { }
}
super.onPause();
}
But i'm pretty sure that the android system do not wait my thread conclusion and pause my application before it. How can i force thread conclusion?
This is the way, I used in my code meet your requirement.Hope, this will be helping you too. If you find a better solution, Please share it.
In the below snippet, mThread is thread got created in onCreate. OnDestroy is a method that would be called before your activity destroyed.Its a best place to empty the allocated resources.
#Override
public void onDestroy() {
super.onDestroy();
if(null != mThread) {
Thread dummyThread = mThread;
mThread = null;
dummyThread.interrupt(); // Post an interrupt request to this thread.
}
}
Cheers !
Are you sure that you are not getting an InterruptedException?
Try putting a stacktrace in the catch sentence...and also check if your thread isAlive().
You cannot do that. Thread.join is a blocking potentially long operation that must not be done on the UI Thread (onPause being on the UI Thread).
You can ask your thread to stop, (setting mRun to false is a commonly accepted way of doing so), but you cannot exclicitely wait on it.
To be sure , mark the thread as daemon, always check a flag if doing a repetitive task in a thread, like in a loop. Also, call interrupt, which will take care of blocking IO or network calls.
myThread.setDaemon(true)
and
cancelFlag = true;
myThread.interrupt();
BufferedReader hl = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.lines)));
while(hl.ready()){
showLines.append(hl.readLine()+"\n");
showLines.invalidate();
Thread.sleep(10);
}
That is my code but it is not redrawing when I tell it to. It is supposed to redraw after every line that is added to textview, but it still only redraws at the end? Can someone please help me, I can't figure it out.
That is bacause your invalidate() is in a thread while loop and is being acummulated, so to speak, until the loop ends, and only than it draws...
I had the same problem when using Thread.sleep() within a loop. You can use a post delayed method to draw each line, which in this case is one line per second:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
BufferedReader hl = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.text)));
TextView showLines = (TextView) findViewById(R.id.textView1);
appendLines(hl, showLines);
}
public void appendLines(final BufferedReader br, final TextView tv){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try {
if(br.ready()){
try {
tv.append(br.readLine()+"\n");
} catch (IOException e) {
e.printStackTrace();
}
tv.invalidate();
appendLines(br, tv);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, 1000);
}
That is my code but it is not redrawing when I tell it to.
invalidate() does not happen immediately when you call it. invalidate(), like append() and anything else involving the UI, puts a message on a message queue, that will be processed by the main application thread as soon as you let it. Since you are wasting the user's time in pointless sleep() calls, plus doing flash I/O, in a loop on the main application thread, the main application thread cannot process the messages on the message queue. It will process all of your invalidate() and append() calls after your loop is over and you return control to Android from whatever callback you are in.
It is supposed to redraw after every line that is added to textview
No, it isn't.
but it still only redraws at the end?
Correct.
The simple solution is for you to get rid of the invalidate() and the Thread.sleep(10) and just load the entire file contents into your TextView in one call.
The better solution is for you to read the whole file in via an AsyncTask, then append the text to the TextView in one call in onPostExecute(). If needed, use a ProgressDialog or something to keep the user entertained while this is going on.
I am trying to use a Handler to have some code execute in some amount of time.
This works well in 2 of my classes, but I'm running on an issue with this one:
One of my class extends Activity, and starts a Thread (that implements Runnable).
In my run() method, I have, as in my other classes:
mHandler = new Handler();
mHandler.removeCallbacks(StopRequest);
mHandler.postDelayed(StopRequest, 30000);
The program seems to complain:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
I don't understand why it is posting, could someone please help me?
EDIT: Adding parts of my code:
out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream())), true);
out.println("VOICE_CALL_REQUEST");
// Wait for a response
// Set a timer (about 30 seconds)
mHandler = new Handler();
mHandler.removeCallbacks(StopRequest);
mHandler.postDelayed(StopRequest, 3000);
// Ready reply
InputStream stream = clientSocket.getInputStream();
BufferedReader data = new BufferedReader(new InputStreamReader(stream));
String line = data.readLine();
mHandler.removeCallbacks(StopRequest); // Timer is removed here
And if the timer hits 30 seconds:
// Stop a call request after some amount of time
private Runnable StopRequest = new Runnable() {
public void run() {
// Send a message to cancel the voice call
out.println("VOICE_CALL_CANCEL");
// Close the port
try {
clientSocket.close();
}
catch (IOException e) { finish(); }
}
};
Thanks a lot,
Jary
You can't create a handler in a worker thread (unless it has a looper, which you normally never do). The handler needs a looper, since it needs a point that evaluates all incoming messages and calls the handler when necessary.
Your handler needs to be in the UI thread. If you want to do something in a worker thread, you need to do your own message handling (you could use synchronized methods in your thread that set member variables which the worker thread checks), or, if your thread is more of the event-driven variety, you could really consider adding a looper - but again, that is not a common practice.
I found a solution. Defining the handler in the onCreate method fixes it. Rest of the code is identical. Thanks :)