I have a service which sends continously values to an activity through some custom event listeners.
Here everything works fine. Certain values are displayed in my activity as expected, but some others make the application to crash. This is because some of the incoming data is calculated inside a normal thread (that I cannot have access for changing it), and I know I have to use a handler here, but as far as I tried the app still crashing.
more graphically I would like to do the following
onValuesChanged(float val) {
myTextView.setText( Float.toString(val) )
}
where val is calculated in a normal thread, but of course it makes crash the app when doing the setText.
Any suggestions?
Use AsyncTask instead of Thread and in the onPostExecute() you can update the UI.
or use Activity.runOnUiThread(new Runnable() {
void run() {
// do something interesting.
}
});
hey u can send a custom broadcast from your service like this
Intent mintent = new Intent();
mintent.setAction("com.action");
mintent.putExtra("name", "value");
sendBroadcast(mintent);
and register a receiver in your activity which will get the value from incoming intent and then call the handler like this to update the UI ..plese parse the int to string at receiving
myTextView.post(new Runnable() {
public void run() {
myTextView.setText( Float.toString(val) )
}
});
Every time you send a broadcast to your activity and it will update the ui ..
However the above mentioned way is also right but if you have to stay with service then go for this way else above......
Related
Under some conditions, when my app starts, it displays an AlertDialog. However, the alert never gets displayed. I discovered that if I add a delay, it works (i.e. gets displayed).
More specifically: on app startup, it executes the main activity onCreate() which under a certain condition starts a 2nd activity. In the 2nd activity, through a separate thread, it makes a check for some web server status. If the Android device doesn't have Internet connectivity, HttpURLConnection returns an error instantly and my enclosing function executes a callback to the 2nd activity. My code then uses post() to attempt to display an alert to the user (using post allows displaying the alert on the UI thread, which is required).
Apparently it tries to display the alert before any of the either activity's UI has been created. If I use postDelayed() in the 2nd activity, the problem still persists. However, if I use the following block of code in the main activity, the alert shows properly:
new Handler().postDelayed (new Runnable ()
{
#Override public void run()
{
Intent intent = new Intent (app, MyClass.class);
app.startActivityForResult (intent, requestCode);
}
}, 3000);
My solution is a hack that happens to work at the moment. I don't mind having a little delay on start-up for this particular situation but I don't want a delay that's longer than necessary or one that may sometimes fail.
What is the proper solution?
Ok, here's a workaround. First, I'll speculate that the problem is that the attempt to display the alert is happening before the looper for the UI thread has been started. Just a speculation.
To work around the problem I added a recursive post which gets called from onResume(), like this:
private boolean paused = true;
#Override public void onResume ()
{
super.onResume();
paused = false;
checkForAlert();
}
#Override public void onPause ()
{
super.onPause();
paused = true;
}
And here's the function that does the post:
private AlertInfo alertInfo = null;
private void checkForAlert()
{
if (alertInfo != null)
{
...code to build alert goes here...
alertInfo = null;
}
if (!paused)
contentView.postDelayed (new Runnable()
{
#Override public void run() { checkForAlert(); }
}, 200);
}
AlertInfo is a simple class where the thread needing the alert can put the relevant info, e.g. title, message.
So, how does this work? checkForAlert() gets called during onResume() and will continue to get called every 200ms until "paused" is false, which happens in onPause(). It's guaranteed to be recurring whenever the activity is displayed. The alert will get built and displayed if alertInfo is not null. In the secondary thread, I simply create an AlertInfo instance and then within 200ms the alert gets displayed. 200ms is short enough that most people won't notice the delay. It could be shorter but then battery use goes up.
Why did I start checkForAlert() in onResume instead of onCreate()? Simply because there's no need for it to run unless the activity is currently "on top". This also helps with battery life.
I have a download process that runs in the background, and updates the UI with progress (a ListView adapter). It works fine until I leave the activity and come back. After loading the activity again there is a "new" ListView object that is not the same one that is bound to the BG download process. How can I structure my code so that the background process can always talk to the ListView in my activity?
The specific line that does this is:
adapter.notifyDataSetChanged();
Here is the shell of the Download class:
public class Download
{
}
protected void start()
{
TransferManager tx = new TransferManager(credentials);
this.download = tx.download(s3_bucket, s3_dir + arr_videos.get(position), new_video_file);
download.addProgressListener(new ProgressListener()
{
public void progressChanged(final ProgressEvent pe)
{
handler.post( new Runnable()
{
#Override
public void run()
{
if ( pe.getEventCode() == ProgressEvent.COMPLETED_EVENT_CODE )
{
Download.this.onComplete();
}
else
{
Download.this.onProgressUpdate();
}
}
});
}
});
}
protected void onProgressUpdate()
{
this.download_status = "downloading";
Double progress = this.download.getProgress().getPercentTransfered();
Integer percent = progress.intValue();
//Log.v("runnable", percent + "");
downloaded_data.edit().putInt(position+"", percent).commit();
adapter.notifyDataSetChanged();
}
}
The short answer is simply "no". There's no simple way to find/keep the reference to a ListView in a destroyed/recreated Activity.
One way you can get around this is to use BroadcastReceiver. You can broadcast progress intents, and have the Activity register/deregister from those intents in onCreate() and onPause().
Another (arguably easier) hack you can do it is to persist the state (along the lines of what you're doing with downloaded_data.edit()), and have a thread in your Activity that regularly polls this state and updates the ListView accordingly.
You can save data of listview in file, then in function onCreate callback to take it. Using File may be a solution. Once your Activity is destroyed, all datas are lost
Make tasks detachable, like an Executor service placed in a component that is always there between Activity changes:
Use a Service: clients can connect to it and request what tasks are running etc.
Implement Application class and let it hold references to tasks that are running, exposed via a static field.
I'm pretty new to this, so sorry if my question might be trivial, and I'm sure this is basic stuff, but really I couldn't find a solution.
I'd like to realize an autorefresh in an active activity. I have a BT-service running in background and need a confirmation for some received data through mHandler. If it receives the expected I want to change the string of a textview, right now I'm using an extra button, but it's the ugliest way.
So I need a loop inside the activity, but what should I use? which action listener?
ok what you can do is you can create a broadcast reciever in your activity. Write this code in you oncreate. fix it actually i am at home so you need to fix it i m giving you idea.
BroadcastReciever broadcast_obj = new BroadcastReciever (
#overrieded
onRecieve(Intent intent) {
String action = intent.getAction();
if(action == "my_bt_action") {
//UPDATE YOUR TEXTVIEW AND DO WHATEVER WORK YOU WANT.
}
});
Now you need to register your broadcast for that just put these line in your oncreate after creating Broadcast reciever which we have just done.
registerREciever(broadcast_obj, new IntentFilter("my_bt_action");
now you need to send your broadcast when your service will perform your calculation or your task for that it is simple.
Intent intent = new Intent (getApplictionContext,"my_bt_action");
sendBroadcast(intent);
from above code you can easily communicate between your activity and service.
hope it will work.
Maybe you can try a loop inside a thread
boolean update = false; // control the state to update textview
new Thread(new Runnable(){
void run(){
while(true){
if(!update){
...
textview.setText("something.");
...
update = true;
}
}
}
}.start();
I have question regarding the service and activity.
I have one service which calls some other class to get contacts from phone, and activity where the contacts will be placed. What is the best thing to do:
1 this: On bound Activity "ask" in infinite loop for status from service like this:
Thread trdTest = new Thread(new Runnable() {
public void run() {
boolean done= true;
while(done){
if (service.status == Constants.GETTING_CONTACTS_DONE_OK){
handler.sendEmptyMessage(0);
done= false;
}else if (service.status == Constants.GETTING_CONTACTS_ERROR_NOTOK){
handler.sendEmptyMessage(1);
done= false;
}
}
}});
trdTest.start();
2: this: Create cistom event in service and fire event when getting users is done. Of course the bounded activity will listen for that event
Thanx for the answers.
Running loops like that will probably slow down many things and is not a good idea. The second approach seems to me like a much better idea.
I am trying to prevent my application calling the same method twice in the event of a double-click, or if the user presses different buttons quickly, almost at the same time.
I have clickable Views, acting as buttons, that call the same method but passing different parameters. This is the call:
startTheSearch(context, getState(), what, where);
Inside this method I'm creating a new Thread, because it queries a web server for the result:
new Thread(new Runnable() {
public void run() {
progDiag = ProgressDialog.show(ctx, null, "Searching", true);
getServerXML(context, what, where, searchIsCustom, mOffset);
handler.sendEmptyMessage(0);
}
}).start();
The problem is that upon two quick clicks, the method is fired twice, two threads are created, and consequently two new activities are created. That makes my app crash.
When the methods are done, and we have the result from the server, we call the handler:
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Intent i = new Intent(Golf.this, Result.class);
Bundle b = new Bundle();
b.putString("what", mWhat);
b.putString("where", mWhere);
b.putInt("offset", mOffset);
b.putBoolean("searchIsCustom", searchIsCustom);
i.putExtras(b);
startActivityForResult(i, Activity.RESULT_OK);
progDiag.dismiss();
} catch (Exception e) {
Alerts.generalDialogAlert("Error", "settings", ctx);
}
}
};
I tried to have a global boolean variable called "blocked" initially set to false, creating a condition like:
if(!blocked){
blocked = true;
new Thread(new Runnable() {
public void run() {
But this only seems to work on slower phones like the G1, I tried on Nexus and before it set blocked = true, the second request has was granted. So is there any way I can block the method being called if it's already running, or if the thread has started so it wont create a new one?
In the book Hello Android the author Ed Burnette gives a very nice solution for this problem.
To leave your app snappy and responsive you should create a second thread to do the web request.
Instead of creating a new thread for every request you can use a SingleThreadExecutor. If you start a second thread you can check if you are waiting for the result of another thread and block until this thread is ready, or cancel the old thread and start a new one if you think that the user now wants to do some other thing.
You can find the source code from the book on this page. Look for the Translate folder inside the source. It is a nice example on how to react to user commands and how to prevent too many web requests because of a user touching a lot on the gui.
Instead of using the "blocked" Boolean, you might investigate using a mutex. They're designed for this kind of problem.
I tried on Nexus and before it set
blocked = true, the second request has
was granted
That is impossible. Android UIs are single-threaded. There is no way that two onClick() methods of OnClickListeners will be called at the same time.