I'm working on an Android app that needs to maintain a network connection to a chat server. I understand that I can create a service to initiate the connection to the server, but how would the service notify an Android Activity of new incoming messages? The Activity would need to update the view to show the new messages. I'm pretty new to Android, so any help is appreciated. Thanks!
Can you pass a handler to your service?
First, define your handler as an interface. This is an example, so yours may be more complex.
public interface ServerResponseHandler {
public void success(Message[] msgs); // msgs may be null if no new messages
public void error();
}
Define an instance of your handler in your activity. Since it's an interface you'll provide the implementation here in the activity, so you can reference the enclosing activity's fields and methods from within the handler.
public class YourActivity extends Activity {
// ... class implementation here ...
updateUI() {
// TODO: UI update work here
}
ServerResponseHandler callback = new ServerResponseHandler() {
#Override
public void success(Message[] msgs) {
// TODO: update UI with messages from msgs[]
YourActivity.this.updateUI();
}
#Override
public void error() {
// TODO: show error dialog here? (or handle error differently)
}
}
void onCheckForMessages() {
networkService.checkForMessages(callback);
}
and NetworkService would contain something like:
void checkForMessages(ServerResponseHandler callback) {
// TODO: contact server, check for new messages here
// call back to UI
if (successful) {
callback.success(msgs);
} else {
callback.error();
}
}
Also, as Aleadam says, you should also be away that a service runs on the same thread by default. This is often not preferred behavior for something like networking. The Android Fundamentals Page on Services explicitly warns against networking without separate threads:
Caution: A service runs in the main thread of its hosting process—the service does not
create its own thread and does not run in a separate process (unless you specify
otherwise). This means that, if your service is going to do any CPU intensive work or
blocking operations (such as MP3 playback or networking), you should create a new thread
within the service to do that work. By using a separate thread, you will reduce the
risk of Application Not Responding (ANR) errors and the application's main thread can remain dedicated to user interaction with your activities.
For more information on using threads in your service, check out the SO articles Application threads vs Service threads and How to start service in new thread in android
Did you check the Service API page: http://developer.android.com/reference/android/app/Service.html ?
It has a couple of examples on how to interact with a Service.
The service runs on the same thread and the same Context as the Activity. Check also here: http://developer.android.com/reference/android/content/Context.html#bindService%28android.content.Intent,%20android.content.ServiceConnection,%20int%29
Finally, take a look also at Lars Vogel's article: http://www.vogella.de/articles/AndroidServices/article.html
One common and useful approach is to register a broadcast receiver in your Activity, and have the Service send out notification events when it has useful data. I find this to be easier to manage than implementing a handler via a callback, mainly because it makes it easier and safer when there is a configuration change. If you pass a direct Activity-reference to the Service then you have to be very careful to clear it when the Activity is destroyed (during rotation, or backgrounding), otherwise you get a leak.
With a Broadcast Receiver you still have to unregister when the Activity is being destroyed, however the Service never has a direct reference to the Activity so if you forget the Activity will not be leaked. It is also easier to have the Activity register to listen to a topic when it is created, since it never has to obtain a direct reference to the Service...
Lars Vogel's article discusses this approach, it is definitely worth reading! http://www.vogella.com/tutorials/AndroidServices/article.html#using-receiver
Related
Currently, I need a bound (Music)Service, because I need to interact with it. But I also want it to not be stopped, even when all components have unbound themselves.
As the Android Developer Guide says
"[...] Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed."
The Guide also says
"[...] your service can work both ways—it can be started (to run indefinitely) and also allow binding."
In my application, the service is started when the application starts.
I want to have this service destroyed only by a user-click on a close-button I am displaying in a custom notification. But currently, when I am destroying my MainActivity the service also stops.
This is where I am now, this is called when I want to create my Service:
public void createServiceConnection(){
musicConnection = new ServiceConnection(){
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
MusicService.MusicBinder binder = (MusicService.MusicBinder)service;
musicSrv = binder.getService();
attachMusicService();
}
};
}
...which calls this:
public void attachMusicService(){
playerFragment.setMusicService(musicSrv);
musicSrv.attach(context); //need this for my listeners, nevermind
bindService(context);
}
...which calls this:
public void bindService(Context act){
if(playIntent==null){
playIntent = new Intent(act, MusicService.class);
act.startService(playIntent);
act.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}else{
act.startService(playIntent);
act.bindService(playIntent, musicConnection, Context.BIND_AUTO_CREATE);
}
//finished. I can do stuff with my Service here.
}
Have I misunderstood something?
I feel like the service should keep running, even the activity is destroyed, because I first made a started service and then bound to it.
Bind to your service from custom Application class. I don't think you can keep service alive after activity that's bound to it is destroyed (when onDestroy is called). You can keep service alive if activity pauses (onPause) by calling startForeground from service
Seems like the code was correct.
According to this Question I found out that my problem was the notification I displayed, wich is pretty interesting.
Seems like that a Service that is created for running indefinitely needs to have a Notification wich is displayed by startForeground(NOTIFY_ID, notification);.
I showed my notification with notificationmanager.notify(NOTIFY_ID, notification); before, now I have
`notificationmanager.notify(NOTIFY_ID, notification);
startForeground(NOTIFY_ID, notification);`
and the service won't stop anymore after all my bound Activities are destroyed.
I am writing a Tracking App in Android.
I have got a Service implements LocationListener, which does all the stuff with location and writing to database, and Activity.
I would like to run Service in new thread to optimize my app. I want also to send both sides messsages from Service to Activity, which will show info about location.
I bind service, like it is mentioned in Bind to Service section and implement using a Messenger. Next I tried to do:
Thread t = new Thread(){
public void run(){
bindService(new Intent(this, GPSLogger.class), mConnection, Context.BIND_AUTO_CREATE);
}
};
t.start();
App is working, but all the GPSLogger stuff is doing in main thread.
Is it any way to repair this?
Regular services run in main thread.
You can use IntentService instead. It is a job queue with a single bg thread.
If you insist on using the base Service class then you'll have to spawn your own threads.
I am transitioning from writing a java Swing application to JavaFX to write a modern java based GUI application.
I would like to know the best approach to create a network based reusable threading service. The way I coded up the network service was to use a controller class (generated from the FXML via the Net-beans GUI). I put the threading logic here via a private Service member named 'transmitter' and I wired up the start/stop logic via the Start/Stop button's event callback.
The network based thread is implemented as a javafx Service - I did this since I would like to restart the service/thread whenever the destination address changes. This seems to be the recommended approach in place of a stand alone Task.
The network service is very simple right now, all it does is use some GUI widgets to configure a packet to transmit to a host/port once a second. I need to restart the service only if the host/port widget changes, however if the network service is running, I would like to modify the packet without interrupting/restarting the DatagramSocket. The place where I have questions and require some guidance are:
What is the recommended approach to threading a network thread in an
FXML based application? An example would be greatly appreciated.
How do I safely communicate changes from GUI widgets (via their
action performed callbacks) to the running service class?
Shown below are the most relevant parts of my controller class:
/**
* FXML Controller class
*
* #author johnc
*/
public class OpMessageServerController implements Initializable {
#FXML
private Text mCurrentDateTimeText;
#FXML
private Label mApplicationStatus;
#FXML
private ComboBox<DiscreteStatus> mPofDS;
#FXML
private ComboBox<PhaseOfFlightFMS> mPofFMS;
#FXML
private ComboBox<DiscreteStatus> mTailNumberDS;
#FXML
private ComboBox<DiscreteStatus> mConfigTableDS;
#FXML
private ComboBox<DiscreteStatus> mDateTimeDS;
#FXML
private TextField mEpicPN;
#FXML
private TextField mConfigTablePNHash;
#FXML
private TextField mTailNumber;
#FXML
private ComboBox<DiscreteStatus> mTopLevelPNDS;
#FXML
private Button mStartStopButton;
#FXML
private ComboBox<String> mDLMUHostSpec;
#FXML
private CheckBox connectionStatusC1;
#FXML
private CheckBox wsuConnectionStatus;
#FXML
private CheckBox connectionStatusC4;
#FXML
private CheckBox connectionStatusC3;
#FXML
private CheckBox connectionStatusC2;
#FXML
private CheckBox dlmuwConnectionStatus;
private Service<Void> transmitter;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
mPofDS.setItems(FXCollections.observableArrayList(DiscreteStatus.values()));
mPofDS.getSelectionModel().selectFirst();
mPofFMS.setItems(FXCollections.observableArrayList(PhaseOfFlightFMS.values()));
mPofFMS.getSelectionModel().selectFirst();
mTailNumberDS.setItems(FXCollections.observableArrayList(DiscreteStatus.values()));
mTailNumberDS.getSelectionModel().selectFirst();
mConfigTableDS.setItems(FXCollections.observableArrayList(DiscreteStatus.values()));
mConfigTableDS.getSelectionModel().selectFirst();
mDateTimeDS.setItems(FXCollections.observableArrayList(DiscreteStatus.values()));
mDateTimeDS.getSelectionModel().selectFirst();
mTopLevelPNDS.setItems(FXCollections.observableArrayList(DiscreteStatus.values()));
mTopLevelPNDS.getSelectionModel().selectFirst();
// mDLMUHostSpec.setItems(FXCollections.observableArrayList(
// FXCollections.observableArrayList("localhost:1234", "192.168.200.2:1234")));
// add event handler here to update the current date/time label
// this should also update the transmit datastructure
final Timeline timeline = new Timeline(new KeyFrame(
Duration.seconds(1), (ActionEvent event) -> {
LocalDateTime currentDateTime = LocalDateTime.now();
mCurrentDateTimeText.setText(currentDateTime.format(
DateTimeFormatter.ofPattern("kk:mm:ss uuuu")));
}));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
// create a service.
transmitter = new Service() {
#Override
protected Task createTask() {
return new Task<Void>() {
#Override
protected Void call() throws InterruptedException {
updateMessage("Running...");
updateProgress(0, 10);
DatagramSocket sock = null;
while (!isCancelled()) {
try {
if (sock == null) {
DatagramSocket sock = new DatagramSocket();
}
} catch (SocketException ex) {
Logger.getLogger(OpMessageServerController.class.getName()).log(Level.SEVERE, null, ex);
}
//Block the thread for a short time, but be sure
//to check the InterruptedException for cancellation
OpSupportMessage opSupportMessage = new OpSupportMessage(
DiscreteStatus.NormalOperation,
PhaseOfFlightFMS.Cruise,
DiscreteStatus.NormalOperation,
"TAILNUM",
DiscreteStatus.NormalOperation);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
String[] specParts = mDLMUHostSpec.getValue().split(":");
if (specParts.length == 2) {
try {
opSupportMessage.write(bos);
byte[] buff = bos.toByteArray();
DatagramPacket packet = new DatagramPacket(
buff, buff.length, InetAddress.getByName(
specParts[0]), Integer.parseInt(specParts[1]));
mSocket.send(packet);
Thread.sleep(1000);
} catch (IOException ex) {
} catch (InterruptedException interrupted) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
}
}
}
updateMessage("Cancelled");
return null;
}
#Override
protected void succeeded() {
System.out.println("Scanning completed.");
}
#Override
protected void failed() {
System.out.println("Scanning failed.");
}
#Override
protected void running() {
System.out.println("Scanning started.");
}
#Override
protected void cancelled() {
System.out.println("Scanning cancelled.");
}
private void DatagramSocket() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
};
}
};
mApplicationStatus.textProperty().bind(transmitter.messageProperty());
};
#FXML
private void startStopButtonAction(ActionEvent event) {
if (!transmitter.isRunning()) {
transmitter.reset();
transmitter.start();
}
}
…
}
Background
This answer is based upon a collection of comments on the question, it rambles a bit, does not provide a solution targeted at the code in the question and does not address some of the concepts in the question such as a low level UDP socket based communication system - apologies for that.
Sample Solution Project
I did a proof of concept of a JavaFX app using web socket based communication: javafx-websocket-test. Perhaps some of the concepts from there might help you, in particular the client JavaFX Task and Service code and the sample client application and controller that uses it.
The project does demonstrate, in an executable implementation, some of the communication principles outlined in Adam Bien's article on JavaFX Integration Strategies that James_D linked, for example:
Setting up a web socket endpoint within a JavaFX service.
Wrapping each communication interaction in an async JavaFX Task.
Using async event callbacks to shunt success and failure results back to the UI.
Additionally the example shows interaction between the network service and the JavaFX UI, with the JavaFX UI making async requests to the service and processing async responses from it.
I do recall the seemingly simple Java web socket API did contain a few gotchas. It is just a proof of concept, so be careful of using it as the basis for a robust network service.
Commentary and thoughts
This is actually an invariably tricky question to answer IMO, due to these reasons:
There are many forms of network communication, some of which are suited to different applications.
There is (currently) no standard or best practice of integrating network services with JavaFX applications.
Providing a robust network connection with UI status monitoring and exception handling is often not as straight-forward as it might seem and is easy to get wrong.
There are many subtleties to be dealt with, such as:
What to do in the event of a communication failure?
What to do if the application issues requests at a faster rate than the network or server can process?
What happens if the user shuts down the application while messages are outstanding?
How to ensure that the UI is not frozen while lengthy communication processes occur?
How to provide UI feedback that lengthy network processing is on-going?
What underlying communication technology is being used?
Is the underlying communication stateful or stateless?
Is the communication non-blocking and event driven or blocking?
How to serialize and deserialize data for transmission?
Even though a one-size fits all communication model would be difficult, a "standard" communication model could be adapted which fits many needs. For example something similar to http ajax calls in the browser based network model or NetConnections for flash. Those seem to function well enough for a wide variety of needs. Though of course, they aren't optimal for everything, otherwise alternate systems such as web sockets or http live streaming would not have been created.
Ideally, there would be a single, standardized API like jQuery.ajax() for JavaFX client => server communication, but I haven't yet seen anybody create a JavaFX equivalent of that kind of API.
Unlike the rest of the core JavaFX APIs, such standardized high-level interfaces for network communication don't exist in an off-the-shelf form at the moment. However, there are plenty of libraries and functions available to act as the basic building blocks for developing your own service; perhaps even too many to reasonably process.
Note that most higher level network protocol libraries, such as a Tyrus web socket implementation or the Apache HTTP components underlying a JAX-RS provider have their own internal thread-pools for communication. Systems like netty are based upon nio and are event driven rather than thread managed. What your JavaFX network client service is one of these two things:
For non-blocking I/O it is issuing async calls, hooking into the response events and relaying them back to JavaFX via Platform.runLater.
For blocking I/O, it spawning a thread with a Task or Service with either an implicit or explicit executor service pool to manage the UI interaction but not the actual network comms.
A key and confusing thing is that the JavaFX application code should always perform the network communication in an async manner. For non-blocking I/O the call is already async, so no wrapper task is necessarily required. For blocking I/O, you don't want to block the UI thread, so the Task wrapper running in it's own thread prevents that occurring.
One would think this would make the non-blocking I/O calls simpler, but it doesn't really, as the JDK's non-blocking I/O API is quite low level and is pretty tricky to code to. It isn't really appropriate for high level application code.
Generally, application code is better off using a higher level library such as JAX-RS, web sockets or akka (or, preferably, a layer on top of them) which internally manage the details of the communication in either a blocking or non-blocking fashion AND provide an event driven API for sending and receiving messages. The individual message events can be wrapped in a JavaFX Task for async processing. So, from the JavaFX application point of view, everything is event driven, nothing is blocking, and the same application API works regardless of the underlying communication protocol and blocking/non-blocking communication infrastructure.
thanks for the proof of concept application, this will be quite useful, however one thing that is a bit obscure is how one can safely communicate GUI changes to the running service thread safely. It appears that the HelloService uses a 'name' simple string property to communicate changes from the GUI to the service before it is started. I wonder how one might communicate UI changes to a running background service in a thread safe manner. Via some sort or message api perhaps?
A BlockingQueue with a fixed max-size which rejects additional requests when the queue is full can be used for communication from JavaFX thread based code to a consumer service. It is a reasonably elegant solution to the classic producer-consumer problem.
Of course, you could just skip the blocking queue and keep creating async tasks ad-nauseum, which is fine for low volume communication, but could lead to a starvation of limited thread resources for high volume communication. One standard way to handle that is to use an ExecutorService from Executors which manages a thread pool. The thread pool for the executor service can be defined to be bounded to a max number of threads and internally use an unbounded queue where messages pile up if all threads are busy. That way you don't need to define your own blocking queue, you just issue async service requests and they are immediately handled in threads if they can be or the requests pile up in the internal queue if they cannot.
This is actually the way that a JavaFX Service works:
The Service by default uses a thread pool Executor with some unspecified default or maximum thread pool size. This is done so that naive code will not completely swamp the system by creating thousands of Threads.
and:
If an Executor is specified on the Service, then it will be used to actually execute the service. Otherwise, a daemon thread will be created and executed. If you wish to create non-daemon threads, then specify a custom Executor (for example, you could use a ThreadPoolExecutor with a custom ThreadFactory).
More sophisticated solutions for which a simple BlockedQueue messaging is not appropriate would use a topic based message queue style solution, e.g., a Java based STOMP client such as this kaazing example.
Getting the message info to the service is just part of the requirement, that is essentially doing an async message send. You also need to process the response that comes back. To do that, there are two alternatives:
You model each request as a separate Task, and the onSuccess and onError handlers process the task response. Running the task within a service ensures that it is handled by an executor with a fixed thread pool backed by an internal queue for overflow.
You write your own long running service interface with it's own API and encapsulate a blocking queue for requests, using Platform.runLater for handling communicating results back to the UI.
To make the response handler logic dynamic and adjustable by the caller, you could pass the handler function as a lambda function to be executed on success for the original call using Platform.runLater.
If you wrap the call in a Task or Service, and use the onSucceeded function, you don't need the runLater call, because the implementation will ensure that the onSucceeded handler is called on the JavaFX thread once the task completes.
Note, that often the network request and response require some conversion of marshaling and unmarshaling of data to and from a serializable stream. Some of the higher level network APIs such as the JAX-RS or web socket providers provide interfaces and utilities to do some of this work for you, often using specific libraries for different types of conversion, such as JAXB for XML serialization of Jackson for JSON serialization.
Slightly related info and further thoughts
This next is probably a bit off-topic, but this is an example of BlockingQueue and Task interaction, it is not a network service, but it does demonstrate use of queues within a producer/consumer situation, with a reactive UI and progress monitoring.
One other thing that would be interesting to see (at least for me), is an Akka based solution for JavaFX client->server communication. That seems like a nice alternative to traditional http/rest/soap/rmi calls or message queue based processing. Akka is inherently an event based solution for fault-tolerant asynchronous concurrent communication, so it would seem a good match-up for a UI based framework such as JavaFX, allowing a developer to process at an appropriate layer of abstraction. But I have yet to see a JavaFX based messaging client that relies on Akka.
I would like to know the best approach to create a network based
reusable threading service. The way I coded up the network service was
to use a controller class (generated from the FXML via the Net-beans
GUI). I put the threading logic here via a private Service member
named 'transmitter' and I wired up the start/stop logic via the
Start/Stop button's event callback.
I humbly suggest that you develop your network service and your GUI controller as separate projects.
I would have the network service running in its own container or virtual machine as a daemon/background thread. The advantage of this organization is that it keeps your server away from the vagaries of the JavaFX event loop and application thread. You'll want to design your service to recognize administration commands and/or interrupt requests from your controller. You can develop your network services as REST or whatever you want without wondering how to roll this into the JavaFX application thread.
I would then have the GUI controller running as a separate GUI application either in the same process or, if remote administration is desired, in a separate JVM (and use IPC to send/receive administration messages).
TL;DR: if it were me, I would resist the temptation to program the network service as a JavaFX application.
Okay, here goes... I am new to android programming and am in desperate need of direction.
My end result in mind is to be able to send requests to my service and depending on WHAT is requested, have it perform different actions.
Example 1: User presses a refresh button in an activity, which downloads information and then displays it it.
Example 2: User navigates to a login fragment in an activity where he can input his user name and password. His currently saved information is displayed beforehand.
Example 3: User presses widget, which downloads information and then displays some information in the widget.
Hopefully I've gotten my idea across; sending consuming tasks to a service, with the ability to update whatever display currently being worked on.
With the services' task being dependant on what is being asked of it (service: do I download? do I fetch login info? do I fetch some other information?), it must know how to proceed, once started... which leads me to my question:
How do I tell my service which task to perform after it is called?
Also, but less importantly, what is the best, most code-efficient way to update views (widget, activity)?
Background information:
I have decided to use a service to facilitate both the widget and
Activities.
The service performs demanding tasks (downloads, database
fetching/saving, and more) on an AsyncTask.
I am calling my service as follows:
Intent intent = new Intent(getActivity(), WorkerService.class);
getActivity().startService(intent);
You can use a BoundService
A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely.
You have two ways of creating a BoundService:
1) Using a Binder - This is probably what you want to do.
If your service is private to your own application and runs in the
same process as the client (which is common), you should create your
interface by extending the Binder class and returning an instance of
it from onBind(). The client receives the Binder and can use it to
directly access public methods available in either the Binder
implementation or even the Service. This is the preferred technique
when your service is merely a background worker for your own
application. The only reason you would not create your interface this
way is because your service is used by other applications or across
separate processes.
2) Using a Messanger
Remember that the service runs in the UI (main) thread. If you do long lasting operations you should create a background thread.
public class LocalService extends Service {
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
// Random number generator
private final Random mGenerator = new Random();
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
LocalService getService() {
// Return this instance of LocalService so clients can call public methods
return LocalService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
}
In my PollFragment.java that able to call new PollTask((MainActivity)getActivity()).execute((Void)null);
And in my PollTask.java
public PollTask(MainActivity activity){
super(activity);
TerminalCfg terminalCfg = Global.getTerminalCfg();
terminalId = terminalCfg.getTerminalId();
retailerAcc = terminalCfg.getRetailerAcc();
internalId = APIUtil.getInternalId(activity);
username = APIUtil.getUsername(activity);
}
And now I want to call the new PollTask((MainActivity)getActivity()).execute((Void)null);
in MyBackgroundService with extends Service like below :
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
new PollTask((MainActivity)getActivity()).execute((Void)null);
// 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;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
Is there any other way to replace the getActivity() to call the method?
A Service is a separate component from an Activity and thus you cannot get a reference to it using getActivity(). Services are designed for doing work not visible to the user, including (but not limited to) background work on a separate thread from the UI thread. Services are more robust and offer more control over what work is being performed that is not visible to the user. They do not require an Activity to run.
An AsyncTask is a simple way of doing work from inside an Activity on a separate Thread from the UI thread.
Basically, you dont want or need an AsyncTask in a Service.
Instead, in your Service you should either spawn a Thread, or use IntentService which will handle creating a worker Thread for you. Then when you are finished, send an intent back to the Activity either by starting it or using a LocalBroadcast
Alternatively, you can tie a Service to an Activity and provide methods that the Service and Activity can call directly on each other through an IBinder interface. These are called bound services and will only be alive as long as the Activity is alive.
Try an IntentService
I think your best bet is to try learning how to use an IntentService
http://developer.android.com/reference/android/app/IntentService.html