I'm trying to download multiple files using IntentService. The IntentService donwloads them okey as expected one at a time, the only problem is that when the Internet is down the intent service will not stop the donwload rather it will get stuck on the current thread. If I manage to stop the current thread it will continue running the other threads stored in its queue even though the internet connection is down.
It was suggested in another post that I use LinkedBlockingQueue and create my own Worker thread that constantly checks this queue for new threads. Now I know there are some increased overheads and thus performance issues when creating and destroying threads but that's not a concern in my case.
At this point, All I want to do is understand how IntentService works which as of yet I don't (and I have looked at the code) and then come up with my own implementation for it using LinkedBlockingQueue controlled by a Worker thread. Has anyone done this before ? Could provide a working example, if you feel uncomfortable providing the source code, pseudo code is fine by me. Thanks!
UPDATE: I eventually implemented my own Intent Service using a thread that has a looper which checks the queue which in turn stores the intents passed from the startService(intent).
public class MyIntentService extends Service {
private BlockingQueue<Download> queue = new LinkedBlockingQueue<Download>();
public MyIntentService(){
super();
}
#Override
public void onCreate() {
super.onCreate();
new Thread(queueController).start();
Log.e("onCreate","onCreate is running again");
}
boolean killed = false;
Runnable queueController = new Runnable() {
public void run() {
while (true) {
try {
Download d =queue.take();
if (killed) {
break;
}
else {
d.downloadFile();
Log.e("QueueInfo","queue size: " + queue.size());
}
}
catch (InterruptedException e) {
break;
}
}
Log.e("queueController", "queueController has finished processing");
Log.e("QueueInfo","queue size: " + queue.toString());
}
};
class Download {
String name;
//Download files process
void downloadFile() {
//Download code here
}
Log.e("Download","Download being processed is: " + name);
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
public void killService(){
killed = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Download d = new Download();
d.setName(intent.getStringExtra("VIDEOS"));
queue.add(d);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e("stopSelf","stopSelf has been just called to stop the Service");
stopSelf();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
I'm not so sure about the START_NOT_STICKY in the onStartCommand() method. If it's the right flag to return or not. Any clarification on that would be appreciated!
UPDATE: I eventually implemented my own Intent Service using a thread that has a looper which checks the queue which in turn stores the intents passed from the startService(intent).
public class MyIntentService extends Service {
private BlockingQueue<Download> queue = new LinkedBlockingQueue<Download>();
public MyIntentService(){
super();
}
#Override
public void onCreate() {
super.onCreate();
new Thread(queueController).start();
Log.e("onCreate","onCreate is running again");
}
boolean killed = false;
Runnable queueController = new Runnable() {
public void run() {
while (true) {
try {
Download d =queue.take();
if (killed) {
break;
}
else {
d.downloadFile();
Log.e("QueueInfo","queue size: " + queue.size());
}
}
catch (InterruptedException e) {
break;
}
}
Log.e("queueController", "queueController has finished processing");
Log.e("QueueInfo","queue size: " + queue.toString());
}
};
class Download {
String name;
//Download files process
void downloadFile() {
//Download code here
}
Log.e("Download","Download being processed is: " + name);
}
public void setName(String n){
name = n;
}
Related
I am developing a android app, which will update device location after 4 seconds interval and depending on the response received from the server it will open specific activity.
Problem 1) In some case it will open up a activity like incoming phone call with sound. I am facing problem when I am removing the app from recent app. I noticed the poll function is running twice at the same time, and multiple media is playing at the same time.
Problem 2) I am using Service intead of IntentService(I am a beginner and not sure which will be better). The background service should run even the phone goes to sleep mode, just like WhatsApp or other messenger run.
As the file is big enough, I am attaching only important part
public class TaxiNorrService extends Service implements LocationListener {
...
...
final Handler poll_handler = new Handler();
private NotificationManager mNM;
private final Actions actions = new Actions();
public Ringtone r;
private String newtext;
private Runnable BreakRunnable;
private Runnable poll_runnable;
private Handler BreakHandler;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
poll_runnable = new Runnable() {
#Override
public void run() {
if(!App.isAutoBreak()){
if(BreakHandler !=null){
BreakHandler.removeCallbacks(BreakRunnable);
}
if(r != null) {
if (r.isPlaying()) {
r.stop();
}
}
}
if (actions.checkPermission(getApplicationContext())) {
checkGPS();
if(isNetworkAvailable()){
if(App.isPollOn()){
poll(latitude, longitude);
}
}else{
if(BreakHandler !=null){
BreakHandler.removeCallbacks(BreakRunnable);
}
boolean foregroud = false;
try {
foregroud = new ForegroundCheckTask().execute(getApplication()).get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
boolean background = isMyServiceRunning(TaxiNorrService.class);
if(foregroud == true && background == true && App.isAppForground()){
if(!App.isLoadingVisible()){
Intent intent = new Intent(TaxiNorrService.this, Loading_activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
}
poll_handler.postDelayed(this, 4000);
}
};
return Service.START_STICKY;
}
private void poll(double lat, double lon){
//Connected to API endpoint
}
...
...
#Override
public void onDestroy() {
if(r != null) {
if (r.isPlaying()) {
r.stop();
}
}
poll_handler.removeCallbacks(poll_runnable);
super.onDestroy();
}
}
I found the answer for my questions. The code written in the onStartCommand should be within onCreate function. This is because onCreate will execute when service starts first time, and onStartCommand will execute every time when you start the app. Please follow this topic,
Android - running a method periodically using postDelayed() call
In my application I want use service for get request to server.
I should run this service for always and not stop it!
I write below code in service, but just show for 5 time and when receive to 5 step. then not show Toast!
But I want always getData() and show Toast.
Service class :
public class NotifyService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
//Your logic that service will perform will be placed here
//In this example we are just looping and waits for 5000 milliseconds in each loop.
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(5000);
} catch (Exception e) {
}
if (isRunning) {
ExploreSendData sendData = new ExploreSendData();
sendData.setPageIndex(1);
sendData.setPageSize(10);
sendData.setShowFollows(false);
sendData.setShowMovies(true);
sendData.setShowNews(true);
sendData.setShowReplies(false);
sendData.setShowSeries(true);
sendData.setShowSuggestions(false);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<ExploreResponse> call = api.getExplore(new SharedPrefrencesHandler(NotifyService.this)
.getFromShared(SharedPrefrencesKeys.TOKEN.name()), sendData);
call.enqueue(new Callback<ExploreResponse>() {
#Override
public void onResponse(Call<ExploreResponse> call, Response<ExploreResponse> response) {
if (response.body().getData() != null && response.body().getStatusCode() != 401
&& response.body().getStatusCode() != 402) {
Toast.makeText(NotifyService.this, "Test Show message ever 5second", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ExploreResponse> call, Throwable t) {
}
});
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
I copy this service code from internet, but just show 5times. I want show always.
How can I edit my codes and fix it? Please help me. Thanks
The problem is not in the service, services start and continue living as long as the app is alive and android doesn't kill it. For an infinite loop replace the "for loop" with "While loop". The below loop doesn't end.
while (true) {
......
......
......
}
I am working on below code to run a service in background,but the problem is i am not getting how to run the service indefinitely even though the app is closed,here on press of back my service is stopping.I have read many tutorials but still confused with this.
public class HelloService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
} catch (Exception e) {
}
if (isRunning) {
Log.i(TAG, "Service running");
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
On Android there is NO way (at least for a third party app) to have a never ending process running. The system can always kill your service. So you can use a foreground service but the system can kill your service even in this case (even with low probability). In addition, you should consider that the cpu can go to sleep. So you should take a wakelock but in this way you can kill the user battery so it's not a good solution. My suggestion is to always work "on event" for example with a brodacast receiver that starts a intent service, it does some work and then exit. The always running processes are simply a wrong design choices on Android.
One Way is to use while loop but keep a check i.e
while(true) {
if (condition != true) {
Thread.sleep(time);
} else {
break;
}
}
Can anyone tell me the way to keep a Service always running or restarting itself when the user close it? I've watched that facebook services restart when i clear memory.
I don't want to make ForegroundServices.
You should create a sticky service. Read more about it here.
You can do this by returning START_STICKY in onStartCommand.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
Read also about application:persistent which is "Whether or not the application should remain running at all times". This is more troublesome - System will try not to kill your app which will effect others in the system, you should be careful using it.
I copied this from a service I used in an app I did before.
ITS IMPORTANT TO NOT UPDATE ANY UI. because you have no user interface in services. this applies to Toasts as well.
good luck
public class nasserservice extends Service {
private static long UPDATE_INTERVAL = 1*5*1000; //default
private static Timer timer = new Timer();
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate(){
super.onCreate();
_startService();
}
private void _startService()
{
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
doServiceWork();
}
}, 1000,UPDATE_INTERVAL);
Log.i(getClass().getSimpleName(), "FileScannerService Timer started....");
}
private void doServiceWork()
{
//do something wotever you want
//like reading file or getting data from network
try {
}
catch (Exception e) {
}
}
private void _shutdownService()
{
if (timer != null) timer.cancel();
Log.i(getClass().getSimpleName(), "Timer stopped...");
}
#Override
public void onDestroy()
{
super.onDestroy();
_shutdownService();
// if (MAIN_ACTIVITY != null) Log.d(getClass().getSimpleName(), "FileScannerService stopped");
}
}
I am developing an Android app and I am doing some heavy work (bringing data from an online web page and parsing it to store in database) in a service. Currently, it is taking about 20+ mins and for this time my UI is stuck. I was thinking of using a thread in service so my UI doesn't get stuck but it is giving error. I am using the following code:
Thread thread = new Thread()
{
#Override
public void run() {
try {
while(true) {
sleep(1000);
Toast.makeText(getBaseContext(), "Running Thread...", Toast.LENGTH_LONG).show();
}
} catch (InterruptedException e) {
Toast.makeText(getBaseContext(), e.toString(), Toast.LENGTH_LONG).show();
}
}
};
thread.start();
This simple code is giving run time error. Even If I take out the while loop, it is still not working.
Please, can any one tell me what mistake I am doing. Apparently, I copied this code directly from an e-book. It is suppose to work but its not.
Android commandment: thou shall not interact with UI objects from your own threads
Wrap your Toast Display into runOnUIThread(new Runnable() { });
Example of new thread creation taken from Android samples (android-8\SampleSyncAdapter\src\com\example\android\samplesync\client\NetworkUtilities.java):
public static Thread performOnBackgroundThread(final Runnable runnable) {
final Thread t = new Thread() {
#Override
public void run() {
try {
runnable.run();
} finally {
}
}
};
t.start();
return t;
}
runnable is the Runnable that contains your Network operations.
You can use HandlerThread and post to it, here is an example to service that has one.
public class NetworkService extends Service {
private HandlerThread mHandlerThread;
private Handler mHandler;
private final IBinder mBinder = new MyLocalBinder();
#Override
public void onCreate() {
super.onCreate();
mHandlerThread = new HandlerThread("LocalServiceThread");
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
public void postRunnable(Runnable runnable) {
mHandler.post(runnable);
}
public class MyLocalBinder extends Binder {
public NetworkService getService() {
return NetworkService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
You may define your jobs in a runnable object, use a thread object for running it and start this thread in your service's onStartCommand() function. Here is my notes:
In your service class:
define your main loop in an Runnable object
create Thread object with the runnable object as parameter
In your service class's onStartCommand method():
call thread object's start function()
my code :
private Runnable busyLoop = new Runnable() {
public void run() {
int count = 1;
while(true) {
count ++;
try {
Thread.sleep(100);
} catch (Exception ex) {
;
}
ConvertService.running.sendNotification("busyLoop" + count);
}
}
};
public int onStartCommand(Intent intent, int flags, int startId) {
sendNotification("onStartCommand");
if (! t.isAlive()) {
t.start();
}
return START_STICKY;
}