1. Looper.prepare();
2. Handler mHandler = new Handler() {
3. public void handleMessage(Message msg) {}
4. };
5. mHandler.post(gpsLocationListenerThread);
6. Looper.loop();
7.
I'm calling a Thread class from AsyncTask. When i call it using code from 1-6, it creates the Thread and runs it. But AsyncTask get stucked there. I need to run this other Thread without blocking my AsyncTask. How to make it happen?
public GPSLocationListenerThread(Context context){
this.context = context;
mlocManager = (LocationManager)context.getSystemService(context.LOCATION_SERVICE);
mlocListener = new GPSLocationListener();
}
public void setHandler(Handler _h){
this.mHandler = _h;
}
public void run(){
mlocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10000, 100, mlocListener); // in 1000 mseconds or in 100m change
mlocManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 10000, 100, mlocListener); // in 1000 mseconds or in 100m change
//mHandler.getLooper().quit();
while (DataHolder.getDataHolderObject().isTripStarted()){
try {
this.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
mlocManager.removeUpdates(mlocListener);
}
Well you need to call Looper.quit(); anyway or it will never quit. Where you need to call it i have no idea unless you post a bit more code :)
Contrary to the documentation, it's not always needed to quit a looper.
And if you insist - you must call it on the same thread of the looper.
See my elaborate answer here.
Related
I have a Service which fetches some data from the web and updates a List which is "stored" in the Application.
Thus, i can access it from the main activity and use it for my ArrayAdapter.
When I update the data, the referenced item from the list is changed.
My Question is, how is the best practice to update the data in the Adapter in the main activity?
I have two solutions in mind, but I dont know if they are correct that way. Additional to that, I would like to implement a version which is not using much battery!
First: Thread which is called every second, updating the Adapter with notifyDataSetChanged():
private void startListUpdateThread()
{
Thread ListManageThread = new Thread() {
LinkItem listItem;
public void run() {
Log.d("DL", "List Update - start");
while(true)
{
runOnUiThread(UpdateGUIList);
try {
Thread.sleep(1000); //5Sekunden!
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e("DL", "ERROR: InterruptedException - " + e.getMessage());
}
}
}
};
ListManageThread.start();
}
private Runnable UpdateGUIList = new Runnable() {
#Override
public void run() {
mFileAdapter.notifyDataSetChanged();
}
};
Second: Using a delayed Handler post
private final Handler handler = new Handler();
private void startListUpdate()
{
handler.removeCallbacks(UpdateListUI);
handler.postDelayed(UpdateListUI, 1000); // 1 second
}
private Runnable UpdateListUI = new Runnable() {
public void run() {
//Remove Elements first
removeDeletedItemsFromList();
//Update Adapter
mFileAdapter.notifyDataSetChanged();
handler.postDelayed(this, 1500); // 1,5 seconds
}
};
So, whats the best way to do it? Perhaps there is also an other Way to do it, but of which I haven`t thought of before!
Instead of using the handler you will use the Async task. Though handler works here but it's JAVA concept and Async Task is Android.
And you can update the list view by using the : mFileAdapter.notifyDataSetChanged(); only it's correct.
Instead of using Handler and Thread you can use AlarmManager. Just start the Alarm once and it will update your list with the defined period of interval without any Thread or Handler. You had created a service and you can reference to that service using the AlarmManager.
AlarmManager mgr = (AlarmManager) arg0.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(arg0, TestService.class);
PendingIntent pi = PendingIntent.getService(arg0, 0, intent, 0);
mgr.setRepeating(AlarmManager.RTC_WAKEUP, 2000, 2000, pi);
And in the TestService you can have the code to update your List.
i have to get my location inside service from another class by this code
Mylocation mylol = new Mylocation();
private void locationClick() {
mylol.getLocation(this, locationResult);
mylol.cancelTimer();
// runDialog(3);
}
public LocationResult locationResult = new LocationResult(){
;
#Override
public void gotLocation(final Location location){
//Got the location!
double MyFinalLat=location.getLatitude();
double MyFinalLon=location.getLongitude();
Myloc=MyFinalLat+","+MyFinalLon;
Toast.makeText(getBaseContext(),"Your current location"+Myloc,
Toast.LENGTH_SHORT).show();
};
};
}
but i should make the gpss take his time to find locattion
how can i make my service slaaps for 20 secons for exampl??
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
my_button.setBackgroundResource(R.drawable.defaultcard);
}
}, 2000);
The code:
Thread.sleep(20000);
Will make the current thread sleep for 20 seconds. From an Activity, this would probably cause a force close, because it effectively make your process seem like it's locked up (I assume). In a Service, as you describe, you may be alright though.
BTW the 20 seconds isn't incredibly precise, as noted in the docs.
in the below code send() function is executing many times in a second,i want to execute send() once in a second,how i change the code
timer.scheduleAtFixedRate(
new TimerTask() {
public void run() {
try {
send();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
},
1000,
1000);
send function is given below
void send() throws Exception, IOException
{
s=new Socket("10.0.2.2",4200);
r=new PrintWriter(s.getOutputStream());
while(true)
{
Log.e("msg","hi send\n");
r.print("hai");
}
}
Logcat output is given below
I replaced timers with Runnables/Handlers recently, it's much easier
//declare at top of your activity
private Handler h = new Handler();
private Runnable myRunnable = new Runnable() {
public void run() {
//do stuff
//run again in one second
h.postDelayed(myRunnable, 1000);
}
};
//trigger the runnable somewhere in your code e.g. onClickHander or onCreate etc
h.postDelayed(myRunnable, 1000);
It happened for me when I used a TaskTimer and the phone got into sleep mode. I think it is related to TimerTask using Thread.sleep() to provide the timing. This relies on uptimeMillis() which according to documentation - 'is counted in milliseconds since the system was booted. This clock stops when the system enters deep sleep (CPU off, display dark, device waiting for external input), but is not affected by clock scaling, idle, or other power saving mechanisms. This is the basis for most interval timing such as Thread.sleep(millls)'
Solution would be either to use AlarmManager or WakeLocks.
an easier approach would look like this:
new Thread() {
public void run() {
while(true) {
send();
try{
Thread.sleep(1000); // pauses for 1 second
catch(Exception e) {}
}
}
}.start();
In my code i'm using an IntentService to listen to location updates (either GPS or network updates) and this IntentService is triggered when an event is received, so it is started with startService() from any activity.
public class AddLocationService extends IntentService implements LocationListener {
/*My code here*/
}
#Override
protected void onHandleIntent(Intent intent) {
if(getOldLoc() == null)
{
//Get a new location
this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, TIME_INTERVAL_GPS, 0, this);
this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, TIME_INTERVAL_GPS, 0, this);
Log.d(AddLocationService.TAG, "Network listener started");
this.time_start_listening = System.currentTimeMillis();
mTimerThread mTimerRunnable = new mTimerThread();
this.timerThread = new Thread(mTimerRunnable);
this.timerThread.start();
}
else
/*REUSE OLD LOCATION*/
}
Now my problem is : When two events start this IntentService and the second starts it while the first one is still requesting for updates, I will like the second one to wait until first one is fully finished (location found OR timer thread finishes).
However whenever the IntentService is executed a second time (first instance still running), it prints me the log and does as it was executing in parallel.
However I thought that the main goal of IntentService was that it is something sequential so a second intent would have to wait until first one is done...
Did I missunderstood something ?
It appears that your onHandleIntent method is not blocking the thread it is executing on, so it will return quickly and allow the second intent to be processed. Not only that, but any callbacks from the LocationManager to that thread are unlikely to be processed as the background thread is likely to be killed when onHandleIntent is finished.
If you really want to use IntentService to manage your intent queue then you will need to do your location handling on its own thread, and join the IntentService thread to the location thread whilst it is waiting for the location callback.
Heres a bit of code that demonstrates the idea:
public class TestService extends IntentService {
private static final String TAG = "TestService";
private Location mLocation = null;
public TestService() {
super(TAG);
}
#Override
public void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent");
if (mLocation == null) {
Log.d(TAG, "launching location thread");
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
LocationThread thread = new LocationThread(locationManager);
thread.start();
try {
thread.join(10000);
} catch (InterruptedException e) {
Log.d(TAG, "timeout");
return;
}
Log.d(TAG, "join finished, loc="+mLocation.toString());
} else {
Log.d(TAG, "using existing loc="+mLocation.toString());
}
}
private class LocationThread extends Thread implements LocationListener {
private LocationManager locationManager = null;
public LocationThread(LocationManager locationManager) {
super("UploaderService-Uploader");
this.locationManager = locationManager;
}
#Override
public void run() {
Log.d(TAG, "Thread.run");
Looper.prepare();
this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
Looper.loop();
}
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
Log.d(TAG, "onLocationChanged("+location.toString()+")");
mLocation = location;
Looper.myLooper().quit();
}
#Override
public void onProviderDisabled(String arg0) {
}
#Override
public void onProviderEnabled(String arg0) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
}
Of interest in there is the Looper that runs a message loop on the thread (to allow handling of the callbacks).
Given the effort required to do this with IntentService it might be worthwhile investigating deriving from Service instead and managing your own intent queue.
onHandleIntent is in it's own thread already. You don't (shouldn't) create on in there. It's all handled by IntentService for you.
Thanks a million, that is exactly what I needed to handle the location requests.
Thank you for explanations and making it clear for me, I wasn't very familiar with all the looper concept, now I understand it better !
In case someone need the same kind of thing, don't forget to stop the thread looper if your location thread is not stopping naturally (end of time on join(millis)), by adding this in onHandleIntent() :
if(thread.isAlive())
{
thread.onThreadStop();
try{
thread.interrupt();
}catch (Exception e) {
Log.d(TAG, "Exception on interrupt: " + e.getMessage());
}
}
after thread.join(yourTime), so for example if you didn't find any location update you still stop the thread after a certain time. And on method onThreadStop() :
/*We remove location updates here and stop the looper*/
public void onThreadStop()
{
this.locationManager1.removeUpdates(this);
handleLocationChange(AddLocationService.this.currentBestLocation);
Looper.myLooper().quit();
}
However I thought I saw my two intents being treated the first time I ran this code, but now only the first one is treated when I have multiple intents while still requesting location updates.
My method onHandleIntent() seems to execute correctly, stops the thread after the time specified and even displays the very last Log (last statement of the method) but the second intent is not executed...
Would you have any idea why ?
I created a class extending Thread to retrieve user location through LocationManager in a non-ui thread. I implemented this as a thread because it has to be started on request and do its work just for a limited time.
By the way, I had to add a Looper object in the thread, to be able to create the handler for the LocationManager (onLocationChanged).
This is the code:
public class UserLocationThread extends Thread implements LocationListener {
//...
public void run() {
try {
Looper.prepare();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
Looper.loop();
Looper.myLooper().quit();
} catch (Exception e) {
//...
}
}
#Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
//...
handler.sendMessage(msg); //this is the handler for communication with father thread
}
//...}
I would like the thread to start, receive the user location data (in this case just one time), send the data to the main thread via a message to the handler, and then die.
The problem is that in my case the thread does not die anymore, once the run method ended (that should be fine, because otherwise onLocationChanged would not receive the new locations).
But in this way, assuming that thread's stop and suspend methods are deprecated, what would be a good way, in this case at least, to make a thread with a looper die?
Thanks in advance ;)
You can explicitly quit from Looper's loop using Handler:
private Handler mUserLocationHandler = null;
private Handler handler = null;
public class UserLocationThread extends Thread implements LocationListener {
public void run() {
try {
Looper.prepare();
mUserLocationHandler = new Handler();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
Looper.loop();
} catch (Exception e) {
//...
}
}
#Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
//...
handler.sendMessage(msg);
if(mUserLocationHandler != null){
mUserLocationHandler.getLooper().quit();
}
}
"I implemented this as a tread because it has to be started on request and do its work just for a limited time."
This sounds like a perfect reason to simply reuse the main looper. There's no need to spawn a new Thread here. If you're doing blocking work (network I/O, etc) in onLocationChanged(), at that point you could spin up an ASyncTask.
Implement LocationListener on your Activity/Service or whatever and let it use the main looper by default.
Spawning a new thread, setting it to loop, and then immediately quitting is unnecessary.
IntentService is good for do this job.
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Looper().quit(); is good, and according to specification:
Causes the loop() method to terminate without processing any more messages in the message queue.
But, if you have a task that already is under processing, and you want to stop it too, you can acquire working thread and cause it to interrupt:
#Override
public void onLocationChanged(Location location) {
locationManager.removeUpdates(this);
handler.sendMessage(msg); //this is the handler for communication with father thread
if(mUserLocationHandler != null){
mUserLocationHandler.getLooper().quit();
mUserLocationHandler.getLooper().getThread().interrupt(); // <-- here
}
}
This works fine with most IO, and thread locking/waiting.
Extend the AsyncTask class. It does all the threading and handling for you automatically.