Android SignalR should be implemented as Service or IntentService? - java

On my Android App, I'm implementing SignalR connection (https://github.com/erizet/SignalA) to connect to a Hub server to send requests and receive responses.
a sample of my code is as follows:
signalAConnection = new com.zsoft.SignalA.Connection(Constants.getHubUrl(), this, new LongPollingTransport())
{
#Override
public void OnError(Exception exception)
{
}
#Override
public void OnMessage(String message)
{
}
#Override
public void OnStateChanged(StateBase oldState, StateBase newState)
{
}
};
if (signalAConnection != null)
signalAConnection.Start();
There's also the sending bit
signalAConnection.Send(hubMessageJson, new SendCallback()
{
public void OnError(Exception ex)
{
}
public void OnSent(CharSequence message)
{
}
});
The sending and receiving will occur across activites, and some responses will be sent at random times regardless of the activity, also, the connection should be opened as long as the app is running (even if the app is running in the background) that's why I wish to implement the signalA connection as a background service
The question is should I implement it as:
1 - a Service (http://developer.android.com/reference/android/app/Service.html)
OR
2 - an Intent Service (http://developer.android.com/training/run-background-service/create-service.html)
Keeping in mind that I will need to send strings to the service and get response strings from the service.
I would be most grateful if someone would show me how to implement this kind of connection in code as a background service/intentservice.
Thanks for reading.
UPDATE:
Please see this demo activity made by the developer as how he implemented SignalA
https://github.com/erizet/SignalA/blob/master/Demo/src/com/zsoft/SignalADemo/DemoActivity.java
The problem is AQuery (which I know nothing about) is being used in this demo activity. Does AQuery run in the background all the time ?
The problem is, the latest update on SignalA mentions the following
I have changed the transport. LongPolling now uses basic-http-client
instead of Aquery for http communication. I've removed all
dependencies on Aquery.
Hence I'm not sure whether I should follow this demo activity or not
Update 2:
This is the thing that is confusing me most
in the IntentService, the OnHandleIntent method calls stopSelf after it finishes its tasks, when I actually want the code in the IntentService to keep running all the time
protected abstract void onHandleIntent (Intent intent)
Added in API level 3
This method is invoked on the worker thread with a request to process. Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf().

SignalA is running on the thread that creates and starts the connection, but all network access is done in the background. The remaining work on the starting thread is really lightweight, hence its perfectly ok to do it on the UI tread.
To answer your question, you need to have a thread running the signala connection. Therefore I think a Service is the best choice since SignalA need to be running all the time.
Regarding Aquery and the demo project. I removed all dependencies to Aquery in the libraries, not in the Demo. To be clear, you don't need Aquery to run SignalA.

In my case, what I wanted was a Service not an Intent Service, since I wanted something that would keep running until the app closes

Related

Handling the closing of App By Android

I have created an App which requires to run a operation in background for quite some time suppose 10 - 15 mins.
I am running this operation in An AsyncTask. So during this time the user is minimizing the Screen and using his other apps in his phone as usual.
When this operation is started I am creating a Progress Dialog box and then keep updating it regularly.
But this is the error which I am receiving sometimes very rarely once the operation is over
Fatal Exception: java.lang.IllegalArgumentException
View=DecorView#1234567[ABC:] not attached to window manager PackageName
And this is the detailed stack log
Fatal Exception: java.lang.IllegalArgumentException
View=DecorView#1234567[ABC:] not attached to window manager PackageName
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:508)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:417)
at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.java:136)
at android.app.Dialog.dismissDialog(Dialog.java:446)
at android.app.Dialog.dismiss(Dialog.java:429)
at android.app.Dialog.cancel(Dialog.java:1353)
at PACKAGENAME
at android.app.Activity.runOnUiThread(Activity.java:6078)
at PACKAGENAME
at PACKAGENAME
at android.os.AsyncTask.finish(AsyncTask.java:667)
at android.os.AsyncTask.-wrap1(AsyncTask.java)
at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:684)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6823)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1557)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
To my knowledge this error is because the Android OS wanted to release some memory hence my App was closed since this was not visible to the user. But is there any way to tackle this thing?
Any help would be really appreciated.
EDIT: This is the code which I am using
public class load extends AsyncTask<Void, Void, Void> {
#Override
public Void doInBackground(Void... voids) {
for(int i=0;i<number;i++){
PerformSomeOperation();
UpdateTheProgress();
}
return null;
}
#Override
protected void onPostExecute(Void n) {
runOnUiThread(new Runnable() {
#Override
public void run() {
mProgressDialog.cancel();
CreateAnotherDialog();//This dialog is created to show the user completion of the progress.
}
});
}
You're having this crash because you're trying to update the UI when it's in the background so your Activity could be destroyed at that point. By the way, onPostExecute runs your code on the main thread already but as you're sending a separate message to the main looper you're postponing your logic a bit which can also cause a problem. Moreover, But the main question - why to update the UI if it's not visible to the user anyways?
Also, because you're using the AsyncTask as an inner class you may leak (though temporarily) your Activity object as it's referenced implicitly by the task.
From Android Documentation:
AsyncTasks should ideally be used for short operations (a few seconds
at the most.) If you need to keep threads running for long periods of
time, it is highly recommended you use the various APIs provided by
the java.util.concurrent package such as Executor, ThreadPoolExecutor
and FutureTask.
So, don't use AsyncTasks for long-running operations. A better approach would be to use:
IntentService together with BroadcastReceiver to communicate with your Activity / Fragment (in API >= 26 you should use JobIntentService as IntentService may misbehave due to new restrictions on background services).
RxAndroid (or just ExecutorService/Thread) together with Architecture-Components (more specifically with LiveData) - this way a result of your task can be cached or it can survive the config change.
My personal favourite is option 2.
There are few things to say: (1) the "onPostExecuted()" method is already executed on the UiThread/MainThread, so "runOnUiThread()" is not required. (2) if the Activity is minimized/destroyed when the Asynctask reach the final pass you get an Exception. So you have to check if the View is attached using "View. IsAttachedToWindow()" before execute some GUI methods like "mProgressDialog.cancel()". (3) you have to create a Thread or a Service to do a task that should run/work more than few seconds, or the System could kill it at anytime.

Multiple threads reading from same socket

I am developing an app which displays data from a server. The server is not mine and it is not very stable. Making too many connections crashes the server.
I have one socket to the server in my main activity, but at times I want to open sub activities which read the data and display it. My problem is that I am unable to achieve this with the same socket and have to open a new socket for every activity.
Every activity has a thread which does the reading from the socket and updates the UI elements on that activity as needed.
To use the same socket in multiple activities, I tried to close the inputReader of an activity before starting the new activity, but that simply make the application hang. If I leave it open, then the new thread in the new activity never receives any data. Killing the thread before starting the new activity is not possible because the thread is generally blocked by the read() function.
Is there anyway that I can have a centralized thread which does the reading and then sends the data to all the other threads in other activities so that I don't have to open new sockets in every activity?
I feel that this is a very basic thing that I am asking, but yet I am unable to find a solution.
A pretty straightforward and simple approach is the following:
You create a new Service which runs in the background and communicates with the server through your socket
The Service receives data from the socket and forwards/broadcasts it to all of your Activities which are interested in receiving it (for example to update the UI) by using the LocalBroadcastManager
All of your Activities implement a BroadcastReceiver and receive the data from your Service inside the onReceive() method
To accomplish that, you should read the introduction to Services and BroadcastReceivers to get an idea of how they work. Also to get a basic overview first, you should read about the available App Components.
EDIT, to answer the question in the comment:
You can always stop the Service by calling stopService() but you can also do it differently if you don't want/need all the functionality of a Service. Instead of a Service you could also create a simple Thread or a HandlerThread which communinicates with the server. From inside of your Thread, you can then forward/broadcast the data to your Activities by using the technique mentioned above (LocalBroadcastManager).
Just to give you an example of the basic structure (code untested though):
class SocketThread implements Runnable
{
static final String SOCKET_DATA_RECEIVED = "com.your.package.SOCKET_DATA_RECEIVED";
static final String SOCKET_DATA_IDENTIFIER = "com.your.package.SOCKET_DATA";
private Context context;
SocketThread(Context c) {
context = c.getApplicationContext();
}
#Override
public void run() { // code running in your thread
// fetch data from socket ...
Intent intent = new Intent();
intent.putExtra(SOCKET_DATA_IDENTIFIER, data); // store data in your intent
// send data to registered receivers
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
// your code ...
}
}
Then you have your Activities, for example MyActivity1, MyActivity2, ... MyActivityN. They all register their embedded SocketDataReceiver to receive the broadcast intent SOCKET_DATA_RECEIVED, which is sent by your thread.
Inside your onReceive() methods you can then extract the data from your intent object by using the identifier SOCKET_DATA_IDENTIFIER.
public class MyActivity1 extends Activity
{
private SocketDataReceiver socketDataReceiver;
#Override
protected void onResume() {
super.onResume();
socketDataReceiver = new SocketDataReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(
socketDataReceiver, new IntentFilter(SocketThread.SOCKET_DATA_RECEIVED));
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(socketDataReceiver);
}
private class SocketDataReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
// intent contains your socket data,
// get data from intent using SocketThread.SOCKET_DATA_IDENTIFIER
}
}
}
Basically you answered your question yourself:
I can have a centralized thread which does the reading and then sends the data to all the other threads in other activities.
Meaning: of course, such a thing is possible. But you have to sit down, design and implement it. You would start by defining a reasonable interface that allows your other threads to communicate with that central service, something like:
enum RequestType { DO_THIS, DO_THAT };
interface ServerConnectionService<T> {
List<T> performRequest(RequestType request);
}
Meaning: instead of having your different threads do "low level" talking on that socket, you create an abstraction that allows you to say: "when I need this kind of information, then I use my service; and it returns some specific answer to me). Of course, this is a very generic answer, but well, your question isn't exactly specific either.
The next step would then be to have some central (maybe singleton) implementation of that interface; which runs on its own thread, and can be used by other threads in a synchronized, well-defined way.
Final word of warning: if you don't own that server, and it has low quality and is causing trouble for you - that is not a good setup. Because no matter what you do in your code, if the server doesn't do a good job, users will perceive your app to be the problem. Users don't care if an operation fails because some remote server crashes. So the other aspect in your question is: right now, you are in a bad spot. You should spent some serious time to find ways out of there. Otherwise you will be wasting a lot of time to build workarounds for that server you are dealing with.

