Access my own Service methods from Activity - android

I have a method in a service that I created, and I want to access this method from an Activity that implements a Progress Dialog. This method simply update my database, and it was returning an ANR problem, so I created a Thread and in this thread I want to call this method that is in my Service. I tried instantiating the Service, but the object is null
So, how to create an 'object' in my activity where I can access this method. Someone could help me with that implementation??
Thanks.
The code:
public class UpdateDBProgressDialog extends Activity {
private String LOG_TAG = "UpdateDBProgressDialog";
private TextView tv;
private ProgressDialog pd;
private Handler handler;
private RatedCallsService rcs;
private Intent intent;
public boolean mIsBound = false;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
pd = ProgressDialog.show(this, "Updating Database", "The application is updating the database. Please wait.", true, false);
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
}
};
Thread thread = new Thread(){
public void run() {
try{
rcs.updateDB();// Here I'm trying to call the method that is from the service class. But it says 'rcs' is null.
handler.sendEmptyMessage(0);
}catch(Exception e){e.printStackTrace();}
}
};
thread.start();
new Thread(){
public void run(){
try{
Thread.sleep(10000);
if(!RatedCallsService.RUNNING){
Intent i = new Intent(UpdateDBProgressDialog.this, RatedCallsService.class);
UpdateDBProgressDialog.this.startService(i);
}
}catch(Exception e){e.printStackTrace();}
}}.start();
}
}
I just want an object of the service so I can call the method I created there.

When you start or bind a Service its onCreate method calls and whenever you Start/Bind it again, its onStartCommand method will call. Because service is already created.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if (action.equals(ACTION_PLAY)) // where ACTION_PLAY="any.unique.name.play"
processPlayRequest();
else if (action.equals(ACTION_PAUSE)) // where ACTION_PAUSE="any.unique.name.pause"
processPauseRequest();
else if (action.equals(ACTION_SKIP))
processSkipRequest();
else if (action.equals(ACTION_STOP))
processStopRequest();
else if (action.equals(ACTION_REWIND))
processRewindRequest();
else if (action.equals(ACTION_URL))
processAddRequest(intent);
return START_NOT_STICKY; // Means we started the service, but don't want
// it to
// restart in case it's killed.
}
And call it like:
Intent serviceIntent = new Intent(this, ServiceToStart.class);
serviceIntent.setAction("any.unique.name.play"); // onClick of play button
startService(serviceIntent);

If you want to invoke an operation on a Service from an Activity, there are two options. One is to create an Intent with any data set as extras on the Intent, and then start the Service kind of like you have done in the code. Then in the Service's onStartCommand, pull out the extras and invoke the appropriate method on your Service. For this option, you probably want to use an IntentService. The other option is to bind to the Service and directly invoke methods on it. To do this you will need to declare your Service's operations using AIDL. See the API documentation on Service for details.

Related

How to dismiss progress dialog from service?

I have an activity and it shows progress dialog when the user starts download
And the download from ftp start in a service
I want to dismiss this progress dialog when the service finishes downloading file
How to dismiss it from service?
A better approach would be to use LocalBroadcastManager for notifying Activity from Service.
Step1: Send the local broadcast from your service
public class MyService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// do your operation here(create worker thread for blocking operations)
sendLocalBroadCast() //call this method as soon as above operations completes
return Service.START_NOT_STICKY;
}
}
private void sendLocalBroadCast() {
Intent intent = new Intent("MY_SERVICE_NOTIFICATION");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
Note that the system calls onStartCommand(Intent intent, int flags, int startId) on your service's main thread. A
service's main thread is the same thread where UI operations take
place for Activities running in the same process. You should always
avoid stalling the main thread's event loop. When doing long-running
operations, network calls, or heavy disk I/O, you should kick off a
new thread, or use AsyncTask
Step2: Make your Activity listen to this broadcast
public class MyActivity extends Activity{
BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// you can dismiss your progress dialog here. This method will be called when we receive broadcast from service after the service operation is completed
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
//register for listening to "MY_SERVICE_NOTIFICATION" event
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver,
new IntentFilter("MY_SERVICE_NOTIFICATION"));
}
#Override
protected void onDestroy() {
super.onDestroy();
// remove the receiver
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
}
}
Create an interface finishListener which has listen method, implement it in the activity to do whatever you want and pass it to the service constructor from there call listen method
Its simple
alertdialog.dismiss();
just put that in the bottom of your install code

