I'm trying to write code to pull a server every second for updated messages. The messages then get displayed in a text view. If I do not change the text in the text view it runs fine. It will crash if I try to change the textview on the thread. IF i change it not on the thread works fine.
I'm assuming the thread cannot access the main threads memory? How can I set the text in the view with the text just loaded over the internet?
In the code below I have a thread that does a endless loop with a sleep. It calls a method called SendMessage. Send Message loads in text over the internet and at the end tries to update the View with it. It causes a exception when this happens.
code:
public class cChat extends cBase implements OnClickListener {
/** Called when the activity is first created. */
TextView mUsers;
TextView mComments;
int i=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat);
mUsers=( TextView) findViewById(R.id.viewusers);;
mComments=( TextView) findViewById(R.id.viewchats);;
Thread thread = new Thread()
{
#Override
public void run() {
try {
int t=0;
while(true)
{
SendMessage();
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
public void onClick(View v) {
} // end function
// send a uypdate message to chat server
// return reply in string
void SendMessage()
{
try {
URL url = new URL("http://50.63.66.138:1044/update");
System.out.println("make connection");
URLConnection conn = url.openConnection();
// set timeouts to 5 seconds
conn.setConnectTimeout(1000*5);
conn.setReadTimeout(5*1000);
conn.setDoOutput(true);
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// String line;
String strUsers=new String("");
String strComments=new String("");
String line=new String();
int state=0;
while ((line= rd.readLine() ) != null) {
switch(state){
case 0:
if ( line.contains("START USER"))
state=1;
if ( line.contains("START COMMENTS"))
state=2;
break;
case 1:
if ( line.contains("END USER"))
state=0;
else
{
strUsers+=line;
strUsers+="\n";
}
break;
case 2:
if ( line.contains("END COMMENTS"))
state=0;
else {
strComments+=line;
strComments+="\n";
}
break;
} // end switch
} // end loop
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
} catch (Exception e) {
i++; // use this to see if it goes here in debugger
// System.out.println("exception");
// System.out.println(e.getMessage());
}
} // end methed
}
use runOnUiThread as
YOUR_CURRENT_ACTIVITY.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// the next line will cause a exception
mUsers.setText(strUsers);
mComments.setText(strComments);
//....YOUR UI ELEMENTS
}
});
EDIT :
see doc runOnUiThread
You can use a handler to post tasks (Runnables) to the UI/Main Thread:
private Handler handler = new Handler();
//...
Thread thread = new Thread()
{
#Override
public void run() {
try {
int t=0;
while(true)
{
handler.post(new Runnable() {
#Override
public void run() {
SendMessage();
}
});
sleep(1000*5);
t++;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
You can't touch an UI widget from a thread different than the one used to create it (the UI thread). But if you have a reference to the Activity, you can simply do:
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
mUsers.setText(strUsers);
mComments.setText(strComments);
}
});
which would require strUsers to be accessible by the anonymous class. For that you can simply do:
final String finalUseres = strUsers;
and use finalUsers within run().
Try using a Service to continuously pull/send data to server. This will reduce the load on your UI-Thread.
the Andoid UI toolkit is not thread-safe. So, you
must not manipulate your UI from a worker thread
To fix this problem, Android offers several ways to access the UI thread from other threads. Here is a list of methods that can help:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
you can also use AsyncTask.
see this tutorial on process and threads in android.
Related
Hi currently i have the following code which utilizes Asycn Task and Timer.
My async task is basically trying to send a HTTP GET method from a URL where the response from the server could varies depending on connection and load.
What i would like to do is to have a timed async task. Where, it will schedule an AsyncTask every X second BUT if there is currently an Async Task in progress i would have to kill it first. Then start a new one.
Here is the code that i have at the moment:
private static boolean running = false;
Timer myTimer;
protected void onCreate(Bundle savedInstanceState) {
/* REST OF CODE OMITTED */
MyTimerTask myTask = new MyTimerTask();
myTimer = new Timer();
myTimer.schedule(myTask, 0, 10000);
}
/* REST OF CODE OMITTED */
private class MyTimerTask extends TimerTask {
public void run() {
if(!running){
Log.i("TAG", "NEW TIMER STARTED.");
RetrieveChatMessage task = new RetrieveChatMessage();
task.execute();
running = true;
}else{
running = false;
}
}
}
private class RetrieveChatMessage extends AsyncTask<String, Void, ArrayList<Chat>> {
#Override
protected ArrayList<Chat> doInBackground(String... params) {
// TODO Auto-generated method stub
ArrayList<Chat> cList = null;
String jResult = null;
Log.i("TAG", "RETRIEVING CHAT MESSAGE");
try {
jResult = ((new HttpRetriever())).getChatList(mAccount.email, mAccount.passwd);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
if(jResult != null){
Log.i("TAG", "JSON DATA: " + jResult);
cList = (new ChatHandlers()).getChatList(jResult);
}else{
cList = null;
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("TAG", "JSON Exception " + e.toString());
}
return cList;
}
#Override
protected void onPostExecute(final ArrayList<Chat> result) {
Log.i("TAG", "ON POST EXECUTE");
if(result != null){
// Do something here
}
}
}
To be honest the code above works with slight issues:
1. It seems to execute the Async randomly, instead of every 10 seconds.
2. When i go to another activity, somewhat it prevents other Async task from doing its job (Which is also trying to retrieve JSON response from server).
I am not too worried about the later problem (and that is not the question i am asking). I just would like to know how to have a proper timed Async Task. Can anyone point me to a direction.
Thank you.
EDIT #1:
after reading #thepoosh comment's i tried the following (i put it in onCreate):
scheduleTaskExecutor= Executors.newScheduledThreadPool(5);
scheduleTaskExecutor.scheduleAtFixedRate(new Runnable() {
public void run() {
// Parsing RSS feed:
// myFeedParser.doSomething();
Log.w("THUMBQOO", "NEW TASK STARTED");
retrieveChat();
}
}, 0, 15, TimeUnit.SECONDS);
Result: i have a consistent execution of Task. However, it seems that retrieveChat(); is never be called after the first execution.
Actually AsyncTask is not used for long operations .Check Here
You should use a Thread that uses a interface to notify UI or you can simply use a Handler which is the most Preffered way in android. Simply you can do a task repeatedly for every 10 seconds by
handler.postDelayed(new Runnable() {
#Override
public void run() {
// do work
handler.postDelayed(10000);
}
}, 10000);
Declare a Handler object to maintain future task executor...
private Handler mTimerHandler = new Handler();
Write a thread which will execute your future task...
private Runnable mTimerExecutor = new Runnable() {
#Override
public void run() {
//write your code what you want to do after the specified time elapsed
if(!running){
RetrieveChatMessage task = new RetrieveChatMessage();
task.execute();
running = true;
}else{
running = false;
}
}
};
Call your future tast executor with time using hanlder...
mTimerHandler.postDelayed(mTimerExecutor, 10000);
You can cancle your future task executor any time by this...
mTimerHandler.removeCallbacks(mTimerExecutor);
I am not sure if this is a very good way of accomplishing this (my answer here below) :
Use a Handler, create a HandlerThread and keep posting messages to this handler.
For the handlers "handleMessage" method, you can do your task and again send a message back to the MessageQueue.
HandlerThread thread = new HandlerThread(<name>);
thread.start();
Looper looper = thread.getLooper();
CustomHandler handler = new CustomHandler(looper);
// The CustomHandler class
class CustomHandler extends Handler {
public CustomHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
//Do your operation here
handler.sendEmptyMessageDelayed(msg, <delayTime>);
}
}
This is a common question, and I have read up on the various ways of handling it, but each on seems to fall short for what I am trying to do, which is essentially be a good OO-Citizen.
I have an Activity that invokes a CommunicationManager, which basically polls a TCP socket for data. When the CommunicationManager receives data, it throws a custom event (containing the string it just fetched), which is handled by the Activity. I am doing this, A) because other classes will depend on that data, not just the Activity, and B) because the polling is asynchronous, and should fire an event when it receives results.
My problem lies in that I need to surface those results into a TextView on the UI. I have the polling mechanism all set up, it fires every 1000ms, and invokes the event handler on the Activity. However, the UI never updates.
Assumedly this is a thread issue and the UI thread is not the one getting the change to the TextView, but how do I do this?? I have tried using a Handler, but am not sure where to put it, and when I did get it compiling it never updated the UI.
This seems relatively trivial if everything was done within the Activity, but adding in this other class (CommunicationManager) and the event is making it very confusing for me.
Here is what I have so far:
ACTIVITY (polling is invoked by clicking a button on the UI):
public void onClick(View v) {
if (v.getId() == R.id.testUDPBtn) {
statusText.setText("");
commMgr = new CommunicationManager();
commMgr.addEventListener(this);
MediaPositionPollThread poller = new MediaPositionPollThread(commMgr);
poller.startPolling();
}
}
#Override
public void handleMediaPositionFoundEvent(MediaPositionFoundEvent e) {
statusText.append(e.userData);
}
THREAD:
class MediaPositionPollThread extends Thread {
private CommunicationManager commManager;
private static final String TAG = "MediaPositionPollThread";
private boolean isPolling = false;
public MediaPositionPollThread(CommunicationManager cm) {
commManager = cm;
}
public void startPolling() {
isPolling = true;
this.run();
}
public void stopPolling() {
isPolling = false;
}
#Override
public void run() {
while (isPolling) {
try {
commManager.getCurrentMediaPosition();
Thread.sleep(1000);
}
catch (InterruptedException e) {
Log.d(TAG, "EXCEPTION: " + e.getMessage());
}
}
}
}
COMMUNUCATION MANAGER:
public void getCurrentMediaPosition() {
PrintWriter outStream;
BufferedReader inStream;
String resultString = "";
try {
outStream = new PrintWriter(tcpSocket.getOutputStream(), true);
outStream.println("GET?current_pts");
inStream = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
resultString = inStream.readLine();
fireEventWithData(resultString);
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void addEventListener(MediaPositionFoundEventListener listener) {
_listeners.add(listener);
}
public synchronized void removeEventListener(MediaPositionFoundEventListener listener) {
_listeners.remove(listener);
}
private synchronized void fireEventWithData(String outputString) {
MediaPositionFoundEvent evt = new MediaPositionFoundEvent(this);
evt.userData = outputString;
Iterator<MediaPositionFoundEventListener> i = _listeners.iterator();
while(i.hasNext()) {
((MediaPositionFoundEventListener) i.next()).handleMediaPositionFoundEvent(evt);
}
}
So I have the Activity making a thread that gets executed every second, calling CommunicationManager >> getCurrentMediaPosition, which in turn fires the MediaPositionFoundEvent, which is handled by the Activity and updates the TextView (statusText) on the screen.
Everything works except the screen not updating. I have tried runOnUiThread, and a Handler, but am obviously not getting it right.
Thanks in advance for any insight or solutions!
In your Activity class, add a private Handler _handler,
Initialize it in your onCreate Activity method,
and change your handleMediaPositionFoundEvent method to
#Override public void handleMediaPositionFoundEvent(MediaPositionFoundEvent e) {
_handler.post(new Runnable(){
public void run(){
statusText.append(e.userData);
});
}
}
It looks like your blocking the UI thread with your custom Thread. Please update this method to call start() vs run().
public void startPolling() {
isPolling = true;
this.start();
}
I have Singleton class which holds all the data (visitors of some site) and the data is updated by a service. I have an interface, which is implemented by an (list) activity (which shows visitors), so now as I get the data updated, I simply call the interface method so that the list activity can refresh it.
Now I need to maintain the time visitors are on site (at client end). I want to make a thread in Singleton class which will run a loop after every second, but I am not able to call any method on Main thread, using Handlers.
Here's the code of thread:
void startHeavyDutyStuff() {
Thread t = new Thread() {
public void run() {
try {
while(true) {
sleep(1000);
ArrayList<VisitorMC> data = SharedAppManager.appManager().visitorsData;
boolean doReload = false;
for (VisitorMC item: data) {
item.secsOnSite++;
if(item.secsOnSite == 60) {
item.secsOnSite = 0;
item.minsOnSite++;
doReload = true;
}
}
if(doReload) {
messageHandler.sendEmptyMessage(1);
} else {
messageHandler.sendEmptyMessage(0);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
t.start();
}
And here's the code where I am making the Handler on Main Thread (in Singleton class):
private SharedAppManager() {
//Initialization of the data.
Looper.prepare();
messageHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case 0:
Log.d("THREAD", "after every second");
break;
case 1:
if(visitorsDelegate != null) {
visitorsDelegate.updateVisitorsTime();
}
break;
default:
}
}
};
startHeavyDutyStuff();
}
What am I doing wrong here?
Edit:
I need to update the UI after each second, that's why I am running a separate thread which could change the Data and call update on UI.
I have a very simple UI and i need to constantly run a check process, so I am trying to use a Thread with a while loop.
When I run the loop with nothing but a Thread.sleep(1000) command, it works fine, but as soon as I put in a display.setText(), the program runs for a second on the emulator then quits. I cannot even see the error message since it exits so fast.
I then took the display.setText() command outside the thread and just put it directly inside onCreate, and it works fine (so there is no problem with the actual command).
here is my code, and help will be greatly appreciated.
Thank you!
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
on=(Button) findViewById(R.id.bon);
off=(Button) findViewById(R.id.boff);
display=(TextView) findViewById(R.id.tvdisplay);
display2=(TextView) findViewById(R.id.tvdisplay2);
display3=(TextView) findViewById(R.id.tvdisplay3);
stopper=(Button) findViewById(R.id.stops);
stopper.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(boo=true)
{
boo=false;
display3.setText("System Off");
}
else{
boo=true;
}
}
});
Thread x = new Thread() {
public void run() {
while (boo) {
display3.setText("System On");
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
display3.setText("System On");
display3.setText("System On");
x.start();
}
You can't update the UI from a non-UI thread. Use a Handler. Something like this could work:
// inside onCreate:
final Handler handler = new Handler();
final Runnable updater = new Runnable() {
public void run() {
display3.setText("System On");
}
};
Thread x = new Thread() {
public void run() {
while (boo) {
handler.invokeLater(updater);
try {
// do something here
//display3.setText("System On");
Log.d(TAG, "local Thread sleeping");
Thread.sleep(1000);
} catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
};
You could also avoid a Handler for this simple case and just use
while (boo) {
runOnUiThread(updater);
// ...
Alternatively, you could use an AsyncTask instead of your own Thread class and override the onProgressUpdate method.
Not 100% certain, but I think it is a case of not being able to modify UI controls from a thread that did not create them?
When you are not in your UI thread, instead of display3.setText("test") use:
display3.post(new Runnable() {
public void run() {
display3.setText("test");
{
});
You should encapsulate this code in an AsyncTask instead. Like so:
private class MyTask extends AsyncTask<Void, Void, Void> {
private Activity activity;
MyTask(Activity activity){
this.activity = activity;
}
protected Long doInBackground() {
while (true){
activity.runOnUiThread(new Runnable(){
public void run(){
display3.setText("System On");
}
});
try{
Thread.sleep(1000);
}catch (InterruptedException e) {
Log.e(TAG, "local Thread error", e);
}
}
}
Then just launch the task from your onCreate method.
In non-UI thread,you can't update UI.In new Thread,you can use some methods to notice to update UI.
use Handler
use AsyncTask
use LocalBroadcast
if the process is the observer pattern,can use RxJava
Can wait/notify be used within one thread?
I'm mean I have a listener and in the moment when that listener gets called I wanna enable a thread to do his work.How could I do that?
UPDATE:My data is written in a database...and is written each time the listener is called.Now the thread that I've created reads that data and sends it somewhere....
Next...I get some other data and do the same thing....The other thread needs to know what was the last data he read it so he can start reading from where he left....
Take a look in here:
using wait and notify within one thread
This is how my problem looks like.Thx
I have the following:
synchronized (syncToken)
{
try {
syncToken.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("MyThread: " + s);
in MyThread....so when I do
MyThread t = new MyThread(syncToken);
t.start();
I put my thread on waiting...yes?
And when I do this:
syncToken.notify();
I get my thread back on track....but the execution of the next line is the one after wait()?
I mean this: System.out.println("MyThread: " + s); ????
When u notify a thred does he continues his execution with the line after wait()???Thx
The following is a simple example of concurrency between two different threads. In the example the main thread start a MyThread thread and every 3 seconds it sets a data to the MyThread instance and then MyThread prints it. The idea is to have a synchronized object that you wait on it and notify in the end of the usage to other threads that they can use it:
Test.java:
package stack;
public class Test {
public static void main (String args[])
{
Object syncToken = new Object();
MyThread t = new MyThread(syncToken);
t.start();
for (int i = 0; i < 10; i++)
{
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(syncToken)
{
t.setText("Iteration " + i);
syncToken.notify();
}
}
}
}
MyThread.java:
package stack;
public class MyThread extends Thread{
String s;
Object syncToken;
public MyThread(Object syncToken)
{
this.s = "";
this.syncToken = syncToken;
}
public void run()
{
while(true) // you will need to set some condition if you want to stop the thread in a certain time...
{
synchronized (syncToken)
{
try {
syncToken.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("MyThread: " + s);
}
}
public void setText(String s)
{
this.s = s;
}
}
In this example, the main thread sets a string (every 3 seconds) and the MyThread thread prints it.
Adapt it to your needs, it shouldn't be too hard.
I had similar problem. I created an arbiter used by two threads (in your case it can be listeners thread and your task thread):
listener:
arbiter.waitConsumer();
// prepare data
arbiter.dataLoaded();
task thread:
while(true){
arbiter.waitProducer();
// consume data
arbiter.dataConsumed();
}
arbiter:
public class Arbiter {
private boolean dataLoaded = false;
public synchronized void waitProducer(){
while(!dataLoaded){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void waitConsumer(){
while(dataLoaded){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void dataLoaded(){
dataLoaded = true;
notify();
}public synchronized void dataConsumed(){
dataLoaded = false;
notify();
}}
Listener and task will synchronize themselfes against arbiters monitor. Probably you can call your arbiter queue or pipe and store date for consuming in it?