In the Google's In App Billing example(Dungeons) there is a Service instance created in main Activity onCreate:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHandler = new Handler();
mDungeonsPurchaseObserver = new DungeonsPurchaseObserver(mHandler);
mBillingService = new BillingService();
mBillingService.setContext(this);
....
}
and in the receiver the service is started by the context.startService.
private void notify(Context context, String notifyId) {
Intent intent = new Intent(Consts.ACTION_GET_PURCHASE_INFORMATION);
intent.setClass(context, BillingService.class);
intent.putExtra(Consts.NOTIFICATION_ID, notifyId);
context.startService(intent);
}
Will notify use somehow the some instance created in onCreate or it will create another instance of this class running as an actual service?
What do you mean by "allways one instance"? Is that important?
As far as I know, when receiver get it, It starts the service and check the user has actually bought it (i.e. get purchase info). After the service has completed, it send a broadcast message to you, so that you can act accordingly. I don't think that it runs always in the background.
Related
I'm working on a Android APP. There's a main activity and a service. The service is started by calling startService(intent) in main activity. and it would be running in background no matter the activity is running or not. After the activity is created, it will send broadcast message to service to query some status. The first time of the running is okay, both activity and service initiated correctly. But I get an issue that when I quit the activity and restart it, the service will keep receiving the query message like the activity is sending it repeatedly. But I confirmed the sending code in activity was only executed once. Anyone have idea where the messages comes from?
the codes in main activity onCreate method
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("debug", "Main.onCreate");
Intent intent=new Intent(MainActivity.this, PingService.class);
startService(intent);
Intent intent = new Intent(PingService.ACTION_QUERY);
sendBroadcast(intent);
}
And below are codes in service
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(PingService.ACTION_QUERY)) {
Log.v("debug", "PingService.receiver.onReceive: ACTION_QUERY");
//the program keeps coming here
}
}
};
#Override
public void onCreate() {
Log.v("debug", "PingService.onCreate");
HandlerThread thread = new HandlerThread("pingd",
android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
//handlers
serviceHandler = new ServiceHandler();
daemonHandler = new DaemonHandler(thread.getLooper());
//register broadcast receiver
IntentFilter filter = new IntentFilter();
filter.addAction(PingService.ACTION_ADD);
filter.addAction(PingService.ACTION_QUERY);
filter.setPriority(999);
registerReceiver(receiver, filter);
instance = this;
}
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 need to send some data to my service on app startup. I put data to Intent, cast sendBroadcast(intent) in onCreate method of my activity. So my service doesn't receive any intents.
But if i use Handler.post with custom Runnable in onCreate everything works fine.
Can someone explain me such a strange behavior?
Doesn't work at all:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastIntent = new Intent(BROADCAST);
broadcastIntent.putStringArrayListExtra("URLs", alURLS);
sendBroadcast(broadcastIntent);
}
Works perfectly:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
broadcastIntent = new Intent(BROADCAST);
broadcastIntent.putStringArrayListExtra("URLs", alURLS);
hDelayedPost = new Handler();
hDelayedPost.post(rHandleDelayedSendBroadcast);
}
private Runnable rHandleDelayedSendBroadcast = new Runnable() {
#Override
public void run() {
sendBroadcast(broadcastIntent);
}
};
So my service doesn't receive any intents
Services do not receive broadcasts. BroadcastReceivers receive broadcasts.
UPDATE: Presumably, your Service is not yet running in onCreate() of your activity, and you are calling startService() sometime between onCreate() and when your delayed sendBroadcast() is called.
I have a ContentProvider which fetches data from sqlite database and loads it via Loader. It's updated by a Service which runs an AsyncTask to download data from server and update it in the ContentProvider. I hope it's clear but to be sure:
ListFragment takes data from ContentProvider via Loader,
ContentProvider gets updated with a Service.
Now, when my local sqlite database is empty the first time I launch the app, it shows that it has no events, even though they're being currently downloaded via Service. I would rather have a ProgressBar shown at this moment (the infinite spinning wheel, not a bar). But if I show a ProgressBar when there are no results from database, it would be there even after fetching data from sever in this specific case when there are no records in the external database (and it occurs quite often in my case). So:
When the data is downloaded for the first time by the Service I
would like to show a ProgressBar until ContentProvider gives
non-empty result OR the Service finished it's job.
When ContentProvider returned nothing AND Service finished
it's job (and fetched empty result) I would like the app to show
"no results found".
My problem is probably: how to notify the ListFragment that the Service is still running or that it finished ts job. I mean - I shouldn't store any reference to the calling Fragment inside the Service. It goes against the idea of ContentProviders, doesn't it? So how?
Note: I don't really know which fragment of code would be helpful here, so if you feel that you need to see some specific frag, just tell me in comments. Thanks!
Since you're not so much interested in posting actual progress back to the UI, the simplest way to implement this would be using a pair of custom broadcasts, and maybe a static boolean to show run state as well.
Basically, your service can notify any component of your application that's interested when it is beginning a download and when it has finished it. So you can define two custom action strings:
public static final String ACTION_DOWNLOADSTART = "com.mypackage.intent.ACTION_DOWNLOADSTART";
public static final String ACTION_DOWNLOADCOMPLETE = "com.mypackage.intent.ACTION_DOWNLOADCOMPLETE";
Then have your service broadcast them at the proper points in the code:
Intent start = new Intent(ACTION_DOWNLOADSTART);
sendBroadcast(start);
//...Service does its work
Intent finish = new Intent(ACTION_DOWNLOADCOMPLETE);
sendBroadcast(finish);
You can register for these callbacks anywhere in your application with a BroadcastReceiver and act accordingly (i.e. check the status of the ContentProvider and show/hide progress if necessary).
Another common practice, if you want to be able to check if a Service is running at any given point, is simply to include a private static boolean member that you can toggle when the Service is active (perhaps between onCreate()/onDestroy() but perhaps elsewhere) and an accessor method like isRunning(). Then your application can also check at any time if the Service is running by just calling that method.
There are various techniques how to communicate between Fragment / Activity and a Service.
One of them is using ResultReceiver and sending it to IntentService in Intent extra.
You create custom receiver ServiceResultReceiver extending ResultReceiver.
public class ServiceResultReceiver extends ResultReceiver {
private Receiver mReceiver;
public ServiceResultReceiver(Handler handler) {
super(handler);
}
public void setReceiver(Receiver receiver) {
mReceiver = receiver;
}
public interface Receiver {
public void onReceiveResult(int resultCode, Bundle resultData);
}
#Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (mReceiver != null) {
mReceiver.onReceiveResult(resultCode, resultData);
}
}
}
Make your Fragment implement ServiceResultReceiver.Receiver interface. Create receiver
and initialize it to your Fragment. You than pass the receiver to service and in service just get the receiver from intent and call receiver.send() to send anything back to the receiver.
public class MyFragment extends ListFragment implements ServiceResultReceiver.Receiver {
private ServiceResultReceiver mReceiver;
....
#Override
public void onCreate(Bundle savedInstanceState) {
...
mReceiver = new ServiceResultReceiver(new Handler());
mReceiver.setReceiver(this);
}
public void startMyService() {
final Intent intent = new Intent(getActivity(), MyService.class);
intent.putExtra("receiver", mReceiver);
getActivity().startService(intent);
}
#Override
public void onReceiveResult(int resultCode, Bundle resultData) {
// service finished
}
}
public class MyService extends IntentService {
...
#Override
protected void onHandleIntent(Intent intent) {
// download data and update database
....
final ResultReceiver receiver = intent.getParcelableExtra("receiver");
if (receiver != null) {
receiver.send(0, null);
}
}
}
I have a main activity that launches:
1.- A network prone thread that writes into a socket.
2.- A network prone service that is supposed to read from a socket.
So far I'm done with 1. but I want the information read from the socket to be shown in the main activity. I know I can pass information between the activity and the service using extras but how can I tell the activity to update and get the new data?
I guess that you could use broadcasting intents combined with a BroadcastReceiver in your main activity in order to achieve background communication.
Here's a snippet that can achieve this.
(CODE PUT IN THE ACTIVITY):
class MyActivity extends Activity{
CustomEventReceiver mReceiver=new CustomEventReceiver();
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
/*YOUR ONCREATE CODE HERE*/
/*Set up filters for broadcast receiver so that your reciver
can only receive what you want it to receive*/
IntentFilter filter = new IntentFilter();
filter.addAction(CustomEventReceiver.ACTION_MSG_CUSTOM1);
filter.addCategory(Intent.CATEGORY_DEFAULT);
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy(){
super.onDestroy();
/*YOUR DESTROY CODE HERE*/
unregisterReceiver(mReceiver);
}
/*YOUR CURRENT ACTIVITY OTHER CODE HERE, WHATEVER IT IS*/
public class CustomEventReceiver extends BroadcastReceiver{
public static final String ACTION_MSG_CUSTOM1 = "yourproject.action.MSG_CUSTOM1";
#Override
public void onReceive(Context context, Intent intent){
if(intent.getAction().equals(ACTION_MSG_CUSTOM1)){
/*Fetch your extras here from the intent
and update your activity here.
Everything will be done in the UI thread*/
}
}
}
}
Then, in your service, you simply broadcast an intent (with whatever extras you need)... Say with something like this:
Intent tmpIntent = new Intent();
tmpIntent.setAction(CustomEventReceiver.ACTION_MSG_CUSTOM1);
tmpIntent.setCategory(Intent.CATEGORY_DEFAULT);
/*put your extras here, with tmpIntent.putExtra(..., ...)*/
sendBroadcast(tmpIntent);
One option could be to write the output of the socket reader to a stream - a file stored in the app's internal storage for example, and then periodically poll that file in the activity thread.