Android: make call service thread-safe

I have a loop which do call to service:
context.startService(intent);
In and want to get back the result after the service finish its processing for each request. So I pass an unique id to intent to be able to distinguish the response.
But unfortunately, the startService which call to onStartCommand is not thread-safe. This leads to the response is always the last id, as the intent was changed in later call.
The service code is similar:
public class MyService extends Service {
protected Bundle rcvExtras;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
rcvExtras = intent.getExtras();
// Todo with information in rcv Extra
BaseRestClient restClient = new BaseRestClient(rcvExtras.getString(Constants.INTENT_KEY_OBJECT_TYPE));
restClient.post(data, rcvExtras.getString(Constants.INTENT_KEY_URL), new CallBackHandler(this)); // This is an async call
return super.onStartCommand(intent, flags, startId);
}
private class CallBackHandler extends Handler {
private final WeakReference<MyService> myServiceRef;
public CallBackHandler(MyService myService) {
myServiceRef = new WeakReference<>(myService);
}
#Override
public void handleMessage(Message msg) {
Intent result = new Intent(Constants.WS_CALL_BACK);
rcvExtras.putInt(Constants.INTENT_KEY_STATUS, msg.what);
result.putExtras(rcvExtras);
log.info("Broadcast data");
sendBroadcast(result); // Broadcast result, actually the caller will get this broadcast message.
MyService myService = myServiceRef.get();
log.info("Stopping service");
myService.stopSelf(startId);
}
}
}
How can I make service calling thread-safe?
I can see your problem, this is programatic issue not caused by framework. Here from you call startService until you call stopself, your MyService is singleton, and your rcvExtras is a global variable and will be shared between threads.
It is simple to fix:
Move the declaration of rcvExtras to method scope, here is onStartCommand.
Extend the CallBackHandler to allow your rcvExtras, and use it once callback.
At this time you do not have any varable can be shared, and you safe.
Hope this help.

app forceclose while running in background

