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.
Related
I am building a game where I want the user to go through many activities in 20 seconds. Once the 20 seconds is over, I want to send the user to the GameOver screen. To run the timer in the background, I used a service. The issue is, the service doesn't seem to be running?
The weird thing is, that even the toast isn't showing. Here is the place where I call the service:
Here is the manifest:
Please let me know as to why the service or the timer aren't running. Thank you so much for all of your help, I really appreciate it! If you need any more code, just let me know and I will show you. Thanks!
:-)
{Rich}
Services can't interact with UI, which is what Toast does. If you want to do that, try using runOnUIThread along with getApplicationContext or the fancy way with binding/callbacks. Also, take a look at AlarmManager, might be a simpler solution instead of running a service.
BroadcastReciever should be a solution to get and to show the toasts. Just send the message from service and catch it in activity. Then use it wherever you want.
//Service class
final static String ACTION = "ACTION";
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
intent = new Intent();
intent.setAction(ACTION);
intent.putExtra("StartToast", "Started!");
sendBroadcast(intent);
return START_STICKY;
}
//Activity class
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(MainActivity.this, ServiceClass.class);
myReceiver = new MyReceiver();
intentFilter = new IntentFilter();
intentFilter.addAction(ServiceClass.ACTION);
registerReceiver(myReceiver, intentFilter);
}
private class MyReceiver extends BroadcastReceiver {
public String startToast;
#Override
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
startToast = arg1.getStringExtra("StartedToast");
Toast.makeText(MainActivity.this, startToast, Toast.LENGTH_SHORT).show();
}
Once you register this receiver, you get the message and create a toast automatically when you send data with intent.putExtra(....); .
I am working on using the LocalBroadcastReceiver to send messages from an IntentService to an activity. I have a basic activity all the activities in my project inherit from that contains the activity code below. And a basic IntentService that is initialized by a WakefulBroadcastReceiver that contains the service code below.
In my activity I have:
#Override
protected void onCreate(Bundle savedInstanceState) {
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter("push-message"));
super.onCreate(savedInstanceState);
}
#Override
protected void onPause(){
LocalBroadcastManager.getInstance(this).unregisterReceiver(
mMessageReceiver);
super.onPause();
}
#Override
protected void onResume(){
super.onResume();
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter("push-message"));
}
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
And in my service I have:
public class SimpleMessagerService extends IntentService {
public SimpleMessagerService() {
super("SimpleMessagerService");
}
#Override
protected void onHandleIntent(Intent intent) {
Intent newintent = new Intent("push-message");
// You can also include some extra data.
String message = intent.getExtras().getString("message");
newintent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
}
The service onHandleIntent is being triggered, and when I put a break point in it and evaluate the expression: LocalBroadcastManager.getInstance(this); I can see the mMessageReceiver in the mReceivers list; however when I put a breakpoint in mMessageReceiver's onReceive, I find that it is never being triggered.
More info:
It seems my service cannot actively do anything when it is called, but does not throw an exception. I tried saving my current context in the application file and throwing up a toast message from the service. The process seems to succeed, but the toast message never appears. This is what I have in the manifest for the service:
<service
android:name="packagename.services.SimpleMessagerService"
android:exported="false">
</service>
turns out a couple things where wrong. First exported needed to be true in the manifest. Second, because the service is an Intent service it operates in a different thread than the main activities, so in order to send a broadcast to them I have to make it look something like:
Handler mHandler = new Handler(getMainLooper());
mHandler.post(new Runnable() {
#Override
public void run() {
Intent newintent = new Intent("push-message");
newintent.putExtra("message", message);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(newintent);
}
});
So the main thread is hit. I hope this helps someone else with the same problem.
I'd like to credit rubenlop88 in the for posting this solution for a similar problem in the thread,
java.lang.RuntimeException: Handler (android.os.Handler) sending message to a Handler on a dead thread
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 have written a simple activity to test out services and broacast receivers and a service to go along with it. In order to know whether or not it's working I've set up a Toast within the main activity to be showed once the OnReceive() method is called. But for the life of me I can't get this to work.
These are the codes:
public class ServicesAndBroadcastIntentActivity extends Activity {
private Toast test;
private Intent intent;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
intent = new Intent(this,serviceD.class);
test = Toast.makeText(this,"Test",Toast.LENGTH_LONG);
test.setGravity(Gravity.CENTER,0,0);
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
test.setText((intent.getStringExtra("EXTRA_MSG")));
test.show();
}
};
#Override
public void onResume(){
super.onResume();
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(serviceD.BROADCAST_ACTION));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
}
public class serviceD extends Service{
private Intent intent;
static final String BROADCAST_ACTION = "com.mejg.ServicesAndBroadcastIntent";
public void onCreate() {
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
}
public void onStart(){
intent.putExtra("EXTRA_MSG","hola");
sendBroadcast(intent);
stopSelf();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
You are calling startService() before registerReceiver(). Both are asynchronous operations, but they will still likely occur in sequence. Hence, onStart() of your service will be called before registerReceiver() does its work, which means your broadcast goes out before your receiver is set up.
For this sort of experimentation, I recommend setting up a basic UI (e.g., one really big button) and doing the startService() call when the button is pressed.
Also, since the service calls stopSelf(), you do not need to call stopService() from the activity.
Also also, you might consider using LocalBroadcastManager for this -- same basic syntax with better performance and security, since it all stays within your process.
UPDATE
Also also also, onStart() has been deprecated for two-plus years, and your method signature for it is wrong, anyway. Please use onStartCommand(), with the right parameters.
Also also also also, use #Override when overriding methods, to help you catch these sorts of problems.
When i have a broadcastReceiver say android.intent.action.MEDIA_BUTTON and i want to update the current activity's UI without creating a new activity, is there any good practice on this one?
What i know (might not be correct)
1) I can put the BroadcastReceiver in the same class as the activity and call the updateUI function after certain activity
2) Create a ContentObserver?
3) Communicate to a service created by the activity, use aidl. (I dont know how to get the current service if its registered from an activity)
4) Create a custom filter on the broadcastReceiver located on the same class as the activity, and use context.sendBroadcast(msg of custom filter) and in the custom filter call updateUI (same as one but more generic?)
The final flow is it would come from a BroadcastReceiver and ends up updating the UI without renewing the activity (unless the activity is dead?)
Kindly provide links/source code on your how you tackle this kind of problem. Thanks a lot in advance :)
The easiest way to provide this functionality is to put the broadcast receiver in you Activity and bind / unbind it using registerReceiver and unregisterreceiver:
public class MyActivity extends Activity {
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.this.receivedBroadcast(intent);
}
};
#Override
public void onResume() {
super.onResume();
IntentFilter iff = new IntentFilter();
iff.addAction("android.intent.action.MEDIA_BUTTON");
// Put whatever message you want to receive as the action
this.registerReceiver(this.mBroadcastReceiver,iff);
}
#Override
public void onPause() {
super.onPause();
this.unregisterReceiver(this.mBroadcastReceiver);
}
private void receivedBroadcast(Intent i) {
// Put your receive handling code here
}
}
Depending on the intent you wish to receive, you may need to add the appropriate permissions to your AndroidManifest.xml file.
What I recently had to do to change a Button's text after receiving data from a LocalBroadcastManager is to store the value in a private field and then do the UI stuff in my onResume() method.
public class myClass extends Activity {
private String myString;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// register to receive data
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(receiver, new IntentFilter("myAction"));
}
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// get the extra data included in the intent
myString = intent.getStringExtra("myString");
}
};
#Override
public void onResume() {
super.onResume();
System.out.println("onResume");
// do something to the UI
myButton.setText(myString != null ? myString : "Default");
}
}