I'm a student writing some app to understand and study Android Development.
I'm trying to write an app the should work like this:
MapActivity:
Show a map with user position and open Access point in a range.
User and AP position should be received by the "MainClass".
MainClass:
This should do the main work. It should get user position, get open access point from db and insert into the db new open AP found with WifiManager scans.
Now, the MainClass should work in background, on user agree, even if the app is closed.
My questions are:
Should I do MainClass stuff on a new thread or on the UI thread?
Should MainClass be an AsyncTask, Service or other? please tell me why too.
the scan operation return a scan that get executed in a registered receiver. Does it run on UI thread or in a new one?
Thanks in advance.
UPDATE;
So, if i'm not messing what are you saying, the service should look like this:
public class MainService extends Service {
Thread mainThread;
#Override
public void onCreate() {
mainThread = new Thread(new Runnable() {
#Override
public void run() {
....
mainOperation();
....
}
});
mainThread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
mainThread.run();
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}
does START_STICKY on kill call onStartCommand or onCreate?
Should I do MainClass stuff on a new thread or on the UI thread?
Answer:
You should do on the background thread (new thread) because android does not allow network tasks on UI thread also if you do time taking operation on UI thread UI will freeze
Should MainClass be an AsyncTask, Service or other? please tell me why too.
Answer:
As you clearly said your requirement (MainClass should work in background) you need to use Service because service runs in background even when your app is killed
You should use MainClass.java stuff into a background thread. i.e., Service
Service will trigger data through Broadcast receiver.
Broadcast receiver will send data to MapActivity.java. Registered receiver's onReceive() method always run in the UI thread.
If you want to run MainClass.java stuff in foreground you can use MVP pattern. You should do your stuff into presentation layer.
Background Service will be the best and only solution for your requirements I guess. Because you want your operation to keep running even when your app is closed.
Related
I've have develop an android application with an IntentService.
This IntentService does nothing more like a fileupload.
I just want to implement the functionality to upload multiple "file-upload-threads".
The problem is to stop one specified "file-upload-thread".
For example:
User choose ten files from the device and upload these.
A notification is created to gives the user "transfer-feedback".
While the thread is working the user can choose other files to upload.
Another notification is created but does not start until the first thread is done.
Is it possible to implement a "cancel-functionality" for the user to cancel the first thread and the second thread start automatically?!
Maybe is it better to user an Service instead of an IntentService?
IntentServices are designed to run-one-at-a-time. Of course you could cancel your IntentService since in inherits from Service.
class MyService extends IntentService {
public static volatile boolean shouldStop = false;
public MyService() {
super("My Service");
}
#Override
protected void onHandleIntent(Intent intent) {
doStuff();
}
private void doStuff() {
// do something
// continue doing something
// put those checks wherever you need
// check the condition
if (shouldStop) {
stopSelf();
return;
}
}
}
And from your activity code you can change the state of the boolean flag to true if you want to stop the service. Hope this will help you.
An IntentService is designed to stop itself only when all the requests present in the work queue have been handled.As per docs,IntentService class "Stops the service after all of the start requests are handled, so you never have to call stopSelf()
In case you want to cancel requests,you can probably use volley and cancel previous requests
https://developer.android.com/training/volley/simple.html#cancel
I am trying to develop a application in android that consists a service to read the sensor value for multiple hours. When i start the service my device get hang and all the other process is got slow. To solve this problem i have try to startservice in separate thread as given below but problem is still there.
new Thread(new Runnable() {
#Override
public void run() {
Intent intent=new Intent(getApplicationContext(), SensorService.class);
startService(intent);
}
}).start();
this thread only start the service in different thread but service run in main thread.
Plz someone help me how to run service in separate thread ?
Application components (services, activities, etc) always run in main thread, no matter what thread they are started from.
Consider starting thread in your Service instead, or use an IntentService.
In your particular case you might try to register a global BroadcastReceiver for sensor changes, which, in turn,will start an IntentService to put newly acquired values in db, etc.
Actually, here is the link to similar question solved.
Again, this is not really a multithreading issue. The whole task must be implemented the other way.
You can use Background Services to solve this problem. By using a Thread with sleep() for particular instance will give the solution to yours problem
Background Servies
This link Will help you..
Or Using of PendingIntent will help you, like...
PendingIntent operation = PendingIntent.getActivity(getBaseContext(), 0, ij, Intent.FLAG_ACTIVITY_NEW_TASK);
All you are doing there is launching the new activity, so if your logic for running the monitor is in SensorService, then it's still going to be on the main thread. You need to put the monitoring logic into the new thread, not just launch the activity with it.
If you are trying to run a service on a background thread you need to use the static performOnBackgrounThread method like this code which can be found in the Android documentation (android-8\SampleSyncAdapter\src\com\example\android\samplesync\client\NetworkUtilities.java):
public static Thread performOnBackgroundThread(final Runnable runnable) {
final Thread t = new Thread() {
#Override
public void run() {
try {
runnable.run();
} finally {
}
}
};
t.start();
return t;
}
It is also important to remember that you never want to perform network operations on the Main UI thread. Not that you have here, just a FYI...
I think the answer to this problem lies in the power of IntentService. IntentService is a subclass of the regular Service class. There are a few key differences, however.
Now, here's how you can take IntentServices to your advantage: IntentServices do not run on the main thread. Instead, they run on separate "Worker threads". This single attribute would solve your problem and eradicate the ANRs you are currently facing.
To learn more about the differences between services and IntentServices, check this out.
To start service in the same process but another non-main thread, we can create another HandlerThread and use Handler for running our jobs on it.
class MyService : Service() {
private lateinit var thread: HandlerThread
private lateinit var handler: Handler
override fun onCreate() {
super.onCreate()
thread = HandlerThread("MyService").apply {
start()
}
handler = Handler(thread.looper)
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent?.action == "my-job") {
handler.post {
// Do any job on another non-main thread here
// ...
}
}
}
override fun onDestroy() {
thread.interrupt()
super.onDestroy()
}
}
you can try using AsyncTask, please read this documentation.
http://developer.android.com/reference/android/os/AsyncTask.html
while it is very convenient to use, from my understanding, AsyncTask has two important limitations:
doInBackground of any instances will share the same worker
thread, i.e. one long running AsyncTasks can block all others.
execute, onPostExecute and other "synchronizing" methods must/will always be executed on the UI-thread, i.e. not on the Thread, which wants to start the task.
I ran into trouble, when I tried to reuse some existing AsyncTasks in a background IntentService that are responsible for the client-server communication of my app. The tasks of the service would fight over time in the worker thread with those of the UI activities. Also they would force the service to fall back onto the UI-thread, although that service should perform its work quietly in the background.
How would I go about removing/circumventing these limitations? I basically want to achieve:
A framework that closely resembles AsyncTask (because I need to migrate a lot of critical code there).
Each instance of such a task should run its doInBackground on its own thread instead of a single worker thread for all instances.
Edit: Thx to VinceFR for pointing out this can be achieved by simply calling executeOnExecutor instead of execute.
The callbacks like onPostExecute should be called on the same thread that started the task by calling execute, which should not need to be the UI-thread.
I figure, I'm not the first person to require something like this. Therefore I wonder: Is there already some third-party library that can be recommended to accomplish this? If not, what would be a way to implement this?
Thanks in advance!
The solution looks like this:
All classes that spawn AsyncTasks that might interfere with each other get their own Executor like this one (make that elaborate as you like using thread pools etc.):
private Executor serviceExecutor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
As pointed out by VinceFR you can run an AsyncTask on a given Executor by calling it like this (where payload are the parameters that you would regularly pass to a task):
task.executeOnExecutor(serviceExecutor, payload);
However, this breaks backwards-compatibility to Gingerbread and earlier. Also, if you want to support Honeycomb, you need to make sure, this call happens on the UI thread. Jelly Bean will take care of this automatically.
Now the trickier part: Keeping the service running on its own thread. As many things in Android this seems harder than it needs to be (or maybe I'm lacking some information here). You can't use an IntentService, because that will shut down automatically the first time an AsyncTask takes over and let's the onHandleIntent callback complete.
You need to setup your own thread and event loop on the service:
public class AsyncService extends Service {
private static final String TAG = AsyncService.class.getSimpleName();
private class LooperThread extends Thread {
public Handler threadHandler = null;
public void run() {
Looper.prepare();
this.threadHandler = new Handler();
Looper.loop();
}
}
private LooperThread serviceThread = null;
private Handler serviceThreadHandler = null;
#Override
// This happens on the UI thread
public void onCreate() {
super.onCreate();
}
#Override
// This happens on the UI thread
public int onStartCommand(Intent intent, int flags, int startId) {
this.serviceThread = new LooperThread();
this.serviceThread.start();
while(this.serviceThread.threadHandler == null) {
Log.d(TAG, "Waiting for service thread to start...");
}
this.serviceThreadHandler = this.serviceThread.threadHandler;
this.serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheFirstThingOnTheServiceThread();
}
});
return Service.START_STICKY;
}
// doTheFirstThingOnTheServiceThread
}
No you need to make sure that each time an AsyncTask returns to the UI thread, you end up in your service thread instead:
// This happens on the serviceThread
private void doTheFirstThingOnTheServiceThread() {
// do some stuff
// here we can reuse a class that performs some work on an AsyncTask
ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
// the existing class performs some work on an AsyncTask and reports back via an observer interface
someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
#Override
// This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
public void onOperationComplete() {
serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheSecondThingOnTheServiceThread();
}
});
}
}
someUsefulObject.performOperation();
}
// This happens on the serviceThread
private void doTheSecondThingOnTheServiceThread() {
// continue working on the serviceThread
}
So, this works for me. I'd be delighted to see a simpler solution for this. Note that the solution requires the service to know that is will be called back by the ExistingClassWithAsyncOperation on the UI thread. I don't particularly like this dependency, but don't know how to do better right now. However, I don't have to rewrite a lot of existing classes that perform asynchronous operations using AsyncTask.
I'm developing an Android app that needs to do some updating in the background every hour or so. I have a background service which I've made Sticky. And I'm using Timer.scheduleAtFixedRate to schedule the updates.
This seems to work fine. But I've noticed that when I close the app, the next time the scheduled update runs, it causes Application.onCreate to get called again.
This is a problem because Application.onCreate is where I'm grabbing data down from APIs ready to display to the user. I don't want this to happen in the background.
Is this expected behaviour? If so, perhaps I need to add a check in onCreate to see if the app is in the foreground first? Or maybe I've got something set up wrong?
Thanks!
p.s. It's a Galaxy Samsung running Jelly Bean 4.2.1
Background Service code:
#EService
public class BackgroundService extends Service {
...
private Timer timer = new Timer();
private void performUpdate() {
// Do the stuff here that we need to do on a schedule...
Log.i(LOG_CONTEXT, "Perform scheduled update");
...
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(LOG_CONTEXT, "Background thread started");
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
performUpdate();
}
}, 0, UPDATE_INTERVAL);
// Sticky means service will continue running until explicitly stopped
return START_STICKY;
}
#Override
public void onDestroy() {
Log.d(LOG_CONTEXT, "Background thread stopped");
timer.cancel();
}
}
Application code:
#EApplication
public class MyApplication extends Application {
...
#Override
public void onCreate() {
super.onCreate();
initApp();
}
private void initApp() {
// This is where I want to do stuff when the app is actually
// opened by the user, not every time the background service
// update occurs!
Log.i(LOG_CONTEXT, "Initialise. Why does this happen again after app's closed?");
...
}
...
Log:
12-09 16:28:15.828: I/MyApplication(3049): Initialise. Why does this happen again after app's closed?
[Now I close the app, by pressing the Recent Apps menu button and swiping it away]
12-09 16:28:16.015: I/BackgroundService(3049): Perform scheduled update
12-09 16:28:33.875: I/MyApplication(3080): Initialise. Why does this happen again after app's closed?
Your service runs as a part of your application, so the application is created for it.
Most apps do not need to extend Application. Without seeing all of your code, I'm pretty sure you don't need to either. Just extend Activity for the class that displays stuff to the user and do the API stuff in that. That will not be created when the service runs.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Android Service makes Activity not responding
I use service to synchronize data between database and view. But the service does not work properly, whenever I use service to work long task, the view stop response (I can't do any event in UI) and I have to wait the service has done. Here is my service:
public class SyncService extends Service{
private static final String TAG = "SyncService";
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onDestroy()
{
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent)
{
Log.d(TAG, "call onBind");
return new DataManagerBinder();
}
private class DataManagerBinder extends Binder implements IUserDataManager
{
#Override
public void doProcess(Activity mView)
{
//do some long task (not touch UI thread)
// this will cause the view not response
syncDB();
// update view after process completed
mView.updateViewOnComplete();
}
}
I try to bind this service in client activity
//the interface to handle binder
IUserDataManager viewManager = null;
ServiceConnection serviceConnection = new ServiceConnection()
{
#Override
public void onServiceDisconnected(ComponentName name)
{
Log.i(TAG, "connection closed unexpectedly");
viewManager = null;
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder)
{
Log.d(TAG, "serviceConnection onServiceConnected");
viewManager = (IUserDataManager) binder;
viewManager.doProcess(MyActivity.this);
}
};
Intent intent = new Intent(MyActivity.this, SyncService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
Please give me the solution for that. Thanks in advance!
While others have given some responses, I don't know if the main point has been emphasized:
While a Service sounds like something that would automatically run in the background, it does not. It's merely a piece of code that can react to intents without maintaining a UI. However, the UI thread still does the processing for the Service.
By contrast, it looks like what you want, is a Service that sits in the background and does some work in a background thread. You will use the Service class to spawn a new thread, this is typically done on response to some intent, which you can define (usually in your onStart() or something similar). You will probably start a new thread which actually does the work updating the database, etc..., and use your main Service to coordinate to that thread.
As it looks like you also want to communicate with the service, you will have to implement an appropriate Messenger and Handler pair to keep track of messages you pass between the UI and the Service (coordinating a background thread), and also (possibly) some way (also perhaps a messenger) of coordinating between the Service and the background thread.
As others have noted, you can also use AsyncTask to do things on the UI thread and use a background thread "seamlessly."
Read up on the docs regarding services, specifically the "What is a Service?" paragraph. The service runs on the main UI thread. Take a look at AsyncTask, should solve your issue. The work here is done in a background thread, and the results are sent back to the UI thread.
Android closes service after sometime to save resources.
However you can prevent this from happening using something like
int onStartCommand(Intent, int, int){
return START_STICKY;
}
ref this