In my android app i have one service which calls some webservices after a fix interval.
App is running perfectly in foreground and refresh data,but when user exit from app and use some other app then my app force close after many times.
Why this app force close while running in background.
Code that i was using for start service -
msgIntent = new Intent(mContext, MyBackgroundService.class);
startService(msgIntent);
and inside onDestroy() of my main activity i have following code to stop service-
if(msgIntent!=null){
stopService(msgIntent);
}
background service call some async task and each aync task onPostExecute() method execute some insert statement in database.
i am not geting why this force close occure.
Please give your comments.
Thanks in advance.
My Service Code
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
callAsynchronousTask();
return Service.START_NOT_STICKY;
}
#Override
public void onCreate() {
mContext = this;
super.onCreate();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
public void callAsynchronousTask() {
final Handler handler = new Handler();
Timer timer = new Timer();
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
try {
callWebservice();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
};
timer.schedule(doAsynchronousTask, START_DELAY, DELAY);
}
Actually the problem is here
if(msgIntent!=null){
stopService(msgIntent);
}
in your onDestroy(). Because when you close your application so this above code gets called which is closing your service.
And after closing service again you are trying to insert data by calling service + web service. Hence, there is no service object thats why it gets crashed.
To handle this scenario, you need to comment above code which is in onDestroy() & then check/run it, will solve your problem. & there you need to stop your service by other ways. Go step by step.
you stop the service at onDestroy() method. but services are not depend the activity. So try to neglect the stop service.
(or)
try
{
//stop service code
}
catch(Exception e)
{
}
try this.

Android IntentService update loop

My intention is to have download service created when the app first runs and checks for update every 24 hours. I originally had everything running my main activity but it seems to much to run everything on one thread and one class. So this is my attempt to move it to another class and into service. It suppose to run and check for an update ever 24 hours and if there is no internet try again in 4 hours. I specifically want to involve any recursive problems, having two or three same services checking update, just one every 24 hours. But having problem with integrating my code into service, what am I doing wrong?
public class DownloadService extends IntentService {
// TODO 0 - Define your Download Service as Android component in
// AndroidManifest.xml
private int result = Activity.RESULT_CANCELED;
public DownloadService() {
super("DownloadService");
}
// Will be called asynchronously be Android
#Override
protected void onHandleIntent(Intent intent) {
private final Runnable mUpdateUi = new Runnable(){
public void run(){
check();
}
};
private void start(){
new Thread(
new Runnable(){
public void run(){
Log.d(TAG, "inside start");
Looper.prepare();
mHandler = new Handler();
check();
Looper.loop();
}
}
).run();
}
private void check(){
if (isNetworkAvailable()== true){
try {
new checkupdate().execute();
delayTime = 86400000;
Toast.makeText(DownloadService.this, "Daily update check!", Toast.LENGTH_SHORT).show();
}
catch (IOException e) {
e.printStackTrace();
delayTime = 21600000;
}
}else{
delayTime = 21600000;
Toast.makeText(DownloadService.this, "No internet for Daily update check, try again in little!", Toast.LENGTH_SHORT).show();
}
reCheck();
}
private void reCheck(){
mHandler.postDelayed(mUpdateUi, delayTime);
}
}
IntentService already handles setting up a worker thread and queue, and termination when the queue is empty. Which makes it a very good candidate for something like a download service to manage the actual work of downloading data, but not really a great candidate for a time scheduler.
I'd suggest using an AlarmManager to schedule your work instead. What you want is to trigger an Intent to start your DownloadService, by sending it intent with an Action indicating what to do.
Note also that if you want to cancel an IntentService with an Action, you will need to implement onStartCommand in addition to the usual onHandleIntent, so that you can respond to the action immediately -- you cannot do this from onHandleIntent, since the intent won't be sent to that until the current task in the queue is completed. Here's a quick example:
public class DownloadService extends IntentService {
private static final String TAG = "DownloadService";
////////////////////////////////////////////////////////////////////////
// Actions
public static final String ACTION_CANCEL = "package.name.DownloadService.action.CANCEL";
public static final String ACTION_DOWNLOAD = "package.name.DownloadService.action.DOWNLOAD";
////////////////////////////////////////////////////////////////////////
// Broadcasts
public static final String BROADCAST_DOWNLOADED = "package.name.DownloadService.broadcast.DOWNLOADED";
public static final String BROADCAST_ERROR = "package.name.DownloadService.broadcast.ERROR";
////////////////////////////////////////////////////////////////////////
// Extras
public static final String MESSAGE = "package.name.DownloadService.extra.MESSAGE";
// etc.
private boolean isCancelled;
// usual stuff omitted
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent != null) {
String action = intent.getAction();
Log.v(TAG, "onStartCommand() - action: "+action);
if(ACTION_CANCEL.equals(action)) {
isCancelled = true;
// insert code here to signal any objects to cancel
// their work, etc.
stopSelf();
}
}
return super.onStartCommand(intent, flags, startId);
}
#Override
protected void onHandleIntent(Intent intent) {
if(intent != null) {
final String action = intent.getAction();
Log.v(TAG, "onHandleIntent() - action: "+action);
if(ACTION_DOWNLOAD.equals(action)) {
handleDownloading(intent);
}
else if(ACTION_CANCEL.equals(action)) {
// nothing to do here, handled in onStartCommand
}
}
}
////////////////////////////////////////////////////////////////////
private void handleDownloading(Intent intent) {
// get stuff you need from the intent using intent.getStringExtra(), etc.
if(!isCancelled) {
// do downloading, call broadcastDownloaded() when done
}
else {
// stop work, send broadcast to report cancellation, etc.
}
}
// send a broadcast to a BroadcastReceiver (e.g. in your activity)
// to report that the download completed
private void broadcastDownloaded() {
Log.v(TAG, "broadcastDownloaded()");
Intent broadcastIntent = new Intent();
if (broadcastIntent != null) {
broadcastIntent.setAction(BROADCAST_DOWNLOADED);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
}
}
private void broadcastError(String message) {
Log.v(TAG, "broadcastError(), message: "+message);
Intent broadcastIntent = new Intent();
if (broadcastIntent != null) {
broadcastIntent.setAction(BROADCAST_ERROR);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
if(message != null) {
broadcastIntent.putExtra(MESSAGE, message);
}
sendBroadcast(broadcastIntent);
}
}
}
This is not how IntentService is meant to be used. As per the documentation, IntentService already creates its own worker threads. You should not be creating your own:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Apart from the fact that your code as shown here won't compile (your start method is inside the onHandleIntent method), your general approach seems to be to start your own worker thread. What would happen in this approach is that you would start the thread, onHandleIntent would complete and then the service would be stopped. In addition to not actually working, this approach is also a bad idea because (at best if you're lucky) the service would be running continually 24/7.
What you should do instead is actually do your main work in onHandleIntent which IntentService will queue on a worker thread for you. Then instead of using postDelayed use AlarmManager to set an alarm to send an Intent to start the service again in 24 hours or 4 hours.

