I would like to update a view from within an open activity when the device receives a push notification.
When a push notification is received the updateBalance function is executed,
a mysql database is queried and an amount is returned.
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private void updateBalance(String messageBody) {
h1 = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(Message msg) {
bb = msg.getData();
String str = bb.getString("result");
Log.d(TAG,str);
Message msg=handler.obtainMessage()
}
};
t = new Thread(new MyRunnable(h1));
t.start();
try {
t.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
I have another class
public class MyRunnable implements Runnable {
private Handler h2;
public MyRunnable(Handler h) {
this.h2 = h;
}
#Override
public void run() {
String name = "w12";
BalanceActivity NB = new BalanceActivity(name);
Message m = Message.obtain();
Bundle b = new Bundle();
b.putString("result", "10");
m.setData(b);
h2.sendMessage(m);
}
}
I have a MainActivity that I would like to update after the amount is returned. How would I do this possibly with another Handler and Runnable.
public class MainActivity extends Activity {
TextView TV = (TextView) findViewById(package.name.R.id.Balance);
}
Try to check your activity is currently in foreground. if yes then create method where you can update your view.
public static boolean isServiceRunning(Context context) {
Log.i(TAG, "Checking if service is running");
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
boolean isServiceFound = false;
for (int i = 0; i < services.size(); i++) {
if (Constants.PACKAGE.equals(services.get(i).service.getPackageName())){
if (Constants.BACKGROUND_SERVICE_CLASS.equals(services.get(i).service.getClassName())){
isServiceFound = true;
}
}
}
Log.i(TAG, "Service was" + (isServiceFound ? "" : " not") + " running");
return isServiceFound;
}
Make use of Broadcast Receivers. Register local broadcast receiver in activity. Broadcast data when notification received.
Related
I have build an IntentService in Android.
So if I received a pushNotification message, I muse stopped this service.
public class DosimeterDataSensingService extends IntentService {
private static final String TAG = "DosimeterDataSensingService";
public static boolean isStarted = false;
private Context mContext;
private int mStatus;
private BluetoothDevice mDevice;
private BluetoothGatt mConnGatt;
private boolean notificationsEnabled;
private long dosimeterScanningTime;
private boolean isThreadStarted = false;
private List<DosimeterDataRequest.DataBean> dosimeterDataList;
private List<DosimeterDataRequest.DataBean> dosimeterDataListMqtt;
private DosimeterMqttParcel dosimeterMqttParcel = new DosimeterMqttParcel();
private DosimeterDataRequest dosimeterDataRequest;
private String macAddress;
private boolean isRecordingEnabled = false;
private String dose = "";
private int battery = -1;
private Boolean syncRadiactionWS = false;
private Boolean syncRadiactionMQTT = false;
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* #param name Used to name the worker thread, important only for debugging.
*/
public DosimeterDataSensingService(String name) {
super(name);
}
public DosimeterDataSensingService() {
super(null);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Log.d("dosimetro", "ON HANDLE INTENT");
if(intent!=null){
String action = intent.getStringExtra(PreferenceHandler.ACTION_STOP);
Log.d("dosimetro", action!=null ? action : "no action");
if(action!=null && action.equals(PreferenceHandler.ACTION_STOP)){
Log.d("dosimetro", "fermo il servizio");
String syncScanTime = PreferenceHandler.readString(getApplicationContext(), PreferenceHandler.DOSIMETER_SCANNING_TIME, null);
Log.d("dosimetro", syncScanTime!=null ? syncScanTime : "nullo");
String syncRotTime = PreferenceHandler.readString(getApplicationContext(), PreferenceHandler.DOSIMETER_ROTATION_TIME, null);
Log.d("dosimetro", syncRotTime!=null ? syncRotTime : "nullo");
super.stopSelf();
Log.d("dosimetro", "ho stoppato");
onDestroy();
return;
}
}
}
#Override
public void onCreate() {
super.onCreate();
Paper.init(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = createNotificationChannel();
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
.setSmallIcon(R.drawable.logoxhdpi)
.setCategory(Notification.CATEGORY_SERVICE)
.setContentTitle("Cardio App")
.setContentText("Getting data from Dosimeter")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
Notification notification = mBuilder.build();
startForeground((int) (System.currentTimeMillis() + 1), notification);
isStarted = true;
if (PreferenceHandler.readString(this, PreferenceHandler.TYPE_USER, null).equals("2")) {
checkDosage();
}
List<GetAssignedDevicesListResponse.Parameters> preferenzeParametri= Paper.book().read(PreferenceHandler.PARAMETRI_VITALI, new ArrayList<>());
if(preferenzeParametri!=null && preferenzeParametri.size()>0){
for (GetAssignedDevicesListResponse.Parameters p: preferenzeParametri) {
if(p.getIdParameter() == PreferenceHandler.ID_RADIACTION){
//VERIFICO COME L'RR DEVE ESSERE SINCRONIZZATO
syncRadiactionWS = p.getSyncWs()!=null ? p.getSyncWs() : false;
syncRadiactionMQTT = p.getSyncMqtt()!=null ? p.getSyncMqtt() : false;
Log.e("DOSIMETER", "syncRadiactionWS true");
}
}
}else{
Log.e("DOSIMETER", "paperi init false");
}
checkBattery();
Log.i("SCANNINGTIME", "SYNC WS STARTED");
syncRadiactionLevel();
syncMqtt();
}
#Override
public void onDestroy() {
Log.d("DOSIMETRO", "ondestroy");
isStarted = false;
disconnectDosimeter();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#SuppressLint("LongLogTag")
public void disconnectDosimeter() {
if (mConnGatt != null) {
isThreadStarted = false;
if ((mStatus != BluetoothProfile.STATE_DISCONNECTING)
&& (mStatus != BluetoothProfile.STATE_DISCONNECTED)) {
mConnGatt.disconnect();
mConnGatt.close();
mConnGatt = null;
mStatus = BluetoothProfile.STATE_DISCONNECTED;
}
}
try {
Method m = mDevice.getClass().getMethod("removeBond", (Class[]) null);
m.invoke(mDevice, (Object[]) null);
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
Log.v("Dosimeter", "isRecordingEnabled" + isRecordingEnabled);
Log.v("Dosimeter", "Disconnecteddd");
}
/**
* Enable recording of values
*/
private void startRecordingData() {
String dosimeterRotation = PreferenceHandler.readString(getApplicationContext(), PreferenceHandler.DOSIMETER_ROTATION_TIME, null);
Log.i("ROTATIONTIME", dosimeterRotation);
long dosimeterRotationTime = 0L;
if (dosimeterRotation != null) {
dosimeterRotationTime = Long.parseLong(dosimeterRotation);
new Handler().postDelayed(() -> {
isRecordingEnabled = true;
isThreadStarted = false;
}, dosimeterRotationTime);
}
}
}
To stop the service I m using this code:
Intent i = new Intent(this, DosimeterDataSensingService.class);
i.putExtra(PreferenceHandler.ACTION_STOP,PreferenceHandler.ACTION_STOP);
stopService(new Intent(this, DosimeterDataSensingService.class));
From my log I can see that the system call
super.stopSelf();
onDestroy();
method but the IntentService works always.
You need not call stopSelf() or stopService() for IntentService.
As per the description mentioned in Docs:
Because most of the started services don't need to handle multiple requests simultaneously (which can actually be a dangerous multi-threading scenario), it's best that you implement your service using the IntentService class.
The IntentService class does the following:
It creates a default worker thread that executes all of the intents that are delivered to onStartCommand(), separate from your application's main thread.
Creates a work queue that passes one intent at a time to your onHandleIntent() implementation, so you never have to worry about multi-threading.
Stops the service after all of the start requests are handled, **so you never have to call stopSelf().**
Provides a default implementation of onBind() that returns null.
Provides a default implementation of onStartCommand() that sends the intent to the work queue and then to your onHandleIntent() implementation.
If the service is still running may be some intents are running.
Hope this helps.
Jugnoo Driver App has not been whitelisted in the Auto Start but yet it again starts the service after some time !
How jugnoo rider app runs even it is not Auto start too
I have done notification stuff , changed the manifest to stopWithTask="false" .
I have created a service for same issue,
please check it out with this.
It will help you
public class GpsServices extends Service implements LocationListener, GpsStatus.Listener {
Data data;
private LocationManager mLocationManager;
private SharedPreferences sharedPreferences;
private Data.onGpsServiceUpdate onGpsServiceUpdate;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
public String gps_notification = "gps_channel";
#SuppressLint("MissingPermission")
#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);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (data == null) {
data = new Data(onGpsServiceUpdate);
} else {
data.setOnGpsServiceUpdate(onGpsServiceUpdate);
}
gpsListener();
mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
if (mLocationManager.getAllProviders().indexOf(LocationManager.GPS_PROVIDER) >= 0) {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 500, 0, this);
} else {
Log.w("SideMenuActivity", "No GPS location provider found. GPS data display will not be available.");
}
if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "Gps not enabled", Toast.LENGTH_SHORT).show();
}
}
public void onLocationChanged(Location location) {
Gson gson = new Gson();
String json = sharedPreferences.getString("data", "");
data = gson.fromJson(json, Data.class);
if (data == null) {
data = new Data(onGpsServiceUpdate);
} else {
data.setOnGpsServiceUpdate(onGpsServiceUpdate);
}
String speed = String.format(Locale.ENGLISH, "%.0f", location.getSpeed() * 3.6);
Toast.makeText(this, speed, Toast.LENGTH_SHORT).show();
Log.e("isRunningFalse", speed);
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;//needed for stop.
if (intent != null) {
msg.setData(intent.getExtras());
mServiceHandler.sendMessage(msg);
} else {
Toast.makeText(GpsServices.this, "The Intent to start is null?!", Toast.LENGTH_SHORT).show();
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
/* Remove the locationlistener updates when Services is stopped */
#Override
public void onDestroy() {
mLocationManager.removeUpdates(this);
mLocationManager.removeGpsStatusListener(this);
stopForeground(true);
}
#Override
public void onGpsStatusChanged(int event) {
switch (event) {
case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
#SuppressLint("MissingPermission") GpsStatus gpsStatus = mLocationManager.getGpsStatus(null);
int satsInView = 0;
int satsUsed = 0;
Iterable<GpsSatellite> sats = gpsStatus.getSatellites();
for (GpsSatellite sat : sats) {
satsInView++;
if (sat.usedInFix()) {
satsUsed++;
}
}
if (satsUsed == 0) {
data.setRunning(false);
stopService(new Intent(getBaseContext(), GpsServices.class));
// firstfix = true;
}
break;
case GpsStatus.GPS_EVENT_STOPPED:
if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Toast.makeText(this, "Gps not enabled.", Toast.LENGTH_SHORT).show();
}
break;
case GpsStatus.GPS_EVENT_FIRST_FIX:
break;
}
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
// 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) {
//promote to foreground and create persistent notification.
//in Oreo we only have a few seconds to do this or the service is killed.
Notification notification = getNotification("App is running");
startForeground(msg.arg1, notification); //not sure what the ID needs to be.
// Normally we would do some work here, like download a file.
// For our example, we just sleep for 5 seconds then display toasts.
//setup how many messages
int times = 1, i;
Bundle extras = msg.getData();
if (extras != null) {
times = 1000*60*60*24; //default is one
}
//loop that many times, sleeping for 5 seconds.
for (i = 0; i < times; i++) {
synchronized (this) {
try {
wait(5000); //5 second sleep
} catch (InterruptedException e) {
}
}
String info = i + "GPS SPEED LOG";
Log.d("intentServer", info);
//make a toast
//unable to ensure the toasts will always show, so use a handler and post it for later.
// Toast.makeText(MyForeGroundService.this, info, Toast.LENGTH_SHORT).show();
}
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
// stopSelf(msg.arg1); //notification will go away as well.
}
}
// build a persistent notification and return it.
public Notification getNotification(String message) {
return new NotificationCompat.Builder(getApplicationContext(), gps_notification)
.setSmallIcon(android.R.drawable.ic_menu_mylocation)
.setOngoing(true) //persistent notification!
.setChannelId(gps_notification)
.setContentTitle("Gps Service") //Title message top row.
.setContentText(message) //message when looking at the notification, second row
.build(); //finally build and return a Notification.
}
}
I would like to ask a question about my code in Wifi client communication. I am communicating with a Raspberry Pi as server.
The architecture of my code is:
Main Activity: I have the Handler class and I launch in the OnCreat the first Thread (Thread1) that takes care of establishing the wifi connection.
public class MainActivity extends AppCompatActivity {
public int serverPort = 40000;
public String serverIP = "10.177.86.212";
public WiFiConnector wifiConnection;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextWE = (EditText) findViewById(R.id.editText_WE);
wifiConnection = new WiFiConnector(serverIP, serverPort);
Handler mHandler = new MyHandler();
WiFiConnector.Thread1 = new Thread(new WiFiConnector.Thread1(mHandler,true));
WiFiConnector.Thread1.start();
}
private class MyHandler extends Handler {
private byte[] bytes = null;
#Override
public void handleMessage(Message msg) {
bytes = msg.getData().getByteArray("KEY");
if(bytes!= null){
for (int i = 0; i < bytes.length; i++){
Log.d("Data received", "value " + (0xFF & bytes[i]) );
}
for (int i=0; i<bytes.length; i++) {
editTextWE.setText(editTextWE.getText()+ "Server says: " + bytes.length + " "+ (0xFF & bytes[i]) + "\n");
}
}
}
}
}
WifiConnector class: Thread1 and Thread2 are sharing the handler coming from the Main Activity. Thread1 send a command to Raspberry Pi to let it start sending data. Thread2 is dedicated to read data received from the server.
public class WiFiConnector {
static String serverIP;
static int serverPort;
public static Thread Thread1 = null;
//Constructor
public WiFiConnector(String IP, int port) {
serverIP = IP;
serverPort = port;
}
public static class Thread1 extends Thread implements Runnable {
private Handler handler1;
boolean firsttime = false;
OutputStream out ;
public Thread1(Handler handler_1, boolean firsttime) {
this.handler1 = handler_1;
this.firsttime = firsttime;
}
public void run() {
Socket socket = null;
try {
//Writing to a Socket
InetAddress serverAddress = InetAddress.getByName(serverIP);
socket = new Socket(serverAddress, serverPort);
out = new DataOutputStream(socket.getOutputStream());
if(firsttime){
//I send "B" to Raspberry to let him start sending data
out.write("B".getBytes());
this.fisrttime = false;
}
Thread2 comThread = new Thread2(socket, handler1);
new Thread(comThread).start();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static class Thread2 implements Runnable {
public Socket clientSocket;
private Handler handler_2;
public DataInputStream in;
public byte[] bytes = new byte[13];
public Message msg;
public Thread2(Socket clientSocket, Handler handler2) {
this.clientSocket = clientSocket;
this.handler_2 = handler2;
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
if (Looper.myLooper() == null) {
Looper.prepare();
}
this.in = new DataInputStream(clientSocket.getInputStream());
in.readFully(bytes);
if (in != null) {
for (int i = 0; i < bytes.length; i++){
Log.d("Data received", "valuewifi " + (0xFF & bytes[i]) );
}
msg = new Message();
Bundle b = new Bundle();
b.putByteArray("KEY", bytes);
msg.setData(b);
handler_2.sendMessage(msg);
} else {
Thread1 = new Thread(new Thread1(handler_2,false));
Thread1.start();
return;
}
} catch (IOException e) {
e.printStackTrace();
}
}
Looper.loop();
}
}
}
NOW THE PROBLEM IS:
I am receiving correctly my data (package of 13 bytes each) from Raspberry Pi, indeed:
Log.d("Data received", "valuewifi " + (0xFF & bytes[i]) );
prints correctly my values. Then I create the message to be sent to the handler in MainActivity. the Bundle contains (I have verified) the same values of the input stream received, but the message printed in the Handler of the MainActivity:
Log.d("Data received", "value " + (0xFF & bytes[i]) );
substitutes the first byte value of each message (I am trying to get 2 package each communications with the RPi) with 66 that actually is the ASCII code of "B" that I sent to start the data sending from Raspberry Pi.
PLEASE DO YOU HAVE ANY IDEA ON WHY THIS IS HAPPENING?
Many thanks for your help in advance!:)
Well, I have found that in Thread2 if I put
public byte[] bytes = new byte[13];
inside the run{..} before
in.readFully(bytes);
The exchange of message happens perfectly. Otherwise I only get in MainActivity the last package of byte received from the server.
Any suggestion on why does it happen?
Thanks!
My application has a database where queued items will be stored if it doesn't notice any connectivity to Wifi or mobile network, like 3G og 4G. My problem is:
I have a BroadcastReciever which is registrered this way:
#Override
public void onResume() {
super.onResume();
if(networkMonitor == null)
networkMonitor = new CaseQueueReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkMonitor, filter);
}
My BroadcastReciever is starting a Service to pick out items from this database and send them over either a webservice or mail. My BrodcastReciever is like this:
public class CaseQueueReceiver extends BroadcastReceiver {
boolean available;
QueueDB queueDB;
int count;
public CaseQueueReceiver() {
queueDB = new QueueDB(ContextHelper.context());
count = queueDB.countUnsentCases();
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
String typeName = info.getTypeName();
String subtypeName = info.getSubtypeName();
available = info.isAvailable();
Log.i("Network Monitor", "Network Type: " + typeName + ", subtype: " + subtypeName + ", available: " + available);
if (available && count > 0) {
Intent service = new Intent(context, SendQueuedCasesService.class);
context.startService(service);
}
}
}
}
As you can see if the internet connection is available and the database contains something, I will start a service to send these items in the database.
My Service looks like this:
public class SendQueuedCasesService extends Service {
boolean available;
DatabaseHandler db;
QueueDB queueDB;
HashMap<String, String> queueHashMap;
CreateTransaction transaction;
String pcn, file;
int sent;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
db = new DatabaseHandler(ContextHelper.context());
queueDB = new QueueDB(ContextHelper.context());
queueHashMap = new HashMap<String, String>();
transaction = new CreateTransaction(ContextHelper.context());
queueDB = new QueueDB(this);
int count = queueDB.countUnsentCases();
Log.w("Unsent cases count: ", Integer.toString(count));
if (count > 0) {
queueHashMap = queueDB.getUnsetCases();
Iterator<Entry<String, String>> it = queueHashMap.entrySet().iterator();
while(it.hasNext()) {
Map.Entry pairs = it.next();
pcn = pairs.getKey().toString();
Log.w("PCN in Queued Cases: ", pcn);
file = pairs.getKey().toString();
Log.w("Nist File Path: ", file);
try
{
sent = transaction.createTransaction(pcn, file);
if(sent == -2)
{
queueDB.deleteUnSentCase(pcn);
db.updateDB(pcn, "");
}
else
break;
} catch(MailException e) {
Log.e("MailException: ", e.getMessage());
}
}
Intent i = new Intent(this, WorkflowChooser.getCurrentWorkflow());
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
}
}
}
My problem is that when I start the application this will block the UI for a while and then show the UI. A other problems is that this service isn't triggered if I turn off and the on the WiFi again. Why is this happening?
My problem is that when I start the application this will block the UI for a while and then show the UI.
Service runs in UI thread. That's the problem.
You can try to use IntentService. It will handle all the threading for you automatically.
You should create an AsyncTask or a new thread which handles the Service.
I am implementing an application which is kind of VOIP application. So my application is kind of network application. Now I want to implement two part in my application, one is GUI part and one is network part. My GUI part will just contain activities and handling of user interaction. My Network part should handle all network related activities like handling incoming network data and sending data to network based on GUI interaction. Now whenever there is any incoming data, I want to update some activity whose reference is not there in Network module. So what could be the best way to update activity from some other class? In my case some other class is my Network class. So in short I would like to ask that what should be the architecture in such scenario? i.e. Network part should run in separate thread and from there it should update GUI?
Depending on the type/size of data you need to send to the activity, you can use one of a number of options.
Use one of the methods described here.
Use a BroadcastReceiver: register it in the Activity and then fire off matching Intents in the Service that handles the networking code.
Make your Activity bind to your Service and then pass in a Handler that you send Messages to.
I have written apps like this, and I prefer the Handler method. In fact I have written an Abstract Activity class to do all the hard work and simply extend it in any activity that want to be notified of a change.
To Use the following code, just get your Activity to extend UpdatableActivity and override the dataUpdated() method. This method is called when your Service notifies the handler that data has been updated. In the Service code put your code to do an update in the update() method (Or modify to call your existing code). This allows an activity to call this.updateService() to force an update. The service can call the sendMessageToUI() method to notify all interested activities that the data has been updated.
Here is what the abstract activity looks like:
public abstract class UpdatableActivity extends Activity {
public static final String TAG = "UpdatableActivity (Abstract)";
private final Messenger mMessenger = new Messenger(new IncomingHandler());
private Messenger mService = null;
private boolean mIsBound;
protected class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
if (Constants.LOG_DEBUG) Log.d(TAG, "Service has notified us of an update: ");
switch (msg.arg1) {
case UpdateService.MSG_DATA_UPDATED:
dataUpdated();
break;
default: super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
try {
Message msg = Message.obtain(null, UpdateService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
}
};
/**Override this method in you acctivity to handle the update */
public abstract void dataUpdated();
void doBindService() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Binding to service...");
bindService(new Intent(this, UpdateService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null, UpdateService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
public void updateService() {
if (Constants.LOG_DEBUG) Log.d(TAG,"Updating Service...");
if (mIsBound) {
if (mService != null) {
try {
Message msg = Message.obtain(null, UpdateService.MSG_SET_INT_VALUE, UpdateService.MSG_DO_UPDATE, 0);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
if (Constants.LOG_ERROR) Log.e(TAG,Log.getStackTraceString(e));
}
}
} else {
if (Constants.LOG_DEBUG) Log.d(TAG, "Fail - service not bound!");
}
}
pu
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.doBindService();
}
#Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
} catch (Throwable t) {
if (Constants.LOG_ERROR) Log.e(TAG, "Failed to unbind from the service", t);
}
}
}
And here is what the Service looks Like:
public class UpdateService extends Service {
public static final String TAG = "UpdateService";
public static final int MSG_DATA_UPDATED = 0;
public static final int MSG_REGISTER_CLIENT = 1;
public static final int MSG_UNREGISTER_CLIENT = 2;
public static final int MSG_DO_UPDATE = 3;
public static final int MSG_SET_INT_VALUE = 4;
private static boolean isRunning = false;
private Handler handler = new IncomingHandler();
private final Messenger mMessenger = new Messenger(handler);
private ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients.
#Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_INT_VALUE:
switch (msg.arg1) {
case MSG_DO_UPDATE:
if (Constants.LOG_DEBUG) Log.d(TAG,"UI has asked to update");
update();
break;
}
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Notifying "+mClients.size()+" UI clients that an update was completed");
for (int i=mClients.size()-1; i>=0; i--) {
try {
// Send data as an Integer
mClients.get(i).send(Message.obtain(null, MSG_SET_INT_VALUE, MSG_DATA_UPDATED, 0));
} catch (RemoteException e) {
// The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop.
mClients.remove(i);
}
}
}
public static boolean isRunning()
{
return isRunning;
}
#Override
public void onCreate() {
super.onCreate();
isRunning = true;
if (Constants.LOG_DEBUG) Log.d(TAG, "Service Started");
update();
}
#Override
public void onDestroy() {
if (Constants.LOG_DEBUG) Log.d(TAG, "Service Destroyed");
isRunning = false;
}
private void update() {
/**Your code to do an update goes here */
}
}
Yes, personally i think that the network and UI should be in separate threads. The way I tend to communicate between the two, which is probably not the recommended proper way, but it works for me, is to create a global variable in your application class. hope this helps a little
I would directly post to the main UI thread,
Handler mHandler = new Handler(Looper.getMainLooper());
mHandler.post(new Runnable() {...});