I am having a weird situation where a Service that is created is stopping - sometimes. I have a entry Activity A that starts a service using bindService
// if we now have an IP address then bind ourselves to the MessageService
bindService(new Intent(this, MessagingService.class),
onMessageService,
BIND_AUTO_CREATE);
The MessageService handles kicking of Read and Send threads to handle message traffic with the app. It basically handles polling for new messages at 1 second intervals using a StatusTask and it's timer using timer.scheduleAtFixedRate.
Activity A then kicks off another Activity B that displays info to the user. For some reason that I yet to figure out, most of the time when I press the home button, the polling stops and the Service seems to have stopped. Reslecting my app from the Home recent apps list or via a notification I post when not visible brings the Activity to the foreground, but the Service seems to be gone. Making this harder to debug, about 10-20% of the time everything works great and the Message Polling service keeps plugging away.
Should I be using startService instead? The only direct relationship that the second Activity B has with the Service is that registers itself as an observer of the Read thread in order to be notified about timeouts on Reads. I am not calling stopService anywhere in my code.
public class Testservice extends Service {
private static final String TAG = Testservice.class.getSimpleName();
public Timer timer;
TimerTask scanTask;
final Handler handler = new Handler();
Timer t = new Timer();
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "Service creating");
_startService();
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "Service destroying");
t.cancel();
t = null;
}
public void yourfunction()
{
}
//this will invoke the function on everysecond basis so try it if it helpsa
public void _startService(){
scanTask = new TimerTask() {
public void run() {
handler.post(new Runnable() {
public void run() {
yourfunction();
}
});
}};
t.schedule(scanTask, 1000L, 1000L);
}
if developing using eclipse ---> try this go to DDMS that will be in the Perspective Option in Menu bar ---> select Logcat and while you are running your application just try to repeat the sequence you just mentioned above and on pressing home button just look at what is the error if at all coming during that instance and post the error so that the specific reason could be understood
Regards,
Mistry Hardik
Starting a service with bbindService makes the service lifecycle tied to the bound activities. Once your activity unbinds from the service, the service dies.
a simple service demo class
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class ServicesDemo extends Activity implements OnClickListener {
private static final String TAG = "AlertService";
Button buttonStart, buttonStop;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.servicedemo);
buttonStart = (Button) findViewById(R.id.btnStart);
buttonStop = (Button) findViewById(R.id.btnStop);
buttonStart.setOnClickListener(this);
buttonStop.setOnClickListener(this);
}
public void onClick(View src) {
switch (src.getId()) {
case R.id.btnStart:
Log.d(TAG, "onClick: starting srvice");
startService(new Intent(this, Testservice.class));
break;
case R.id.btnStop:
Log.d(TAG, "onClick: stopping srvice");
stopService(new Intent(this, Testservice.class));
break;
}
}
}
Related
I have an Android application, which uploads data into web service using async tasks(P,Q,R) currently starting fired in button click. I have three tables(A,B,C) of data. Currently I upload Table A data in doInBackground in first async task(P), I call second async task(Q) in onPostExecute of first async task(P).In onPostExecute, I update my local tables with returned data and give some UI messages as well. while that functionality is existing, now I want to upload data in a fixed time interval(every 30 minutes) even though the application is closed. when the device is booting up/installing app/updating app, this process should be started.While uploading data, if the user opens the application, upload button should be disabled.I don't necessarily need a long running task that runs forever.
1.Do I need to use services instead async tasks?
and give me advice on this.
To Upload Data do as follow
I think you are pretty new to android, Rather than Asynctasks i think you should move to volley or retrofit which is very easy and very fast when compared to Asynctask
Do I need to use services instead async tasks
Since you need to upload data every 30 mins i suggest you move your code to a service within which you will upload data. Also since a service is used it will work when the app is closed also, as it runs in the background
Your Receiver class
import java.util.Timer;
import java.util.TimerTask;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class yourReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
int delay = 5000; // delay for 5 sec.5000
int period = 60000; // repeat every 1min.60000
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
Intent serviceIntent = new Intent(context,UploadService.class);
context.startService(serviceIntent);
}
}, delay, period);
}
}
Your Service Class
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;
public class UploadService extends Service {
MediaPlayer myPlayer;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
myPlayer = MediaPlayer.create(this, R.raw.sun);
myPlayer.setLooping(false); // Set looping
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
serviceThread = new ServiceThread();
serviceThread.start();
}
#Override
public void onDestroy() {
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
myPlayer.stop();
}
private class ServiceThread extends Thread {
#Override
public void run() {
synchronized(UploadService.class){
if(uploadStatus) {
uploadStatus = false;
uploadData();
uploadStatus =true;
}
}
}
}
}
I am having problem with my android IntentService. When I first open the application, the service gets started by intent from the profile activity and data is fetched from this service. If I switch to other activity and then back service is still running and that is ok.
However if you press back, so that activity is finished and put in the background, the service is still working as the application is in background but If I get it back to foreground service stops. I do not know why. Bellow is my code, please help.
I have read activity life cycle couple of times and still do not get it why this is happening.
What is weird is that Service receive data one more time before it stops when MainActivity is brought back to running state. Service is not crashing.
Service
public class SomeService extends IntentService
{
public static final String extra = "someData";
public SomeService()
{
super(SomeService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent)
{
Log.e("SomeService", "starting service");
while (true)
{
SomeData data = Api.getNewSocketData();
//Broadcast data when received to update the view
Intent broadcastData = new Intent();
broadcastData.setAction(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
broadcastData.addCategory(Intent.CATEGORY_DEFAULT);
broadcastData.putExtra(extra, " ");
sendBroadcast(broadcastData);
Log.e("SomeService", "received from socket");
}
}
}
Receiver
public class dataBroadcastReceiver extends BroadcastReceiver
{
public final static String ACTION_DATA_RECEIVED = "net.bitstamp.intent.action.ACTION_SOMEDATA_RECEIVED";
#Override
public void onReceive(Context context, Intent intent)
{
Log.e("receiver", "data received");
}
}
Main Activity
#Override
public void onPause()
{
super.onPause();
unregisterReceiver(dataBroadcastReceiver);
}
#Override
public void onResume()
{
super.onResume();
IntentFilter intentFilter = new IntentFilter(dataBroadcastReceiver.ACTION_DATA_RECEIVED);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
dataBroadcastReceiver = new dataBroadcastReceiver();
registerReceiver(dataBroadcastReceiver, intentFilter);
Intent someService = new Intent(this, SomeService.class);
startService(someService);
}
I really need help on this. Thanks
You don't want to the up the IntentService in an infinite loop. It will block all other incoming requests. From the documentation:
All requests are handled on a single worker thread -- they may take as long as necessary (and will not block the application's main loop), but only one request will be processed at a time.
Your Service is likely still happily running along, it just isn't processing your new request because your old one is still being handled in the infinite loop.
I am working on an app that will relay information about its location to a remote server. I am intending to do it by doing a simple HTTP post to the web-server and all is simple and fine.
But according to the spec, the app needs to execute itself from time to time, lets say once in every 30 mins. Be independent of the interface, meaning which it needs to run even if the app is closed.
I looked around and found out that Android Services is what needs to be used. What could I use to implement such a system. Will the service (or other mechanism) restart when the phone restarts?
Thanks in advance.
Create a Service to send your information to your server. Presumably, you've got that under control.
Your Service should be started by an alarm triggered by the AlarmManager, where you can specify an interval. Unless you have to report your data exactly every 30 minutes, you probably want the inexact alarm so you can save some battery life.
Finally, you can register your app to get the bootup broadcast by setting up a BroadcastReceiver like so:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
// Register your reporting alarms here.
}
}
}
You'll need to add the following permission to your AndroidManifest.xml for that to work. Don't forget to register your alarms when you run the app normally, or they'll only be registered when the device boots up.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Here is a semi-different way to keep the service going forever. There is ways to kill it in code if you'd wish
Background Service:
package com.ex.ample;
import android.app.Service;
import android.content.*;
import android.os.*;
import android.widget.Toast;
public class BackgroundService extends Service {
public Context context = this;
public Handler handler = null;
public static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service created!", Toast.LENGTH_LONG).show();
handler = new Handler();
runnable = new Runnable() {
public void run() {
Toast.makeText(context, "Service is still running", Toast.LENGTH_LONG).show();
handler.postDelayed(runnable, 10000);
}
};
handler.postDelayed(runnable, 15000);
}
#Override
public void onDestroy() {
/* IF YOU WANT THIS SERVICE KILLED WITH THE APP THEN UNCOMMENT THE FOLLOWING LINE */
//handler.removeCallbacks(runnable);
Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show();
}
}
Here is how you start it from your main activity or wherever you wish:
startService(new Intent(this, BackgroundService.class));
onDestroy() will get called when the application gets closed or killed but the runnable just starts it right back up.
I hope this helps someone out.
The reason why some people do this is because of corporate applications where in some instances the users/employees must not be able to stop certain things :)
http://i.imgur.com/1vCnYJW.png
EDIT
Since Android O (8.0) you have to use JobManager for scheduled tasks. There is a library called Android-Job by Evernote which will make periodic background work a breeze on all Android versions. I have also made a Xamarin Binding of this library.
Then all you need to do is the following:
In your application class:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new MyJobCreator());
}
}
Create the following two classes YourJobCreator and YourSyncJob(Where all the work will be done. Android allocates time for all the background jobs to be run. For android versions < 8.0 it will still run with an Alarm manager and background service as per normal)
public class MyJobCreator implements JobCreator {
#Override
#Nullable
public Job create(#NonNull String tag) {
switch (tag) {
case MySyncJob.TAG:
return new MySyncJob();
default:
return null;
}
}
}
public class MySyncJob extends Job {
public static final String TAG = "my_job_tag";
#Override
#NonNull
protected Result onRunJob(Params params) {
//
// run your job here
//
//
return Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(MySyncJob.TAG)
.setExecutionWindow(30_000L, 40_000L) //Every 30 seconds for 40 seconds
.build()
.schedule();
}
}
You should schedule your service with alarm manager, first create the pending intent of service:
Intent ii = new Intent(getApplicationContext(), MyService.class);
PendingIntent pii = PendingIntent.getService(getApplicationContext(), 2222, ii,
PendingIntent.FLAG_CANCEL_CURRENT);
Then schedule it using alarm manager:
//getting current time and add 5 seconds to it
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
//registering our pending intent with alarmmanager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), pi);
this will launch your service after 5 seconds of current time. You can make your alarm repeating.
You can use Alarm Manager to start Service at specified time and then repeat alarm in specified interval. When alarm goes on you can start service and connect to server and make what you want
What I'm trying to do
Hello Guys, I'm trying to create a SplashScreen which starts a Service over an Intent. After the Service is started to Activity(SplashScreen) should wait until it receive an Intent from my Service.
Question
What do I need to do, that my Activity waits until it received the Intent from my Service. It would be nice if you could provide me a good tutorial or some code-snippets.
Down here you find the Code of my SplashScreen.
Code
package de.stepforward;
import de.stepforward.service.VideoService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class SplashActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash);
// Sagt dem Video-Service das er beginnen soll die
// Videos herunter zu laden
Intent LoadVideos = new Intent(this, VideoService.class);
LoadVideos.putExtra("VIDEO_SERVICE", "start");
startService(LoadVideos);
// In this thread I want that it waits for my Intent
// and than it goes to the next Activity
Thread splashThread = new Thread() {
#Override
public void run() {
try {
int waited = 0;
while (waited < 3000) {
sleep(100);
waited += 100;
}
}
catch (InterruptedException e) {
// do nothing
}
finally {
finish();
final Intent Showvideo = new Intent(SplashActivity.this,
ChannelTest.class);
startActivity(Showvideo);
}
}
};
splashThread.start();
}
}
Here is what your architecture should look like :
INTENT_CST
String START_INIT_ACTION = "your.package.name.START_INIT";
String INIT_ENDED_ACTION = "your.package.name.INIT_ENDED";
SplashActivity
In onCreate:
startService(new Intent(START_INIT_ACTION)
In onResume:
If you choose to send a broadcast in your service :
registerReceiver(new BroadcastReceiver(){
//implement onChange()},
new IntentFilter(INIT_ENDED_ACTION));
In onPause, unregister your receiver to free memory
LoadingService
Extend AsyncTask to do your background stuff. In onPostExecute, 2 options :
startActivity(new Intent(...)) // as your doing in your post
or
sendBroadcast(new Intent(INIT_ENDED_ACTION)); stopSelf();
Your manifest
Declare the service LoadingService with an IntentFilter with an <action name="your.package.name.START_INIT"/>
See this link it might be helpful for you. You can monitor your service state from your activity.
Restful API service
starting a service does not affect foreground screen .so launch splashscreen and start service , as you are doing right now . do operations in service, after that start new activity form service itself .
I've created a simple Android application for testing how to use a handler or handlers to pass data from a background Service/thread to some other activity other than the MainActivity that created the background service. I've got the Service, thread, and a handler working in the MainActivity. The last step is to get a handler to pass data to some other activity other than the MainActivity. I can get the Service to pass messages to the MainActivity's handler, but I don't know how to get it to pass data to some other activity.
Why would anyone want to do this? I thought this compared to a simple MP3 player, but what it actually compares to is a nice FM radio. The MainActivity uses a background Service that allows me to select an FM station. When I launch the Play activity it should bind to the same background Service so I can continue to listen while it (the nice part) displays a graphic equalizer or animation of the the audio. Basically, I don't know how to bind to the background Service from more than one activity.
My code was originally based on a Service example page 304 in Pro Android 2 and was helped tremendously by a CommonsWare Sample Application.
Please have a look at my current code. It consists of three carefully commented files that describe what I am trying to do and the difficulties I am having passing data to some other activity in addition to the MainActivity:
/**************************************************************************************************
* File: MainActivity.java
* Application: BackgroundService
* Description: This file contains the main activity that is run when the BackgroundService
* application is launched.
**************************************************************************************************/
package com.marie.mainactivity;
import com.marie.mainactivity.BackgroundService;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/*
* Class: MainActivity
* Purpose: Using a button, the MainActivity class starts the backgroundService and
* the RcvMessages activity. Using another button MainActivity stops the backgroundService.
* NOTE: RcvMessages is only a stub that does nothing but display a simple message.
* Handler: MainActivity defines and provides a reference to "handler" for the backgroundService.
*/
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "starting service");
/*
* The bind button: bindBtn
* Clicking this button starts the background Service and launches the
* RcvMessages activity. NOTE: RcvMessages is only a stub so far.
*/
Button bindBtn = (Button)findViewById(R.id.bindBtn);
bindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// Start the background Service for sending canned messages to the handler as a test.
Intent backgroundService = new Intent(MainActivity.this, com.marie.mainactivity.BackgroundService.class);
backgroundService.putExtra(BackgroundService.EXTRA_MESSENGER, new Messenger(handler));
startService(backgroundService);
// Start the RcvMessages activity to receive messages from the handler. But how???
Intent messages = new Intent(MainActivity.this, com.marie.mainactivity.RcvMessages.class);
startActivity(messages);
}
});
/*
* The unbind button: unbindBtn
* Clicking this button stops the background Service.
*/
Button unbindBtn = (Button)findViewById(R.id.unbindBtn);
unbindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// Stop the background Service
Intent backgroundService = new Intent(MainActivity.this, BackgroundService.class);
stopService(backgroundService);
}
});
}
/*
* This is the handler to be passed to the background Service via a Messenger.
* NOTE: I want it to send messages to my RcvMessages activity.
*/
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// simple handler test (does not send messages to RcvMessages activity
String obj = (String) msg.obj;
Log.i("handleMessge", "obj: " + obj);
}
};
}
/**************************************************************************************************
* File: BackgroundService.java
* Application: BackgroundService
* Description: This file contains the background Service that is launched by the MainActivity's
* bind button.
**************************************************************************************************/
package com.marie.mainactivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
/*
* Class: BackgroundService
* Purpose: Using the onStart() method the BackgroundService gets the reference to the
* Messenger instance that was passed to BackgroundService. The messenger is then
* used by the ServiceWorker() thread to send messages to the handler that is defined
* in the MainActivity class.
*/
public class BackgroundService extends Service {
private NotificationManager notificationMgr;
public static final String EXTRA_MESSENGER = "com.marie.mainactivity.EXTRA_MESSENGER";
private Messenger messenger;
#Override
public void onCreate() {
super.onCreate();
notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
displayNotificationMessage("starting Background Service");
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
}
/*
* This is the ServiceWorker thread that passes messages to the handler defined in
* the MainActivity class.
* NOTE: Instead of passing messages to a handler in MainActivity I would like
* it to pass messages to a handler defined in the RcvMessages activity.
*/
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here... something simple
// send a message to the handler defined in the MainActivity class
try {
Message msg1 = Message.obtain();
msg1.obj = "Hello 1";
messenger.send(msg1);
} catch (RemoteException e) {
e.printStackTrace();
}
// stop the service when done...
// BackgroundService.this.stopSelf();
// Or use the unbindBtn in the MainActivity class.
}
}
#Override
public void onDestroy()
{
displayNotificationMessage("stopping Background Service");
super.onDestroy();
}
/*
* onStart is where we get our reference the Messenger that allows
* us to send messages to the handler defined in the MainActivity class.
*/
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Bundle extras = intent.getExtras();
messenger = (Messenger)extras.get(EXTRA_MESSENGER);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void displayNotificationMessage(String message)
{
Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
notification.setLatestEventInfo(this, "Background Service", message, contentIntent);
notificationMgr.notify(R.id.app_notification_id, notification);
}
}
/**************************************************************************************************
* File: RcvMessages.java
* Application: BackgroundService
* Description: This file contains stub code that displays a test message in an EditText.
**************************************************************************************************/
package com.marie.mainactivity;
import android.app.Activity;
import android.os.Bundle;
import android.text.InputType;
import android.widget.EditText;
/*
* Class: RcvMessages
* Purpose: RcvMessages is stub code that I want to extend in some way to receive messages from
* the background Service.
* NOTE: I don't know who to do this.
*/
public class RcvMessages extends Activity {
EditText myText;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messages);
myText = (EditText)findViewById(R.id.my_text);
myText.setSingleLine();
myText.setInputType(InputType.TYPE_NULL);
// Display a simple test message for now.
myText.setText("RcvMessages here");
}
}
Any help using a background Service, thread, and handler(s) to pass data to some other activity in addition to the MainActivity that created the backgraound Service would be greatly appreciated.
The Handler is associated with specific thread, so for as long as you create it in UI thread all you need to do is to share the handler. I would put your handler in my Application class. And you can put the whole Messenger there, if you want. Then you can access handler in any activity via ((MyApplication)getApplication()).getHandler(). When activity starts or pauses, you can register it as a callback.
So something like this
public class MyApplication extends Application {
Handler h = new Handler() {
public void handleMessage(Message m) {
if (realCallback!=null) {
realCallback.handleMessage(m);
}
}
};
Handler.Callback realCallback=null;
......
public Handler getHandler() {
return h;
}
public void setCallback(Handler.Callback c) {
realCallback = c;
}
}
In any activity that needs to do receive requests via messenger
public class MyActivity extends Activity implements Handler.Callback
......
public void onStart() {
((MyApplication)getApplication()).setCallback(this);
}
public void onPause() {
((MyApplication)getApplication()).setCallback(null);
}
public void handleMessage(Message msg) {
//.... Do stuff ....
}
}
This is just an idea. You may need to tune it to your needs.
And don't forget to set MyApplication name in AndroidManifest.xml