Handler will not be called in my activity

I created a Handler in my activity. The handler will be stored in the application object.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.action_activity);
appData = (AttachApplication) getApplication();
Handler updateHandler = new Handler() {
public void handlerMessage(Message msg) {
Log.d( TAG, "handle message " );
}
};
appData.setUpdateHandler( updateHandler );
}
My plan is that this handleMessage will be called when i setEmtpyMessage in my service. The service retrieves the handler from the application object.
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand of attachService");
List<Job> jobList = DBManager.getInstance().getAllOpenJobs();
appData = (AttachApplication) getApplication();
updateHandler = appData.getUpdateHandler();
updateHandler.sendEmptyMessage( 101 );
I checked the logs, but there is no handle message so that it seems that my plan does not work. I want to update a textfield each time my service did its job.
In Your case You shoild use BroadcastReceiver like this:
define receiver in your Activity class:
public class DataUpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(MainService.REFRESH_DATA_INTENT)) {
//do something
}
}
}
on your onCreate or onStart method you must register receiver:
DataUpdateReceiver dataUpdateReceiver = new DataUpdateReceiver();
IntentFilter intentFilter = new IntentFilter(MainService.REFRESH_DATA_INTENT);
registerReceiver(dataUpdateReceiver, intentFilter);
on your service add this:
public static final String REFRESH_DATA_INTENT = "done";
and when you done all staff you must send brocast like this:
sendBroadcast(new Intent(MainService.REFRESH_DATA_INTENT));
Your code snippet says public void handlerMessage(Message msg), but I think you mean public void handleMessage(Message msg), without the r. You can avoid these problems by using the #Override tag when you intent to override methods from a superclass; so your snippet would be rendered #Override public void handleMessage(Message msg), whereas #Override public void handlerMessage(Message msg) would be an error.
What are you trying to do? I really don't see the point of instantiating a Handler in an Activity, since all you're doing is getting Messages from the MessageQueue. You certainly don't want to fool around with any of the Messages that Android posts, and there are much better ways of sending messages to the Activity.
Of course, you don't include the code for AttachApplication, so I can only speculate.
You're also trying to access this Handler from a Service. Something is going on, but I'm not sure what.
If you want to update a TextView every time your Service does its job, send a broadcast Intent from the Service to the Activity, and use a broadcast receiver in the Activity. You should also consider using an IntentService instead of a Service.

Categories

Resources