I have a service that monitors a socket connection. When the connection is lost it needs to display a Toast informing the user that it is reconnecting. This works fine the first time. After that I see the enqueueToast in the log but the toast is not displayed. Any ideas are appreciated. I thought this was going to be an easy thing to add, but I must be missing something.
Log entry
INFO/NotificationService(118): enqueueToast pkg=com.abc
callback=android.app.ITransientNotification$Stub$Proxy#43f7b100
duration=1
Code that calls the Toast
public class ConnectionService extends Service
{ .....
public void restartConnection()
{
try
{
Log.i(this.toString(), "Attempting to reconnect...");
// increase the wait between each retry until the max is reached
int sleepTime = reconnectCounter * MIN_RECON_WAIT;
if (sleepTime > MAX_RECON_WAIT)
{
sleepTime = MAX_RECON_WAIT;
}
String msg = "The connection has been lost. Restart attempt will start in: " + sleepTime/1000 + " seconds";
Log.i(this.toString(), msg);
Toast.makeText(getApplicationContext(), msg , Toast.LENGTH_LONG).show();
Thread.sleep(sleepTime);
// increment the counter
reconnectCounter++;
this.startConnectionThread();
}
catch (Exception e)
{
Log.e(this.toString(), "Exception: " + e.toString());
e.printStackTrace();
}
}// end retartConnection
Yeah, you could go with the runOnUiThread, that's a legit way.
Also, you could try the Handler alternative. Either way it should work.
Here is some code from the top of my head. I don't have the SDK now to test it but I think it should give you a general idea.
public class ConnectionService extends Service {
private Handler handler = new Handler();
public void restartConnection(){
int sleepTime = reconnectCounter * MIN_RECON_WAIT;
if (sleepTime > MAX_RECON_WAIT)
{
sleepTime = MAX_RECON_WAIT;
}
String msg = "The connection has been lost. Restart attempt will start in: " + sleepTime/1000 + " seconds";
(new Timer()).schedule(
new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "msg", Toast.LENGTH_LONG).show();
reconnectCounter++;
this.startConnectionThread()
}
});
}
}, sleepTime);
}//end restartConnection
}//end ConnectionService
here is the solution
http://www.jjoe64.com/2011/09/show-toast-notification-from-service.html
you have to create a Handler in the onStartCommand method. And in the onHandleIntent method you can then create and show a toast notification
Related
I am using Android Studio. I use locationManager.requestLocationUpdates(...) to get the location.
I want to do something like this:
//print location every 5 minutes
12:10am lat=10.23652 long=21.25441
12:15am lat=10.23652 long=21.25441
12:20am lat=15.21456 long=58.21452
12:25am lat=12.24752 long=27.24587
12:30am lat=12.24752 long=27.24587
12:35am lat=12.24752 long=27.24587
...
I'm not interested in knowing if the location changed, I just want to print it every x minutes.
A solution could incorporate a Handler with a postDelayed. It is important to remove any Callbacks!
Try something like this:
private boolean continueLoop = true;
private Handler myHandler = new Handler();
private void startLocationManager() {
try{
Log.d(TAG, "startLocationManager - Started");
// here the delay (in this example it is effectively the interval)
int minutes = 5;
int delay = 1000 * 60 * minutes;
myHandler.postDelayed(mAutoLocationManager, delay);
}
catch(Exception ex){
Log.e(TAG, ex.getMessage());
}
}
private Runnable mAutoLocationManager = new Runnable() {
public void run() {
if(continueLoop){
// preform the scan for the location coordinates
startYourLocationCoordinates();
//re-trigger the call to start a new interval
startLocationManager();
{
}
};
// Make certain that you remove the callback when you leave the activity -- maybe in onPause()
private void stopAutoDownloadManager(){
try{
myHandler.removeCallbacks(mAutoLocationManager);
}
catch(Exception ex){
Log.e(TAG, ex.getMessage());
}
}
I'm trying to show feedback the percentage of which they have downloaded data from a server.
The flow goes something like this:
LoginActivity
- onSuccess, call Service to download data
- while Service is working, I've already switched the user to HomeActivity
HomeActivity
-This activities layout holds a Fragment I created called LoadingFragment
-There is a method in LoadingFragment that is subscribed to an event that is posted by the Service
My problem is that the Fragment UI is not changing at all whenever an event has been posted.
I logged everything, and I can see the event posting the correct data but the data is not being reflected on the UI.
Below is my Service:
#Override
public int onStartCommand(Intent intent, int flags, final int startId) {
Integer id = intent.getIntExtra("id", 0);
//do sync here
Log.i(LOG_TAG, "Make rest call to retrieve all r for id: " + id);
mRestClient.getApiService().getR(id, new Callback<List<R>>() {
#Override
public void success(List<R> rResponse, Response response) {
Integer outstanding = routeResponse.size();
Integer percentage;
LoadingEvent loadingEvent = new LoadingEvent();
SyncEvent syncEvent = new SyncEvent();
Log.i(LOG_TAG, "Callback success r");
System.out.println("yohellotest");
Log.i(LOG_TAG, "Begin insertion");
DaoMaster daoMaster = MyApp.getDaoMaster();
DaoSession session = daoMaster.newSession();
SQLiteDatabase db = session.getDatabase();
RDao rDao = session.getRDao();
WDao wDao = session.getWDao();
JDao jDao = session.getJDao();
Log.i(LOG_TAG, "--Beginning Transaction--");
//db.beginTransaction();
try {
int counter = 0;
for(int i = 0; i < rResponse.size(); i++) {
R r = rResponse.get(i);
rDao.insert(r);
Log.i(LOG_TAG, "inserted r: " + r.getId());
for(int j = 0; j < r.getW().size(); j++) {
W w = r.getW().get(j);
wDao.insert(w);
Log.i(LOG_TAG, "inserted w: " + w.getId());
for(int k = 0; k < w.getJ().size(); k++) {
J j = w.getJ().get(k);
jDao.insert(j);
Log.i(LOG_TAG, "inserted j: " + j.getJId());
}
}
counter += 1;
percentage = (int) Math.floor((double) counter / outstanding * 100);
loadingEvent.setPercentage(percentage);
bus.post(loadingEvent);
}
Log.i(LOG_TAG, "Finished inserting");
//db.setTransactionSuccessful();
} catch (Exception e) {
Log.i(LOG_TAG, "Exception happened " + e.getMessage().toString());
System.out.println("yo something happened, but I don't know what");
} finally {
Log.i(LOG_TAG, "--Closing transaction--");
//db.endTransaction();
}
syncEvent.setIsSuccess(true);
syncEvent.setStatus(200);
bus.post(syncEvent);
}
#Override
public void failure(RetrofitError error) {
Log.i(LOG_TAG, "Rest call failed for this api");
System.out.println("failtests");
}
});
return START_STICKY;
}
Fragment Subscribed Method
#Subscribe
public void loadingResponse(final LoadingEvent loadingEvent) {
Log.i(LOG_TAG, "Response from loading: " + loadingEvent.getPercentage());
if(getActivity() == null)
return;
textTest.setText(loadingEvent.getPercentage().toString());
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.i(LOG_TAG, "Updating ui for loading text" + loadingEvent.getPercentage().toString());
mCircularProgressBar.setProgress(loadingEvent.getPercentage());
textTest.setText(loadingEvent.getPercentage().toString());
}
});
}
When I check my Logs, I see everything coming in fine, but the UI is not reflecting it. What am I missing here?
EDIT
Forgot to mention. I'm using this library for my circle progress bar:
CircleProgressBar
EDIT
As of today, I still have yet to figure this out. I also noticed that my adapter is not being updated when the service posts the event. Previously, the context used to startService() was the getApplicationContext() from the LoginActivity. I thought this might have been a problem so I changed it to get the instance of the HomeActivity instead. I thought that firing the service from my HomeActivity would have solved the problem, but I'm still getting the same results unfortunately.
Okay so no one really tried to attempt answering my question but I figured it out.
I actually skimped over the documentation part of the Service class and didn't know that it was executing on the Main Thread. To fix this, I had to run an AsyncTask to execute my operation in the background.
The only thing I had to change in my codebase was to move the executing code from the onStartCommand method into an AsyncTask. The AsyncTask will be initiated onStartCommand and everything should be working fine.
My code looks something like this now :
Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
DownloadTask downloadTask = new DownloadTask();
downloadTask.execute();
return START_STICKY;
}
private class DownloadTask extends AsyncTask<Void, Void, LoginEvent> {
#Override
protected LoginEvent doInBackground(Void... params) {
//Code here to run my operations
//Call api, insert to db, post events etc...
//
}
#Override
protected void onPostExecute(LoginEvent event) {
//run anything here you want to do after execution
}
}
You can ignore my LoginEvent as this was something for my event bus to post events to any subscribers.
Also, keep in mind that if you are going to change any views from this AsyncTask through the bus, make sure the subscriber uses the runOnUi to execute or else you'll hit a runtime exception since you're trying to change a view from something other than the MainThread.
What i'm trying to do should be pretty simple, i'm calling an IntentService to check periodically in background if the current time is before or after a specified time (passed as Extras in the intent from the MainActivity) and get a notification when it happens.
In Thread's run() method i get an instance of the current time and use it as comparison to the previously specified one in an if/else construct, before re-running the Thread.
The problem is that it always go for "else" even if the current time is after the other one. This problem is just too strange, can anyone explain me where is the error?
Here is my IntentService class:
public class MyCheck extends IntentService {
int hour = 0; int minute = 0;
int i = 0;
private static final String TAG = "Check";
int hourNow;
int minuteNow;
Handler handler = new Handler();
public MyCheck() {
super(MyCheck.class.getName());
}
#Override
protected void onHandleIntent(Intent intent) {
Log.w(TAG, "Service Started!");
hour = intent.getIntExtra("hour", 0);
minute = intent.getIntExtra("minute", 0);
Log.w(TAG, "Step 1 ");
Thread runnable = new Thread() {
#Override
public void run() {
/* do what you need to do */
Log.w(TAG, "Step 2 ");
/* get current time */
Calendar c = Calendar.getInstance();
hourNow = c.get(Calendar.HOUR);
minuteNow = c.get(Calendar.MINUTE);
//HERE, IT SEEMS THAT IT'S ALWAYS BEFORE hour AND minute
if(hourNow > hour || (hourNow == hour && minuteNow > minute)) {
//SEND
Log.w(TAG, "RUN ");
Intent broadcast = new Intent();
broadcast.setAction(NOTIFICATION_SERVICE);
sendBroadcast(broadcast);
handler.removeCallbacks(this);
}
else {
//NOTHING
i++;
Log.w(TAG, "NOT YET " + i);
}
//REPEAT EVERY 6 SECONDS
try {
sleep(6000);
handler.post(this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
runnable.start();
}
}
EDIT
I've found the trivial problem as you can see in my answer below.
If someone wants to complete the answer with some more information about the problems that can occur during the building process they will be apreciated. TIA
The simple solution to this was to wait and reboot Windows. The code wasn't flawed after all, it's just something on the building process that needed some time to tell the compiler that the error wasn't there: maybe there was a copy in cache of a past error that was still taken in account, i'm not sure.
Maybe you can add some information to my last statement, posting an answer or a commenting about it.
Let say I want to pass some configuration data before I start a thread so it can run with it right away how do I do that? Here is a simple code:
Here I'm trying to configure the sleep delay, but it requires me to declare data inside? How can I let the thread know?
public void startAniHandlerThread(){
int sleeptime;
Thread thread1 = new Thread(){
public void run(){
try {
sleep(sleeptime); Log.d("TEST", " Test ");
} catch (Exception e) {
e.printStackTrace();
Log.d("TEST", " "+e);
}
}
};
thread1.start();
}
You can declare sleeptime as
final int sleeptime = <value>;
That way you'll be able to access it from inside the Runnable.
In my app while copying files I want to ask user whether he wants to overwrite the file with same name, skip, etc. Here is some code from the thread:
if(target.exists()){
synchronized(this){
while(wait){
try{
popupHandler.sendMessage(popupHandler.obtainMessage(0, target));
wait();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
Here is my handler:
Handler popupHandler = new Handler(){
#Override
public void handleMessage(Message m){
c.showConfirmDialog("The file " + ((File)m.obj).getName() + " exists. What do you want to do?",
"Overwrite", "Skip", "Keep both", Explorer.PASTE_CONFIRM, null);
}
};
After choosing an option from dialog something like that is called:
public void resume(){
synchronized(copyThread){
copyThread.wait = false;
copyThread.notify();
}
}
And here goes the problem. The copyThread on resume() is always null. I can't find what is wrong because the same scheme with pausing the thread works in my other class. It looks like the thread is dying after sending the message:/ Any ideas? Thanks in advance.