How do download managers work on Android?

I want to know mechanism of Download Managers (not the DownloadManager class introduced in API 9), as in my current project, I need to implement a few things same as download manager.
My basic understanding is that it uses a Service to download files. But what I cannot understand is how will it handle the multiple file download request, e.g. A file is currently being downloaded. Now user adds another file to be downloaded. I don't think a single Service can handle it. Can it? or is there some other method to do it? Any suggestions?
PS forgive me if the question is not clear enough because I myself don't understand my doubt very clearly. :(
They are using a MultiThreaded Socket Wheel.
Means, there is a ForegroundService which handle different Threads within the Service.
The ForegroundService make sure that it will be kept alive. The Threads itself are single Processes which run in a Background Thread.
Threre are several ThreadExecutors available which make sure that you have only a few Threads running paralell or process them thread by thread.
Here is a good tutorial making a SocketWheel http://www.javaspecialists.eu/archive/Issue023.html
Sources:
ThreadExecutor http://developer.android.com/reference/java/util/concurrent/ThreadPoolExecutor.html
ThreadPoolExecutor ExectuorService vs ThreadPoolExecutor (which is using LinkedBlockingQueue)
ForegroundService Android - implementing startForeground for a service?
Edited: for some code
public class DLService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Notification note=new Notification(R.drawable.somegraphics, "some title", randomnr);
Intent i=new Intent(this, ActivityClassToOpenWhenClicked.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi=PendingIntent.getActivity(this, 0, i, 0);
note.setLatestEventInfo(this, "downloadmanager","downloading.. nothing", pi);
note.flags|=Notification.FLAG_NO_CLEAR;
startForeground(1337, note);
// if (intent.hasExtra("dlurl")) {
new Thread(new Runnable() {
public void run() {
new Client("http://yourfile.com/file.jpg");
}
}).start();
return START_NOT_STICKY;
}
class Client {
public Client(String filetodownload) throws Exception {
//do your http connection. for example one download #
// HttpUrlConnection httpConnection = new .....
}
}
}
Its just a quick coded example, not tested. But it shows the concept.
The service itself accept a Intent which can be a url where the file is located. Then it creates a new Thread which do the job. The Thread will run aslong as it takes to download the file. The foregroundService makes sure that the Service will be kept alive. You can also create a ThreadPoolExecutor which handle multiple Thread at onec. Read http://developer.android.com/training/multiple-threads/create-threadpool.html for instructions.

