I am trying some thing new on Android for which I need to access the handler of the UI thread.
I know the following:
The UI thread has its own handler
and looper
Any message will be put
into the message queue of the UI
thread
The looper picks up the event
and passed it to the handler
The handler handles the message and
sends the specfic event to the UI
I want to have my service which has to get the UI thread handler and put a message into this handler.
So that this message will be processed and will be issued to the UI.
Here the service will be a normal service which will be started by some application.
I would like to know if this is possible.
If so please suggest some code snippets, so that I can try it.
Regards
Girish
This snippet of code constructs a Handler associated with the main (UI) thread:
Handler handler = new Handler(Looper.getMainLooper());
You can then post stuff for execution in the main (UI) thread like so:
handler.post(runnable_to_call_from_main_thread);
If the handler itself is created from the main (UI) thread the argument can be omitted for brevity:
Handler handler = new Handler();
The Android Dev Guide on processes and threads has more information.
Create a Messenger object attached to your Handler and pass that Messenger to the Service (e.g., in an Intent extra for startService()). The Service can then send a Message to the Handler via the Messenger. Here is a sample application demonstrating this.
I suggest trying following code:
new Handler(Looper.getMainLooper()).post(() -> {
//UI THREAD CODE HERE
});
At the moment I prefer using event bus library such as Otto for this kind of problem. Just subscribe the desired components (activity):
protected void onResume() {
super.onResume();
bus.register(this);
}
Then provide a callback method:
public void onTimeLeftEvent(TimeLeftEvent ev) {
// process event..
}
and then when your service execute a statement like this:
bus.post(new TimeLeftEvent(340));
That POJO will be passed to your above activity and all other subscribing components. Simple and elegant.
You can get values through broadcast receiver......as follows, First create your own IntentFilter as,
Intent intentFilter=new IntentFilter();
intentFilter.addAction("YOUR_INTENT_FILTER");
Then create inner class BroadcastReceiver as,
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
/** Receives the broadcast that has been fired */
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction()=="YOUR_INTENT_FILTER"){
//HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
String receivedValue=intent.getStringExtra("KEY");
}
}
};
Now Register your Broadcast receiver in onResume() as,
registerReceiver(broadcastReceiver, intentFilter);
And finally Unregister BroadcastReceiver in onDestroy() as,
unregisterReceiver(broadcastReceiver);
Now the most important part...You need to fire the broadcast from wherever you need to send values..... so do as,
Intent i=new Intent();
i.setAction("YOUR_INTENT_FILTER");
i.putExtra("KEY", "YOUR_VALUE");
sendBroadcast(i);
....cheers :)
In kotlin thats how you can do it
Let say if you want to show Toast message from service
val handler = Handler(Looper.getMainLooper())
handler.post {
Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
}
Solution:
Create a Handler with Looper from Main Thread : requestHandler
Create a Handler with Looper from Main Thread: responseHandler and override handleMessage method
post a Runnable task on requestHandler
Inside Runnable task, call sendMessage on responseHandler
This sendMessage result invocation of handleMessage in responseHandler.
Get attributes from the Message and process it, update UI
Sample code:
/* Handler from UI Thread to send request */
Handler requestHandler = new Handler(Looper.getMainLooper());
/* Handler from UI Thread to process messages */
final Handler responseHandler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
/* Processing handleMessage */
Toast.makeText(MainActivity.this,
"Runnable completed with result:"+(String)msg.obj,
Toast.LENGTH_LONG)
.show();
}
};
for ( int i=0; i<10; i++) {
Runnable myRunnable = new Runnable() {
#Override
public void run() {
try {
/* Send an Event to UI Thread through message.
Add business logic and prepare message by
replacing example code */
String text = "" + (++rId);
Message msg = new Message();
msg.obj = text.toString();
responseHandler.sendMessage(msg);
System.out.println(text.toString());
} catch (Exception err) {
err.printStackTrace();
}
}
};
requestHandler.post(myRunnable);
}
Related
I have written a service in android.I want to repeatedly perform a task using service. That is the service shouldn't die and should perform the task repeatedly. However,the service performs the task just once and then gets killed.How to perform the task repeatedly in background.
My current code is->
public class SyncService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(SyncService.this, "servicestarting", Toast.LENGTH_SHORT).show();
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(SyncService.this, "service done", Toast.LENGTH_SHORT).show();
}
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
Toast.makeText(SyncService.this, "repeatedly perform some task", Toast.LENGTH_SHORT).show();
//constantly perform task here
}
}
}
How to repeatedly perform some task using service?
Well you only send one message to the Handler. So that message will be processed once. You could have the Handler pass the same message back again, but with no delay that isn't a good idea- you'll deadlock the main thread. The best way to do something repeatedly would be to spin off a Thread and do it in the Thread, with the Thread's Runnable looping forever.
I have used a handler that runs every 1000 milliseconds in my activity but nothing has changed.
When I use the same handler in my SMSReceiver broadcast receiver class, the activity and its adapter are facing a null pointer problem.
public void update(){
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
convListActivity.getConvListData2();
convListAdapter.notifyDataSetChanged();
}
}, 1000);
}
And then, I have called this method in onReceive method of my broadcast receiver class.
Null pointer exception
is being shown at these lines:
convListActivity.getConvListData2();
convListAdapter.notifyDataSetChanged();
convListActivity and convListAdapter are the activity and its adapter classes.
I have a class which runs on process's main thread. I want to implement a broadcast receiver in this class which runs on a separate thread.
I tried this by making a inner class extending thread & intializing a handler in this inner class, which i can give to registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) for executing broadcast receiver on this handler(which is attached to newly created thread). but in vain. Logs show onReceive is being called on main thread.
please help.(i have seen some posts on how to use registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler), but not of any help).
I would suggest you should use HandlerThread instead of subclassing a Thread
for example
HandlerThread handlerThread = new HandlerThread("DifferentThread" , android.os.Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
Looper looper = handlerThread.getLooper();
private Handler handler = new Handler(looper, this);
// Register the broadcast receiver to run on the separate Thread
registerReceiver (myReceiver, intentFilter, broadcastPermission, handler);
Hope this will help in your Experiment ;)
Njoy!
When using a HandlerThread, be sure to exit the thread after unregistering the BroadcastReceiver. If not, File Descriptor (FD) leaks occur in Linux level and finally the application gets crashed if continue to Register / Unregister.
unregisterReceiver(...);
Then
looper.quit();
Or
looper.quitSafely();
private Handler broadcastReceiverHandler = null;
private HandlerThread broadcastReceiverThread = null;
private Looper broadcastReceiverThreadLooper = null;
private BroadcastReceiver broadcastReceiverReadScans = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
}
private void registerForIntents() {
broadcastReceiverThread = new HandlerThread("THREAD_NAME");//Create a thread for BroadcastReceiver
broadcastReceiverThread.start();
broadcastReceiverThreadLooper = broadcastReceiverThread.getLooper();
broadcastReceiverHandler = new Handler(broadcastReceiverThreadLooper);
IntentFilter filterScanReads = new IntentFilter();
filterScanReads.addAction("ACTION_SCAN_READ");
filterScanReads.addCategory("CATEGORY_SCAN");
context.registerReceiver(broadcastReceiverReadScans, filterScanReads, null, broadcastReceiverHandler);
}
private void unregisterIntents() {
context.unregisterReceiver(broadcastReceiverReadScans);
broadcastReceiverThreadLooper.quit();//Don't forget
}
I have forked LocalBroadcastReceiver to be able to receive broadcasts on an arbitrary java thread.
it works for me. I added a Looper param to
public void registerReceiver(Context act, IntentFilter filt, Looper looper)
if looper is null, the main thread looper is used.
the code is here:
https://github.com/sorenoid/LocalBroadcastManager/blob/master/LocalBroadcastManager.java
I have an application where I send an SMS by clicking on an action button in a Notification. I want to show a Toast after the SMS was sent, but this does not work. I'm afraid it has something to do with AsyncTask and/or BroadcastReceiver.
The workflow of sending an SMS looks like this:
I scan my devices contacts in an AsyncTask and create the Notification from the AsyncTask's onPostExecute()
I use NotificationCompat.Builder for creating the Notification
I add a PendingIntent to the Notification that looks like this:
PendingIntent.getBroadcast(mContext,
(int) _person.getId(), i, PendingIntent.FLAG_ONE_SHOT);
I send the SMS from a BroadcastReceiver's onReceive()
I try to send a Toast from there like this:
Toast.makeText(_context, "SMS sent!", Toast.LENGTH_SHORT).show();
I tried to debug this but unfortunately Eclipse does not show me the variables' contents in onReceive().
I also read something about "Handling compatability" for Notifications Google's developer site here but I could not find a Tutorial where this is explained in more detail.
EDIT:
I guess it might be helpful to explain what Context is passed on through all the classes:
In my MainActivity I display a PreferenceFragment as the main content
In that PreferenceFragment I call new MyAsyncTask(getActivity()).execute(); so that my MainActivity should be my Context
In the constructor of MyAsyncTask I pass this to the class where I create the Notification and save it there as a member (mContext)
The rest I already mentioned...
EDIT 2:
Here's the relevant piece of code of my BroadcastReceiver that listens to the Notification's action:
#Override
public void onReceive(Context _context, Intent _intent)
{
String type = _intent.getStringExtra("type");
if (type.equals("SMS"))
{
String phoneNumber = _intent.getStringExtra("phoneNumber");
String message = _context.getResources().getString(
R.string.smstext);
SmsManager smsManager = SmsManager.getDefault();
smsManager.sendTextMessage(phoneNumber, null, message, null, null);
Toast.makeText(_context, "SMS sent!", Toast.LENGTH_SHORT).show();
}
}
Use a runnable. Whenever I execute commands in a thread, I set up a handler and a runnable that let me run things in the main thread when everything's finished:
// Declare a global handler for the class
final Handler mHandler = new Handler();
// Declare a runnable that will do things app-side when your thread is finished
final Runnable mMessageSent= new Runnable()
{
#Override
public void run()
{
Toast.makeText(_context, "SMS sent!", Toast.LENGTH_SHORT).show();
}
};
// Set up your thread to post the runnable when it's finished sending an SMS
private void sendMessage()
{
Thread t = new Thread()
{
public void run()
{
// Send your SMS here
// When finished, notify the handler so it knows to show a toast notification
mHandler.post(mMessageSent);
}
};
t.start();
}
MasterKale was close, problem is you need to send the toast from the UI thread or it won't work. I'm not sure what he thinks he was doing with that thread.
final Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable(){
#Override
public void run() {
Toast.makeText(mContext, "Message", Toast.LENGTH_SHORT).show();
}
});
If I have an inner class that extends BroadcastReceiver within my Service class, should I care about synchronization, when the BroadcastReceiver class reads/writes to objects from the Service class?
Or to put it in another way: Are BroadacstReceiver's onReceive() Methods started in an extra thread?
The onReceive() method is always called on the main thread (which is also referred to as "UI thread"), unless you requested it to be scheduled on a different thread using the registerReceiver() variant:
Context.registerReceiver(BroadcastReceiver receiver,
IntentFilter filter,
String broadcastPermission,
Handler scheduler)
Are Android's BroadcastReceivers started in a new thread?
Usually but not always, it all depends on how you register it.
If you register your BroadcastReceiver using:
registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
It will run in the main activity thread(aka UI thread).
If you register your BroadcastReceiver using a valid Handler running on a different thread:
registerReceiver (BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)
It will run in the context of your Handler
For example:
HandlerThread handlerThread = new HandlerThread("ht");
handlerThread.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
context.registerReceiver(receiver, filter, null, handler); // Will not run on main thread
Details here & here.
The onReceive() method is called on the main thread. So, in case all your access to the service class is done from within the main thread, you don't need any synchronization.
Android Broadcast receivers are by default start in GUI thread (main thread) if you use
RegisterReceiver(broadcastReceiver, intentFilter).
But it can be run in a worker thread as follows;
When using a HandlerThread, be sure to exit the thread after unregistering the BroadcastReceiver. If not, File Descriptor (FD) leaks occur in Linux level and finally the application gets crashed if continue to Register / Unregister.
unregisterReceiver(...);
Then
looper.quit();
Or
looper.quitSafely();
private Handler broadcastReceiverHandler = null;
private HandlerThread broadcastReceiverThread = null;
private Looper broadcastReceiverThreadLooper = null;
private BroadcastReceiver broadcastReceiverReadScans = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
}
}
private void registerForIntents() {
broadcastReceiverThread = new HandlerThread("THREAD_NAME");//Create a thread for BroadcastReceiver
broadcastReceiverThread.start();
broadcastReceiverThreadLooper = broadcastReceiverThread.getLooper();
broadcastReceiverHandler = new Handler(broadcastReceiverThreadLooper);
IntentFilter filterScanReads = new IntentFilter();
filterScanReads.addAction("ACTION_SCAN_READ");
filterScanReads.addCategory("CATEGORY_SCAN");
context.registerReceiver(broadcastReceiverReadScans, filterScanReads, null, broadcastReceiverHandler);
}
private void unregisterIntents() {
context.unregisterReceiver(broadcastReceiverReadScans);
broadcastReceiverThreadLooper.quit();//Don't forget
}
Also, you can specify the "android:process" receiver element attribute in the AndroidManifest.xml. See here. That way you can specify that the receiver runs as a separate process and isn't tied to the main UI thread.