Suppose I have a method in a class and I need it to run continuously on a loop.
How do I do that, without crashing the app.
I'm asking this because I have a method that gets the foreground activity on the device and I need to know every time the foreground activity is changed.
EDIT-
Here's my code to get the currently active Foreground Activity-
public void getForeground()
{
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
String foreground = am.getRunningTasks(1).get(0).topActivity.getPackageName();
Toast.makeText(getApplicationContext(), foreground, Toast.LENGTH_SHORT).show();
}
Now, I need to call this method so that it whenever there's a particular activity that has been opened (like Facebook, Messenger or Whatsapp), I know about it.
How do I do that?
Is there a simpler way apart from creating a custom listener or using a ScheduledExecutorService ?
Or if it can be done using the above mentioned ways, how do I do that?
Use a new thread to execute the method.
public void yourMethod() {
doStuff();
new Thread() {
public void run() {
yourMethod();
}
}.start();
}
in your edited case you better go this way
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
String foreground;
Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
#Override
public void run()
{
foreground = am.getRunningTasks(1).get(0).topActivity.getPackageName();
Toast.makeText(getApplicationContext(), foreground, Toast.LENGTH_SHORT).show();
}
}, 10000); //every 10 seconds
Related
My Android 4+ app is connected to a custom web service that is used to sync data every few minutes. To make sure, that the online data is always up to date, I want to trigger the sync when ever the app is closed / send to background.
Under iOS this is quite easy:
Listen to applicationDidEnterBackground: in the AppDelegate
Use beginBackgroundTaskWithName: to start you long running background task and to avoid being suspended while the task is still running
How to do this on Android?
First problem is, that there is nothing equivalent to applicationDidEnterBackground:. All solution I found so far propose to use the main Activities onPause() method. However this called any time the main Activity is paused, which is also the case when another Activity is started within the app. The is true for the onActivityPaused() method from ActivityLifecycleCallbacks interface.
So, how to detect that the app (not just an Activity) is closed or send to the background?
Second problem is, that I did not find any information on how to run background task. All solutions point to simply start an AsyncTask, but is this really the correct solution?
AsyncTask will start a new task, but will this task also run, when the app is closed/inactive? What do I have to do, to prevent the app and the task from being suspended after a few seconds? How can I make sure, that the task can complete, before the app is completely suspended?
The following code will help you to post your contents when your app is closed or in the background:
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.widget.Toast;
public class SendDataService extends Service {
private final LocalBinder mBinder = new LocalBinder();
protected Handler handler;
protected Toast mToast;
public class LocalBinder extends Binder {
public SendDataService getService() {
return SendDataService .this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
// write your code to post content on server
}
});
return android.app.Service.START_STICKY;
}
}
More explanation of my code is:
Service runs in the background even if your application is in the background, but remember, it always runs on the main thread, because of which I created a separate thread to perform your background operations.
Service is started as a sticky one, as even if because of any reason your service got destroyed in the background it will automatically get restarted.
More details can be found here:
https://developer.android.com/guide/components/services.html
And to check if your app is in the foreground/background, the following code will help:
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null) {
return false;
}
final String packageName = context.getPackageName();
for (RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
}
// Use like this:
boolean foregroud = new ForegroundCheckTask().execute(context).get();
Happy Coding!!!!
The accepted answer is not correct.
Unfortunately, the author believes that posting a new Runnable task to the Handler() creates a separate thread - "I created a separate thread to perform your background operations" :
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
// write your code to post content on server
}
});
return android.app.Service.START_STICKY;
}
onStartCommand() callback is always called on the main thread, and the new Handler() is attached to the current thread (which is "main"). So the Runnable task is posted at the end of main thread queue.
To fix the issue and execute the Runnable in a really separate thread you can use AsyncTask as the simplest solution:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
// ...
}
});
return android.app.Service.START_STICKY;
}
Think yourself before you copy-paste anything ...
You can use services for what you want to achieve. A service will keep on running in the background even when the activity component has been destroyed, provided you have not invoked stopService(..) or stopSelf() methods.
In the service you can make an Async network call, preferably using retrofit, and then you can update you local storage like Sqlite DB with the latest data fetched from your web service.
Here is the official link, you can just use an unbounded service for what you want to achieve.
For background operations, you can use WorkManager.
I'm not sure if this is the correct way to go about but I will try and explain what I want to do.
I have an Activity which creates a fragment called TemporaryFragment with a label. What I want to do is create and start a service with a Timer in it and that Timer then updates the time in that TextView.
The way I am thinking of going is somehow, when the Service is started, passing the TextView from the Activity to the Service and then the Service keeping a reference to it.
Another possible way is to make the Activity become a listener of the Service and then calling a method in the Service to update the TextView.
Any thoughts would be great and maybe some options.
Thanks in advance.
ADDITION
I'm sorry, I should also specify that I need this timer to run in the background. So when the application is sent to the background, I need the timer to carry on and only stop when I tell it to.
Service is not ideal for such minor task like this, moreover, Service can be run independently of activity. Also spawning new thread or using timer which introduces new thread into the application is not ideal for this relatively minor reason if you are thinking in the terms of mobile applications.
Instead use Handler in your fragment.
create handler in your fragment
private Handler mHandler = new Handler();
to execute your defined task call
mHandler.postDelayed(mUpdateTask, 1000);
or
mHandler.post(mUpdateTask);
and define your task in the fragment
private Runnable mUpdateTask = new Runnable() {
public void run() {
Toast.makeText(getActivity(), "hello world", Toast.LENGTH_SHORT).show();
mHandler.postDelayed(this, 1000);
}
};
If you are showing time-like information instead of countdown-like one, use
mHandler.removeCallbacks(mUpdateTimeTask);
in onPause() method to stop executing your task if the activity is not visible as updating UI isn't relevant and it saves battery (you start task again in onResume() method)
Basically, the idea behind the timer is eventually I am going to add some tracking into my application and therefore need it to continue running even if the application isn't in the foreground – Disco S2
Based on this comment I suggest you to use a local service which resides in the background, doing it's stuff (start a thread from Service#onStart), until it gets stopped by stopService(..).
Activities on the other hand may bind and unbind to that service (see: bindService(..)) to get notified about updates or to communicate with the service in any way.
I would use a more simple approach by using a Thread:
public class MainActivity extends Activity implements Callback {
private static final int MSG_UPDATE = 1;
private static final long INTERVAL = 1000; // in ms
private final Handler handler = new Handler(this);
private Thread worker;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE:
updateView();
return true;
}
return false;
}
private void updateView() {
// TODO tbd
}
#Override
protected void onStart() {
super.onStart();
// start background thread
worker = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(INTERVAL);
} catch (InterruptedException e) {
break;
}
// send message to activity thread
handler.sendEmptyMessage(MSG_UPDATE);
}
}
});
worker.start();
}
#Override
protected void onStop() {
super.onStop();
// stop background thread
worker.interrupt();
try {
worker.join();
} catch (InterruptedException e) {
}
worker = null;
}
}
You can use the TimerTask Class for this. Override the TimerTask.run() method and then add that TimerTask to Timer class.
Also check this question: controlling a task with timer and timertask
I have to run a bit of code in the background every one second, the code will call a webservice which searches a database and returns a value to the application. My question is which method would be the most effective to do this? I have read up on Timers, Threads, AsyncTask and Services and each seem to have their pros and cons. Please can someone tell me which would be the best to use considering execution time and battery life.
Thanks
Update:
I decided to use Aysnc task to run my code in the background while using a TimeTask to trigger the AsyncTask at regular intervals. This way the operation is destroyed when I leave that particular activity
You should use the service to do the background operation but in your case you want to run code in 1 sec here is the example of service using handler it call in every 1 sec.
public class YourService extends Service {
private static final String TAG = "Your Service";
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onDestroy() {
super.onDestroy();
// Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
handler.removeCallbacks(sendUpdatesToUI);
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
/// Any thing you want to do put the code here like web service procees it will run in ever 1 second
handler.postDelayed(this, 1000); // 1 seconds
}
};
#Override
public void onStart(Intent intent, int startid) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);//1 second
Log.d(TAG, "onStart");
}
}
and service can't run every time android idle the service within 3 or 4 hr i suggested you to use the foreground service to use your process long running.
For operations like this I tend to use a Service component. for the task itself i use an AsyncTask which will wait a set time before it repeats itself (using a while loop).
You will have to create a new Thread so that the call don't lock up the device if the call takes longer than expected. The AsyncTask is an easy way to use multithreading, but it lacks the functionality of repeating tasks. I would say that you are best of either using a Timer or the newer ScheduledExecutorService.
If you chose to use the Timer you create a TimerTask that you can hand it. The ScheduledExecutorService takes a Runnable instead.
You might want to wrap the thread in a Service (The Service does not provide a new Thread), but this is not always necessary depending on your needs.
As suggested in comment, you can also use the Handler.postDelayed(). Although you still need to create a new thread and then call Looper.prepare() on it:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(Code from Looper docs)
Also; calls to a webservice every second seems way too frequent, especially if the user is on a slow connection or there are data that needs to be transferred, try to reduce the calls as much as possible.
I think it's not only one solution, so it's up to you. You can try start thread with this run method:
private final int spleeptime = 1000;
public boolean running;
#Override
public void run() {
while (running) {
try {
int waited = 0;
while ((waited < spleeptime)) {
sleep(100);
waited += 100;
}
} catch (InterruptedException e) {
} finally {
// your code here
}
}
}
my usecase is (roughly) the following on first startup:
activity starts a service
service gets and saves data in a database
service notifies activity with an intent
activity displays data
Now I want to display a progress bar while the service is busy. The problem is:
startService(new Intent(getApplicationContext(), UpdateDataService.class));
takes a very long time to "come back" to the UI thread. It seems to be a synchronized function (or not?). If a empty the service class the startService command is processed almost instant. It seems the UI thread waits for the Serice to handle its work, which does not make sense at all. I tried to start (as stupid as it may seem) to start the service a async task while displaying a progress bar in my UI thread. Weird enough this works sometimes. Othertimes I just get a white screen while my service is working and afterwards for a millisecond ma progressbar and then my UI.
Now my question: How do I start the service without blocking my UI?
public class MyClass extends TabActivity {
private ProgressDialog pd;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = null;
//building some tabs here, setting some text views....
// starting service if does not exist yet
boolean serviceRunning = false;
final ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if ("aegir.mobile.UpdateDataService".equals(service.service.getClassName())) {
serviceRunning = true;
Log.i(MY_APP_TAG, "Service found.");
}
}
if (!serviceRunning) {
pd = ProgressDialog.show(this, "Loading...", "Setting up data.", true, false);
new StartServiceAsync().execute("");
}
}
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
pd.dismiss();
}
};
public class StartServiceAsync extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(final String... params) {
// starting service
startService(new Intent(getApplicationContext(), UpdateDataService.class));
return null;
}
#Override
protected void onPostExecute(final String result) {
handler.sendEmptyMessage(0);
super.onPostExecute(result);
}
}
From the guide topic Services:
Caution: A services runs in the same process as the application in which it is declared and in the main thread of that application, by default. So, if your service performs intensive or blocking operations while the user interacts with an activity from the same application, the service will slow down activity performance. To avoid impacting application performance, you should start a new thread inside the service.
This doesn't change just because you call startService from an AsyncTask.
I think you should just move the logic from the service to the doInBackground method in the async task. That's what async task are for, executing hard work giving you a simple way to interact with the UI. It's weird to call a service in the async task, is there any reason why you did that?
Either do your work in the AsyncTask itself, use an IntentService instead of a plain old Service or start a thread from your Service to do your work. A Service in Android does not inherently use a different thread (IntentService does to do its work).
Despite starting your Service from an AsyncTask, right now it seems the actual work is being performed in your UI thread.
please Use this code the easy way to do what you asked in question.
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent = null;
registerReceiver(dataUpdated, new IntentFilter("<FLAG>"));
//building some tabs here, setting some text views....
// starting service if does not exist yet
boolean serviceRunning = false;
final ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (final RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if ("aegir.mobile.UpdateDataService".equals(service.service.getClassName())) {
serviceRunning = true;
Log.i(MY_APP_TAG, "Service found.");
}
}
if (!serviceRunning) {
pd = ProgressDialog.show(this, "Loading...", "Setting up data.", true, false);
startService(new Intent(getApplicationContext(), UpdateDataService.class));
}
}
private BroadcastReceiver dataUpdated= new BroadcastReceiver() {
#SuppressLint("ShowToast")
#Override
public void onReceive(Context context, Intent intent) {
//<Your Process which you want when Service finishes a task >
pd.dismiss();
}
};
#Override
protected void onDestroy() {
unregisterReceiver(dataUpdated);
}
In Service when your Task will Complete call this Method
sendBroadcast(new Intent("<FLAG>"));
I am trying to update my UI in FirstActivity when I receive a notification but is confused by runOnUiThread , Runnable and Handler. Here is what I have: I am running FirstActivity and NotificationService. When NotificationService reeives a notification, it will update FirstActivity UI.
I also have another service AlarmService running.
First Activity
#Override
public void onResume() {
super.onResume();
//some other code for alarm service
}
NotificationService
//on receiving notification
private void showNotification(String text) {
//Get activity
Class<?> activityClass = null;
try {
activityClass = Class.forName("com.pakage.FirstActivity");
contextActivity = (Activity) activityClass.newInstance();
//Update UI on FirstActivity not working
contextActivity.runOnUiThread(new Runnable() {
public void run()
{
Looper.prepare();
TextView tv = (TextView ) contextActivity.findViewById(R.id.notifyTest);
Looper.loop();
}
});
} catch (Exception e) {
e.printStackTrace();
}
//Shows the notification
Notification n = new Notification();
//... etc
}
I keep getting looper.prepare error. Do I need to put extra codes in my FirstActivity?
My 1st instinct is that you should instead have the Activity bind to your service and handle the UI update on its side instead of the Service directly modifying the Activity.
See more info here:
http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
And an example here:
Example: Communication between Activity and Service using Messaging
I've always just had the service fire off a Broadcast and then in my Activity I have a BroadcastReciever listening for the Broadcast. It's an approach that is much simpler than the one you outlined above.
I have no idea why you are putting a Looper in
contextActivity.runOnUiThread(new Runnable() {
public void run()
{
Looper.prepare();
TextView tv = (TextView ) contextActivity.findViewById(R.id.notifyTest);
Looper.loop();
}
});
because the UI (main) thread already has a Looper/Handler etc..
Even if it did work Looper.loop() is going to block and since you are running it on the UI thread, it will block the UI thread which is not what you want.
What you really want to do is
contextActivity.runOnUiThread(new Runnable() {
public void run()
{
TextView tv = (TextView ) contextActivity.findViewById(R.id.notifyTest);
tv.setText("do something that must be on UI thread") // or whatever
}
});
You don't really need to do all this fancy stuff to get the Activity
activityClass = Class.forName("com.pakage.FirstActivity");
contextActivity = (Activity) activityClass.newInstance();
assuming the Service and Activity are both running in the same process you can just save a reference to the Activity but be careful to update the reference when the Activity gets destroyed.