Android Threads, Services, and two way communication between them

I'm struggling to wrap my head around what needs to happen here. I'm currently working on an app that runs a service. The service when started opens a webserver that runs in a background thread.
At any point while this service is running the user can send commands to the device from a browser. The current sequence of events is as follows.
User sends request to server
Server sends a message to the service via the msg handler construct, it sends data such as the url parameters
The service does what it wants with the data, and wants to send some feedback message to the user in the browser
?????
The server's response to the request contains a feed back message from the service.
The way my functions are set up I need to pause my serve() function while waiting for a response from the service and then once the message is received resume and send an http response.
WebServer.java
public Response serve( String uri, String method, Properties header, Properties parms, Properties files )
{
Bundle b = Utilities.convertToBundle(parms);
Message msg = new Message();
msg.setData(b);
handler.sendMessage(msg);
//sending a message to the handler in the service
return new NanoHTTPD.Response();
}
CommandService.java
public class CommandService extends Service {
private WebServer webserver;
public Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
execute_command(msg.getData());//some type of message should be sent back after this executes
};
Any suggestions? Is this structure the best way to go about it, or can you think of a better design that would lead to a cleaner implementation?
I think the lack of answers is because you haven't been very specific in what your question is. In my experience it's easier to get answers to simple or direct questions that general architecture advice on StackOverflow.
I'm no expert on Android but I'll give it a shot. My question is why you have a Webservice running in the background of a Service, why not just have one class, make your Service the Webservice?
Regarding threading and communication and sleeping, the main thing to remember is that a webserver needs to always be available to serve new requests, whilst serving current requests. Other than that, it's normal that a client will wait for a thread to complete its task (i.e. the thread "blocks"). So most webservers spawn new a thread to handle each request that comes in. If you have a background thread but you block the initial thread while you wait for the background thread to complete its task, then you're no better off than just completing everything on the one thread. Actually, the latter would be preferable for the sake of simplicity.
If Android is actually spawning new threads for you when requests come in, then there's no need for a background thread. Just do everything synchronously on one thread and rejoice in the simplicity!

