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
Related
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.
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.
A game I wrote some time ago has a problem with ANRs, and debugging suggests they're down to HTTP requests taking a long time (and thus causing the ANR).
I'd thought that by assigning the HTTP code into a Runnable called from within a Handler, I'd could avoid the ANR - but it seems this isn't the case?
The stack dumps suggest the runnable/handler code is still running within the 'Main' thread and thus still causes ANRs??
The task it's doing is asynchronous (uploading highscores and achievements) and so can be started and left to it's own devices entirely - what is the best way to implement this so that ANRs aren't going to become a problem?
One topic suggested that the Handler should be created in the Application class and not within the Game's Activity - but I can't find any detail on the differences between those cases??
All ideas greatly apprec.
p.s. extending this to ask - I assume an ANR relating to HTTP comes down to the phone being out-of-service/network/WiFi, because I've set a SHORT timeout for these requests (they're non-essential and can be retried later!?)
A Handler will execute code / handle messages per default (any constructor without Looper e.g. new Handler()) in the current thread. That is in almost every case the main thread. If you want it to execute in a different thread you have to tell it which Looper thread it should use.
Android has a utility class called HandlerThread that creates a Thread with a Looper.
Short example:
public class MyActivity extends Activity {
private Handler mHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
HandlerThread handlerThread = new HandlerThread("background-handler");
handlerThread.start();
Looper looper = handlerThread.getLooper();
mHandler = new Handler(looper);
mHandler.post(new Runnable() {
public void run() {
// code executed in handlerThread
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
// stops the HandlerThread
mHandler.getLooper().quit();
}
}
In case your task needs only a some information and does not need to report back, I'd go with an IntentService. Those don't go mad if your Activity-lifecycle recreates the Activity.
You would create a small Service in it's own file
public class SaveService extends IntentService {
public SaveService() {
super("SaveService");
}
#Override
protected void onHandleIntent(Intent intent) {
if ("com.example.action.SAVE".equals(intent.getAction())) {
String player = intent.getStringExtra("com.example.player");
int score = intent.getIntExtra("com.example.score", -1);
magicHttpSave(player, score); // assuming there is an implementation here
}
}
}
Add it to the AndroidManifest.xml
<application ....
<service android:name=".SaveService" />
</application>
And in your code start it with
Intent intent = new Intent(this /* context */, SaveService.class);
intent.setAction("com.example.action.SAVE");
intent.putExtra("com.example.player", "John123");
intent.putExtra("com.example.score", 5123);
startService(intent);
IntentService#onHandleIntent() runs on a background thread already so you don't have to bother about that.
Your Handler runs on the main thread. That is what causes ANR.
Even if you create it in the Application, by default (no parameters given to Handler) will be created on the main thread. You have to create a Looper, with its own Thread. See here.
A Handler initialized with your own Looper, that is a viable option to solve ANR...
A more simple alternative solution can be, if you place your async network operation into an AsyncTask. A simple approach is to place the AsyncTask into your Activity. A somewhat more complex could be to create a Service (holder for non-ui related functionality), that does the communication, and cleans itself from memory, once the communication is over...
I'd use AsyncTask and place it into the Activity / fire it up from the Activity...
Finally, HERE you can find a nice tutorial on threads in android.
I have a service, that when starting, fires up a thread which is supposed to be the "main thread" of the service. The service is bound to two other services which is part of a library that I'm using. In this thread, I want to handle messages that is sent to the service from the services it is bound to (because this is how it works with binding... right?). The binding goes well (returns true) but my problem is that I can't seem to receive any messages at all. A description of my setup follows:
The Service:
class MyService extends Service {
onCreate(...) {
myServiceApp = new MyServiceApp(this);
}
onStartCommand(...) {
Thread thread = new Thread(myServiceApp);
thread.start();
}
}
The Main Thread Class:
class MyServiceApp() {
private Service service;
final Handler mHandler = new Handler() {
void handleMessage(Message msg) {
...
}
};
void run() {
boolean as = service.bindService(new Intent(...), ..., Context.BIND_AUTO_CREATE));
boolean ctrl = service.bindService(new Intent(...), ..., Context.BIND_AUTO_CREATE));
Looper.prepare();
while(true) {
...
}
}
}
Now, I know that to be able to declare a handler like this, I need a message loop for the thread, so I call prepare() in the run method. I also felt like I need to run through the message loop every turn in my while loop, so I added a Looper.loop() there, but that just made the application hang on that line.
So my question is, how do I solve the problem and have the messages delivered where I want? I'm aware of that my app architecture might not be optimal, so feel free to give suggestions on how to improve it.
In order to execute some IO operations in my app I wrote a thread, there's nothing on its run method but it has several other methods, like void write(String filename, String data) and void create(String filename), all of which work like a charm. My question is, I used to think this thread was running on the background or something like this but since after removing the .run() statement on my main activity calling said methods still works, how can I have a thread running and waiting for a message from the activity without blocking the app? And second question, since the methods are still working does it mean they are being executed on the main UI thread when I call them from my main activity?
You should use the start() method, instead of the run().
With run() you are running the given Runnable in the calling thread.
With start() you are starting a new thread that handles this Runnable
For the methods to run on the said thread you will have to have to call your methods from the thread and not from any other thread.
class WorkerThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
Then use WorkerThread.mHandler.postRunnable or sendMesssage for the work to be done on another thread.
In order to make a que for processing stuff when delivered, you need to make use of android's native stuff which is the best option available:
HandlerThread
Looper
Handler
Message
For examples, read this and this.