that code will help me explain my problem:
public class TestHandlerActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Thread(){
public void run(){
for (int i=0;i<20;i++){
handler.post(run);
}
}
}.start();
}
Handler handler=new Handler(){
};
Runnable run = new Runnable(){
public void run(){
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d("TAG", "Message processed");
}
};
}
That way the new thread makes the petitions which are served by the handler in the main thread.
What i need to do is exactly the opposite. The UI thread launches petitions wich are served sequentially by another thread (the order is important), and the UI thread don't need to be notified when each petition end.
Some points are important for this: The petitions have 3 parameters (int, int, boolean), they make changes in the database and are generated by the interaction of the user with the UI, so they aren't launched simultaneously
Thanks in advance
One option is to use this for making your thread: http://developer.android.com/reference/android/os/HandlerThread.html
This will create a thread with its own message queue and loop. You can create a Handler to run work on the thread like so:
HandlerThread handlerThread = new HandlerThread("My Handler");
handlerThread.start();
Handle myHandler = new Handler(handlerThread.getLooper());
This does require that all work done by thread be done so by sending messages and scheduling Runnables on it through Handlers.
Related
I am trying to run a CountDownTimer inside a Thread, but it just won't work..
So in the MainActivitys onCreate I start it on Button click like that:
public void onClick(final View v) {
Log.d("Main", "onClick");
runOnUiThread(runner);
}
runner is an Instance of a class which implements Runnable:
private CountDownLatch doneSignal = new CountDownLatch(1);
#Override
public void run() {
Log.d("WR", "run");
this.countDown(20);
Log.d("WR", "waiting");
try {
doneSignal.await();
} catch (final InterruptedException ex) {
Log.e("WR", ex.getMessage(), ex);
}
Log.d("WR", "waited");
}
private void countDown(int time) {
final CountDownTimer timer = new CountDownTimer(time * 1000, 1000) {
#Override
public void onTick(final long millisUntilFinished) {
Log.d("WR", "onTick");
}
#Override
public void onFinish() {
Log.d("WR", "onFinish");
doneSignal.countDown();
}
};
Log.d("WR", "starting");
timer.start();
Log.d("WR", "started");
}
With this code, the application just freezes after Logging onClick, run and starting.
Changing runOnUiThread(runner) to new Thread(runner).start(); makes the application crash immediately after Logging onClick with no more output.
Some research said that the CountDownTimer needs to be run on UI-Thread due to the use of a Handler. But it just freezes.
When I remove the entire Thread stuff and just call runner.run(); in the Buttons onClick (also removing the implements Runnable in the runner Instance) I get following Log entries: onCLick, run, starting, started, waiting. But then nothing happens, as if the timer does not run, no call of the onTick method.
How can I fix my CountDownTimer?
CountDownTimer runs on The Ui Thread, and it has to run on the UI Thread, because internally it uses an Handler, which in turns neead a Looper. runOnUiThread(runner); whatever runner does, runs on the UI Thread.
private CountDownLatch doneSignal = new CountDownLatch(1);
calling await() on the UI Thread will block it, and since the countDown() runs on the same thread you practically dead-locked your app
I have the following below code.
//This is global for the activity.
Handler handler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
//update the UI
}
};
In my onResume() I am starting a new thread that runs a runnable.
protected void onResume()
{
super.onResume();
Thread t = new Thread(runnable);
t.start();
}
My runnable is as follows :
Runnable runnable = new Runnable()
{
public void run()
{
// some networking stuff
// some db stuff
// whatever
handler.sendEmptyMessage(0);
handler.postDelayed(new Runnable()
{
public void run()
{
new Thread(runnable).start();
}
}, 30000);
}
}
And I have this inside onPause() :
protected void onPause()
{
super.onPause();
handler.removeCallbacks(runnable);
}
At the end I call the handler.sendEmptyMessage(0); so that the handleMessage(Message msg) gets called and I do the UI changes, and I repeat the task but starting a new runnable, which starts a new thread that runs the same runnable as this.
Clarification questions :
I am starting a new Thread inside my onResume(), which means that the runnable is not running on the UI Thread, however, the handler is being created on the UI thread and is naturally attached to the UI thread. How is the UI is being changed flawlessly ?
It is supposed for handler.removeCallbacks(runnable), however, whenever I minized the app, the runnable still keeps on running every 30 seconds. (this might be because it is on a new thread, that is not associated with the Handler created). How can I make it stop ?
public class MainActivity extends Activity {
public static final int UPDATE = 1;
public static final int WORK = 2;
private Handler uiHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case UPDATE:
// Perform UI updates here
....
// UI Updates done, schedule WORK in 30 seconds:
this.sendMessageDelayed(this.obtainMessage(WORK), 30000);
break;
case WORK:
new Thread(doWork).start();
break;
default:
super.handleMessage(msg);
}
}
};
private WeakReference<Handler> handlerRef = new WeakReference<Handler>( uiHandler );
private Runnable doWork = new Runnable() {
#Override
public void run() {
// This will run on a different thread.
// If UI is still around, tell it to update
Handler ui = handlerRef.get();
if( ui != null )
ui.sendEmptyMessage(MainActivity.UPDATE);
}
};
#Override
protected void onPause() {
uiHandler.removeMessages(WORK);
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
// Resume UI updates in 500ms, allowing UI to settle
uiHandler.sendMessageDelayed(uiHandler.obtainMessage(WORK), 500);
}
....
}
This pattern uses a single Handler on the UI thread. Background work is done in the Runnable, which the ui Handler will post to a new Thread, so avoiding NetworkOnMainThreadException and -- more importantly -- unresponsive UI. Further, a new update is scheduled thirty seconds after the background process has completed, to avoid taxing the system with long-running updates. The background thread uses a WeakReference to the ui Handler, so if the Activity is killed while the thread is working, it won't send UI updates to it.
I'm really stuck here, I've read a lot on threading on android but I'm unable to find an answer that suits my proyect.
I've got a frontend (Manages GUI) and a backend (Manages the data and stuff). I need to update the GUI as soon as the backend finishes running a thread but I can't figure out how!
Main.java package frontend
public class Main extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Thread thread = new Thread() {
#Override
public void run() {
Server server = new Server(getApplicationContext());
}
};
thread.start();
Server.java package backend
public static List<String> lista = new ArrayList<String>();
public Server(Context context) {
Revisar archivo = New Revisar();
archivo.DoSomething();
}
After archivo.doSomething finishes I need to update the GUI with the backend data stored in the static list.
Any suggestions?
As you've surmised, you can't update the GUI from a background thread.
Typically, to do what you want, you use the message handling mechanism to pass a message to the GUI thread. Typically, you pass a Runnable which will be executed in the GUI thread. You can also pass a Message if you've subclassed the Handler and added code to deal with messages.
Messages are passed to Handlers. You can either create your own Handler in the GUI thread, or use one of several that already exist. For example, every View object includes a Handler.
Or you can simply use the runOnUiThread() Activity method.
Pattern 1, handler plus runnables:
// Main thread
private Handler handler = new Handler();
...
// Some other thread
handler.post(new Runnable() {
public void run() {
Log.d(TAG, "this is being run in the main thread");
}
});
Pattern 2, handler plus messages:
// Main thread
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
Log.d(TAG, "dealing with message: " + msg.what);
}
};
...
// Some other thread
Message msg = handler.obtainMessage(what);
handler.sendMessage(msg);
Pattern 3, call runOnUiThread():
// Some other thread
runOnUiThread(new Runnable() { // Only available in Activity
public void run() {
// perform action in ui thread
}
});
Pattern 4, pass a Runnable to a View's built-in Handler:
// Some other thread
myView.post(new Runnable() {
public void run() {
// perform action in ui thread, presumably involving this view
}
});
Private static ProgressDialog loading;
public void downloadData(){
Thread t = new Thread(){
public void run(){
//download stuff
}
handler.sendEmptyMessage(0);
};
t.start();
try{
t.join();
}catch(InterruptedException ignore){}
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
loading.dismiss();
}
};
When I call donloadData without using t.join() it displays the ProgressDialog.
However, when using t.join(), the t thread seems to execute correctly but the ProgressDialog does not show.
Why is the ProgressDialog not showing?
Any suggestions on what to change so that I can use t.join() and display the ProgressDialog?
the t.join method will block current thread util the t thread finish it's work.
try this:
Private static ProgressDialog loading;
public void downloadData(){
Thread t = new Thread(){
public void run(){
//download stuff
//edit: when finish down load and send dismiss message
handler.sendEmptyMessage(0);
}
//handler.sendEmptyMessage(0);
};
//edit: before start make the dialog show
loading.show();
t.start();
//edit: the join method is not necessary
try{
t.join();
}catch(InterruptedException ignore){}
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
loading.dismiss();
}
};
above code may be solve your problem.
join() is a call o'death. If a thread blocks or gets stuck, calling join() on it ensures that the stuckness is efficiently extended to the calling thread.
If you can possibly get away with it, don't use join() at all. Especially don't use it to wait for results from another thread by calling it straight after start(). Double-especially don't use it in a GUI event-handler.
I have a thread in java/Android like this:
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
update_i();
}
};
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
Thread myThread = new Thread(new Runnable() {
public void run() {
while (true) {
try {
handler.sendMessage(handler.obtainMessage());
Thread.sleep(timer);
} catch (Throwable t) {
}
}
}
});
myThread.start();
}
The thread works fine when I run my application. But I want to start/restart the thread with a button.
Button.OnClickListener StartButtonOnClickListener = new Button.OnClickListener() {
#Override
public void onClick(View v) {
//start/restart the thread
}
};
If I copy the thread into the button I just make a new thread every time the user clicks on the button. I want to run the thread when the user first time click on the button, "kill it" and start from the beginning if the user click on the button a second time (I don’t want to start a second thread).
I think that Colin is wright you can´t just restart you need to make a new instance, and the interrupt function will stop the running thread if it is still running.
I recommend you make an inner class, instand of an inline implementation, it will make it easier to understand.
if(myThread.isAlive()){
myThread.interrupt();
}
myThread = new MyThread();
myThread.start();
hope this helps
You can't restart a Thread.
From the documentation :
Throws IllegalThreadStateException
if the Thread has been started before
You can kill the previous thread, but in the end you will have to create a second instance of your thread.
Resources :
Javadoc Android - Thread.start()