how to schedule some code execution in android or: what exactly are daemon threads in android?

i'm currently working on an app for the android os that requires to fetch data from a remote server from time to time.
as this "update" should be carried out even when the actual frontend app is not running, i implemented a remote service that is started on system boot. now i need to schedule a timer to start the update.
is the "Timer"-class the right one for this job? and if "yes": what is the difference between a "normal" Timer() and one started as a "daemon" by Timer(true)?
http://developer.android.com/reference/java/util/Timer.html isn't very helpful with this :(
EDIT:
ok - i see there are much more methods to do this than i expected. to clarify:
i want to execute some code at a time that is specified.
this timer is used to trigger the execution of code 7 days in the future. (i.e., every week at a given weekday and time)
the code should run WITHOUT waking the phone up if it is "sleeping" (screen dimmed).
when running the code, no activity should be started. i.e. no app pops up on the screen.
the code that is executed should fetch some data from the internet. if at this time no internet connection is available, the timer should be set to sth like 30 minutes and then try again.
after completing the code execution, the timer will be set for the next interval which will be 7 days later.
the timer should be started at system boot, e.g., if i reboot the phone, the timer should determine the next date to execute the code and schedule the timer. this has to work without ANY user interaction!
when "sleeping", the thread/service/timer/whatsoever should not consume any system resources if possible...
what i need is pretty much a simple unix cronjob.
i think anyone here knows "newsrob" for android? what i want to realize is pretty much the same as the newsrob-updateservice.
Use AlarmManager. This allows you to set your schedule, then exit your components. Your code does not need to remain in memory and will be triggered when the alarm sounds.
i implemented a remote service that is started on system boot
Please don't do that just for a scheduled task. Use AlarmManager.
If you want the work to be done while the phone is asleep, you will need to use a _WAKEUP alarm type and perhaps use something like my WakefulIntentService to keep the device awake while the work is being done.
I recently had to develop an application following the same pattern.
Here is how I designed it:
I created a service started either explicitely by the frontend when enabling it through a configuration dialog, either started by a BroadcastReceiver waiting for the activation of network connectivity:
<receiver android:name=".notifications.MyReceiver">
<intent-filter>
<action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
The service, when started, starts a new HandlerThread, and associates it with a Looper:
public class MyService extends Service {
private Looper serviceLooper;
private MyHandler serviceHandler;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
//Toast.makeText(this, "service started", Toast.LENGTH_SHORT).show();
HandlerThread thread = new HandlerThread("MyHandlerThread", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
serviceLooper = thread.getLooper();
serviceHandler = new MyHandler(this, serviceLooper);
// initial message
serviceHandler.sendMessage(Message.obtain());
}
#Override
public void onDestroy() {
serviceLooper.quit();
//Toast.makeText(this, "service stopped", Toast.LENGTH_SHORT).show();
}
}
When the network goes down or if the frontend disables it, the service is stopped, as well as the looper.
Now, in the MyHandler, I actually get the updates from the server when receiving messages.
public class MyHandler extends Handler {
private final Context context;
public MyHandler(Context context, Looper looper) {
super(looper);
this.context = context;
}
#Override
public void handleMessage(Message msg) {
// handle message and perform update
// ...
// try again 30 minutes
this.sendMessageDelayed(Message.obtain(), 1000 * 60 * 30);
}
}
The trick as you can see, is to send itself a delayed message to be handled 30 minutes later.
The advantage of this solution over using the AlarmManager is that the phone will NOT be forcibly woken up at a designed time, meaning it plays nicer with the phone resources if not needed.
Moreover, I don't start the service at boot time, only when there's an active internet connexion, and I stop it as soon as the connexion is gone.
It's been pretty efficient so far.

Categories