I am new to Java and since this question belongs to a very time sensitive project for my work, I dont have the time to learn everything about AsyncTasks.
So my question is:
How do I construct an AsyncTaskout of the following code?
The goal is to draw a route on a map. I fill the ArrayListwith two Geopoints (start-location and the destination of the route). The roadManager is supposed to send those waypoints to a server that sends me back the route.
buildRoadOverlay is the method that finally draws the route on the map.
RoadManager roadManager = new OSRMRoadManager(this);
ArrayList<GeoPoint> waypoints = new ArrayList<GeoPoint>();
GeoPoint myLocation = new GeoPoint(51.488978, 6.746994);
waypoints.add(Location);
waypoints.add(myLocation);
Road road = roadManager.getRoad(waypoints);
I guess this has to go in the onPostExecute -method, right?:
Polyline roadOverlay = RoadManager.buildRoadOverlay(road);
map.getOverlays().add(roadOverlay);
The variable location from the upper code originates from a different method, from which I intend to start the Async task. Meaning, I need to transmit the variable to the AsyncTask when calling it, which I am also not sure how to do exactly.
This is the initialization of the variable location:
GeoPoint Location = new GeoPoint(Double.parseDouble(place.getLongitude()),
Double.parseDouble(place.getLatitude()));
Put the time consuming task in doInBackground(), udpate view in onPostExecute().
public void drawRouteAsync() {
GeoPoint location = new GeoPoint(Double.parseDouble(place.getLongitude()),
Double.parseDouble(place.getLatitude()));
GeoPoint myLocation = new GeoPoint(51.488978, 6.746994);
new RouteAsyncTask().execute(location, myLocation);
}
private class RouteAsyncTask extends AsyncTask<GeoPoint, Void, Road> {
#Override
protected Road doInBackground(GeoPoint... params) {
ArrayList<GeoPoint> waypoints = new ArrayList<GeoPoint>();
waypoints.add(params[0]); // location
waypoints.add(params[1]); // myLocation
RoadManager roadManager = new OSRMRoadManager(mContext); // your context
Road road = roadManager.getRoad(waypoints); // time consuming
return road;
}
#Override
protected void onPostExecute(Road road) {
Polyline roadOverlay = RoadManager.buildRoadOverlay(road);
map.getOverlays().add(roadOverlay); // update view
}
}
AsyncTask have 3 important methods:
protected void onPreExecute() //main thread
protected E doInBackground(T... params) //async thread
protected void onPostExecute(E result) //main thread
E and T will be definded in implementation.
So knowing this, your AsincTask should look somthing like this:
public class GetRouteTask extends AsyncTask<GeoPoint, Void, Integer> {
private Context mContext;
private OnGetRouteCompleted delegate;
private Road route;
public GetRouteTask (Context context, OnGetRouteCompleted delegate) {
this.delegate = delegate;
this.mContext = context;
}
#Override
protected Integer doInBackground(GeoPoint... params) {
ArrayList<GeoPoint> wayPoints = new ArrayList<GeoPoint>();
wayPoints.add(params[0]); // pointFrom
wayPoints.add(params[1]); // pointTo
try {
RoadManager roadManager = new OSRMRoadManager(mContext);
route = roadManager.getRoad(waypoints);
return 1;
} catch (JSONException e) {
return -1;
}
}
#Override
protected void onPostExecute(Integer success) {
if (success == 1) {
delegate.onGetRouteCompleted(true, route);
} else {
delegate.onGetRouteCompleted(false, null);
}
Polyline roadOverlay = RoadManager.buildRoadOverlay(road);
map.getOverlays().add(roadOverlay); // update view
}
public interface OnGetRouteCompleted {
public void onGetRouteCompleted(boolean success, Route route);
}
}
And this how you use it:
public class SomeActivity extend Activity implements OnGetRouteCompleted {
// Methods and properties...
public void drawRouteAsync() {
GeoPoint pointFrom = new GeoPoint(51.489878, 6.143294);
GeoPoint pointTo = new GeoPoint(51.488978, 6.746994);
new GetRouteTask(getApplicationContext(), this).execute(new GeoPoint(){pointFrom , pointTo});
}
#Override
public void onGetRouteCompleted(boolean success, Route route) {
if (success) {
Polyline roadOverlay = RoadManager.buildRoadOverlay(route);
map.getOverlays().add(roadOverlay); // update view
}
}
}
Related
Hi I 'm new to Android programming and I have an app that when user clicks on a country it starts another activity displaying an a map with a marker locating the capital city.
But I need to get the capital from my async task method.So it needs to return country info and then I can update my map.I called my update map method in onPost Execute but the app just crashes?
In my on Create
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync( this);
new GetCountryDetails().execute(selectedCountry);
Then in my Async task
private class GetCountryDetails extends AsyncTask<String, String, CountryInfo> {
#Override
protected CountryInfo doInBackground(String... params) {
CountryInfo countryInfo = null;
In my onPostExecute
protected void onPostExecute(CountryInfo countryInfo) {
countryCapital=countryInfo.getCapital();
updateMap(map);//doesn't work here
onMapReady:
public void onMapReady(GoogleMap map) {
map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
map.getUiSettings().setMapToolbarEnabled(true);
updateMap
public void updateMap(GoogleMap map){
LatLng capitalCity = getCityLatitude(this, countryCapital);
map.moveCamera(CameraUpdateFactory.newLatLng(capitalCity));
MarkerOptions marker = new MarkerOptions().position(capitalCity).title( countryCapital);
map.addMarker(marker);
}
Any help will be appreciated thank!
I
Create Map varible as activity field.And define variable in onMapReady function.After that use activity variable as you want. I think it should works.
GoogleMap map;
public void onMapReady(GoogleMap map) {
this.map = map;
map.setMapType(GoogleMap.MAP_TYPE_HYBRID);
map.getUiSettings().setMapToolbarEnabled(true);
}
below code snippet works perfectly for me. Please try it out.
private GoogleMap mMap;
ArrayList<LatLngBean> arrayList;
private ArrayList<LatLng> listLatLng;
add below code in onPostExecute method
LatLngBean bean = new LatLngBean();
bean.setTitle(jobj.getString(""));
bean.setSnippet("Hello, " + jobj.getString(""));
bean.setLatitude(jobj.getString("latitude"));
bean.setLongitude(jobj.getString("longitude"));
arrayList.add(bean);
runOnUiThread(new Runnable() {
#Override
public void run() {
mapFragment.getMapAsync(YourActivity.this);
}
});
and then add below code onMapReady() method
#Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
if (arrayList.size() > 0) {
try {
listLatLng = new ArrayList<>();
for (int i = 0; i < arrayList.size(); i++) {
final LatLngBean bean = arrayList.get(i);
double lat = Double.parseDouble(bean.getLatitude());
double lon = Double.parseDouble(bean.getLongitude());
LatLng latLng = new LatLng(lat, lon);
BitmapDescriptor icon = BitmapDescriptorFactory.fromResource(R.drawable.salesman_map_icon);
mMap.addMarker(new MarkerOptions()
.position(latLng)
.title(bean.getTitle())
.snippet(String.valueOf(i))
//.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_ORANGE)));
.icon(icon));
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(17));
LatLng object = new LatLng(lat, lon);
listLatLng.add(object);
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
My applications hang for a bit when I populate data from realm database to my listview.
So I planned to do it using Asynchronously so meanwhile data is collected I display a Loading dialogue here is the Code.
Already referred to this question by not able to implement in my case.
private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
#Override
protected RealmResults doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
realm = realm.getDefaultInstance();
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
sscresult = query.findAll(); //error 1
return sscresult;
}
#Override
protected void onPostExecute(RealmResults r) {
progressDialog.dismiss();
list.setAdapter(new MyAdapter(sscresult)); //error 2
realm.close();
}
}
ok so there are two problems if anyone can be solved my application would be error-free
if I try to run list.setAdapter(new MyAdapter(sscresult)); in background process the error is:-
this can run only in UI thread
if try to run in postExecute error is :-
Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.
I am not able to solve this issue please help
You can have your query evaluated on a background thread using asynchronous query API in Realm.
private OrderedRealmCollectionChangeListener<RealmResults<User> callback = new OrderedRealmCollectionChangeListener<>() {
#Override
public void onChange(RealmResults<User> results, OrderedCollectionChangeSet changeSet) {
if (changeSet == null) {
// The first time async returns with an null changeSet.
} else {
// Called on every future update.
}
}
};
private RealmResults<User> result;
public void onStart() {
result = realm.where(User.class).findAllAsync();
result.addChangeListener(callback);
}
But if you give the RealmResults to a RealmRecyclerViewAdapter, then this is all automatic.
P.S. not closing Realm instance in doInBackground() is like, S-class horrible mistake. Please close your Realm instance on non-looping background threads.
Specifically the following:
// private class YourAsyncTask extends AsyncTask<String, String, RealmResults> {
//
// ProgressDialog progressDialog;
// #Override
// protected void onPreExecute() {
// // start loading animation maybe?
// progressDialog = ProgressDialog.show(DictionarySscWords.this,
// "ProgressDialog",
// "Loading all words!");
// }
//
// #Override
// protected RealmResults doInBackground(String... params) {
// RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
// Realm.setDefaultConfiguration(realmConfig);
// realm = realm.getDefaultInstance();
// RealmQuery<Word> query = realm.where(Word.class);
//
// for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
// if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
//
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
// } else {
// query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
// .or();
//
// }
//
// }
// sscresult = query.findAll(); //error 1
// return sscresult;
//
// }
//
// #Override
// protected void onPostExecute(RealmResults r) {
// progressDialog.dismiss();
// list.setAdapter(new MyAdapter(sscresult)); //error 2
// realm.close();
// }
//}
and
public class MyActivity extends AppCompatActivity {
private RealmResults<Word> words;
private Realm realm;
private WordAdapter wordAdapter;
#BindView(R.id.recycler_view)
RecyclerView recyclerView;
#Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.my_activity);
ButterKnife.bind(this);
realm = Realm.getDefaultInstance();
words_for_ssc = ...
RealmQuery<Word> query = realm.where(Word.class);
String[] array = words_for_ssc[Integer.parseInt(params[0])];
for (int i = 0; i < array.length; i++) {
query = query.equalTo("word", array[i]);
if (i != array.length - 1) {
query = query.or();
}
}
words = query.findAllSortedAsync("word");
wordAdapter = new WordAdapter(words);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(wordAdapter);
}
#Override
public void onDestroy() {
super.onDestroy();
realm.close();
realm = null;
}
}
public class WordAdapter extends RealmRecyclerViewAdapter<Word, WordViewHolder> {
public class WordAdapter(OrderedRealmCollection<Word> words) {
super(words, true);
}
#Override
public WordViewHolder onCreateViewHolder(...) {
...
}
#Override
public void onBindViewHolder(WordViewHolder holder, int position) {
holder.bind(getData().get(position));
}
public static class WordViewHolder extends RecyclerView.ViewHolder {
public WordViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
public void bind(Word word) {
...
}
}
}
I think a cleaner solution to your problem without changing much of the code can be written below. In this case, everything that realm does happen on the background thread inside doInBackground. The realm instance is also closed on the thread it was created.
Now what I did basically is that I extracted a deep copy of the list of Words from RealmResult from realm.copyFromRealm(sscresult) which is completely detached from realm and can be moved around and modified inside any thread. All these objects are now free from realm and can be used in onPostExecute without any worries. The only thing you need to modify is the MyAdapter constructor which doesn't take a RealmResult but instead a List of Words which is exactly what you need and can be iterated the same way as RealmResult was.
The only downside of this approach is that the list of Words will not get synced automatically since they're detached and their value won't change automatically if they get altered inside Realm from somewhere else. But I'm pretty sure though that it won't bother you.
I'm also going to attach an official reference for realm.copyFromRealm() which is here.
private class YourAsyncTask extends AsyncTask<String, String, List<Word>> {
ProgressDialog progressDialog;
#Override
protected void onPreExecute() {
// start loading animation maybe?
progressDialog = ProgressDialog.show(DictionarySscWords.this,
"ProgressDialog",
"Loading all words!");
}
#Override
protected List<Word> doInBackground(String... params) {
RealmConfiguration realmConfig = new RealmConfiguration.Builder(context).build();
Realm.setDefaultConfiguration(realmConfig);
try(realm = realm.getDefaultInstance()) {
RealmQuery<Word> query = realm.where(Word.class);
for (int i = 0; i < words_for_ssc[Integer.parseInt(params[0])].length; i++) {
if (i == words_for_ssc[Integer.parseInt(params[0])].length - 1) {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i]);
} else {
query = query.equalTo("word", words_for_ssc[Integer.parseInt(params[0])][i])
.or();
}
}
// Here's the sort. Use findAllSorted instead.
// You can change Sort.ASCENDING to Sort.DESCENDING to reverse
// the order.
sscresult = query.findAllSorted("word", Sort.ASCENDING);
// This is where the magic happens. realm.copyFromRealm() takes
// a RealmResult and essentially returns a deep copy of the
// list that it contains. The elements of this list is however
// completely detached from realm and is not monitored by realm
// for changes. Thus this list of values is free to move around
// inside any thread.
ArrayList<Word> safeWords = realm.copyFromRealm(sscresult);
realm.close();
return safeWords;
}
}
#Override
protected void onPostExecute(List<Word> words) {
progressDialog.dismiss();
// Please note here MyAdaptor constructor will now take the
// list of words directly and not RealmResults so you slightly
// modify the MyAdapter constructor.
list.setAdapter(new MyAdapter(words));
}
}
Hope it helps!
In my android app I'm trying to extend the Thread class to easy pass my values between the original thread and a another one. So I can easily update my UI.
To do this I extended the Thread class:
public class ThreadUpdateUI extends Thread {
AppCombatActivityExtended activity;
Map<?,?> values;
public ThreadUpdateUI(AppCombatActivityExtended activity, Map<?,?> values){
this.activity = activity;
this.values = values;
}
public void UpdateUI(Map<?,?> values){
this.activity.UIThreadFinished(values);
}
public Map<?,?> GetValues()
{
return this.values;
}
}
Not only did I extend Threads, but I also extended the class for Activity so I have a main function I can call in every activity to update my UI:
public class AppCombatActivityExtended extends AppCompatActivity {
protected void UIThreadFinished(Map<?,?> values){}
}
In my activity I use the ThreadUpdateUI class to run a thread in which I can pass all my own values to use in the other thread:
public class MainActivity extends AppCombatActivityExtended {
static final String carlooking_key = "text_carlooking";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//init views
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
//init parameters for thread
HashMap<String, String> UIThreadParameters = new HashMap<>();
UIThreadParameters.put(carlooking_key, text_carlooking.getText().toString().replace(".", ""));
//ThreadUpdateUI
ThreadUpdateUI TU_UI = new ThreadUpdateUI(this, UIThreadParameters) {
#Override
public void run() {
try {
Integer counter = 0;
while (true) {
sleep(1000);
Map values = GetValues();
String text = values.get(carlooking_key).toString();
text += "_test";
Map result = new HashMap<String,String>();
result.put(carlooking_key, text);
UpdateUI(result);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
TU_UI.start();
}
#Override
protected void UIThreadFinished(Map<?, ?> values) {
super.UIThreadFinished(values);
final TextView text_carlooking = (TextView) findViewById(R.id.main_text_carlooking);
text_carlooking.setText(values.get(carlooking_key).toString());
}
}
My code crashes at:
UpdateUI(result);
Saying: "Only the original thread that created a view hierarchy can touch its views."
In my trace I can see the following:
at MainActivity.UIThreadFinished(MainActivity.java:56)
at ThreadUpdateUI.UpdateUI(ThreadUpdateUI.java:21)
at MainActivity$1.run(MainActivity.java:42)
Which could indicate that the reference changed in my ThreadUpdateUI causing to call ThreadUpdateUIFinished in a different thread than the original.
Is it possible to make this code return to the original thread to update my UI in a loop?
I have literally been searching for this for weeks. I am a novice java programmer but I have been able to piece together an app that can use a double latitude and longitude hard coded in the same class. It will show a list of current places surrounding those points. I have another separate class with a method that is able to get the current location based on the gps/network but I can't pass the variables created from this second class to the PlaceRequest class. I have looked through all of the tutorials on the above subjects but there isn't anything combining current location and place search results. I have two getters declared but can't call the variables in these. Again sort of a rookie so may be an easy fix. Any ideas?
Update - Here is my code so far:
GooglePlaceActivity.java
public class GooglePlaceActivity extends Activity {
/** Called when the activity is first created. */
Button btn1;
TextView txt1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.main);
btn1 = (Button)findViewById(R.id.button1);
txt1 = (TextView)findViewById(R.id.textView1);
btn1.setOnClickListener(l);
}
private class SearchSrv extends AsyncTask<Void, Void, PlacesList>{
#Override
protected PlacesList doInBackground(Void... params) {
PlacesList pl = null;
try {
pl = new PlaceRequest().performSearch();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return pl;
}
#Override
protected void onPostExecute(PlacesList result) {
String text = "Result \n";
if (result!=null){
for(Place place: result.results){
text = text + place.name +"\n";
}
txt1.setText(text);
}
setProgressBarIndeterminateVisibility(false);
}
}
View.OnClickListener l = new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
SearchSrv srv = new SearchSrv();
setProgressBarIndeterminateVisibility(true);
srv.execute();
}
};
}
//////////////////////
PlaceRequest.java
public class PlaceRequest {
private static final HttpTransport transport = new ApacheHttpTransport();
private static final String API_KEY = "keyhere";
private static final String LOG_KEY = "GGPlace";
// The different Places API endpoints.
private static final String PLACES_SEARCH_URL = "https://maps.googleapis.com/maps/api/place/search/json?";
private static final String PLACES_AUTOCOMPLETE_URL = "https://maps.googleapis.com/maps/api/place/autocomplete/json?";
private static final String PLACES_DETAILS_URL = "https://maps.googleapis.com/maps/api/place/details/json?";
private static final boolean PRINT_AS_STRING = true;
//double latitude;
//double longitude;
CurrentLocation clo = new CurrentLocation(null);
//clo.onLocationChanged(latitude);
//double longitude = CurrentLocation.getLongitude();
//double latitude = CurrentLocation.getLatitude();
double longi = clo.getLongitude();
double lat = clo.getLatitude();
public PlacesList performSearch() throws Exception {
try {
//CurrentLocation currlo = new CurrentLocation();
//double lat = currlo.getLatitude();
//double longi = currlo.getLongitude();
Log.v(LOG_KEY, "Start Search");
GenericUrl reqUrl = new GenericUrl(PLACES_SEARCH_URL);
reqUrl.put("key", API_KEY);
//reqUrl.put("location", latitude + "," + longitude);
//reqUrl.put("location", getLatitude(latitude) + "," + getLongitude());
reqUrl.put("location", lat + "," + longi);
reqUrl.put("radius", 1600);
reqUrl.put("types", "food");
reqUrl.put("sensor", "false");
Log.v(LOG_KEY, "url= " + reqUrl);
HttpRequestFactory httpRequestFactory = createRequestFactory(transport);
HttpRequest request = httpRequestFactory.buildGetRequest(reqUrl);
Log.v(LOG_KEY, request.execute().parseAsString());
PlacesList places = request.execute().parseAs(PlacesList.class);
Log.v(LOG_KEY, "STATUS = " + places.status);
for (Place place : places.results) {
Log.v(LOG_KEY, place.name);
}
return places;
} catch (HttpResponseException e) {
Log.v(LOG_KEY, e.getResponse().parseAsString());
throw e;
}
catch (IOException e) {
// TODO: handle exception
throw e;
}
}
public static HttpRequestFactory createRequestFactory(final HttpTransport transport) {
return transport.createRequestFactory(new HttpRequestInitializer() {
public void initialize(HttpRequest request) {
GoogleHeaders headers = new GoogleHeaders();
headers.setApplicationName("Google-Places-DemoApp");
request.setHeaders(headers);
JsonHttpParser parser = new JsonHttpParser(new JacksonFactory()) ;
//JsonHttpParser.builder(new JacksonFactory());
//parser.jsonFactory = new JacksonFactory();
request.addParser(parser);
}
});
}
}
/////////////
CurrentLocation.java
public class CurrentLocation {
private static final long MINIMUM_DISTANCE_CHANGE_FOR_UPDATES = 1; // in Meters
private static final long MINIMUM_TIME_BETWEEN_UPDATES = 1000; // in Milliseconds
LocationManager locationManager ;
double latitude=0;
double longitude=0;
public CurrentLocation(Context ctxt) {
super();
locationManager = (LocationManager) ctxt.getSystemService(Context.LOCATION_SERVICE);
// Register the listener with the Location Manager to receive location updates
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
MINIMUM_TIME_BETWEEN_UPDATES,
MINIMUM_DISTANCE_CHANGE_FOR_UPDATES,
new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onLocationChanged(Location location) {
longitude = location.getLongitude();
latitude = location.getLatitude();
}
});
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
}
Edit: After looking your complete code, I see a few fundamental design flaws so I'm going to show you how I did it and you can adapt it to your program flow. Please keep in mind that this example is vastly simplified from my original, but it should be enough to get you going.
First, the CurrentLocation.java file. My design decision for wrapping this in a Future was so that I can re-use it in multiple activities with the added bonus of killing it when necessary.
public class CurrentLocation implements Callable<Location> {
private static final String TAG = "CurrentLocation";
private Context context;
private LocationManager lm;
private Criteria criteria;
private Location bestResult;
private boolean locationListenerWorking;
public CurrentLocation(Context context) {
lm = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
this.context = context;
criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
bestResult = null;
locationListenerWorking = false;
}
public Location call() {
return getLoc();
}
private Location getLoc() {
String provider = lm.getBestProvider(criteria, true);
if (provider != null) {
Log.d(TAG, "Using provider: " +provider);
locationListenerWorking = true;
lm.requestLocationUpdates(provider,
0,
0,
singeUpdateListener,
context.getMainLooper());
} else {
Log.w(TAG, "Couldn't find a location provider");
return null;
}
while (locationListenerWorking) {
// Check for the interrupt signal - terminate if necessary
if (Thread.currentThread().isInterrupted()) {
Log.i(TAG, "User initiated interrupt (cancel signal)");
cleanup();
break;
}
try {
// ghetto implementation of a busy wait...
Thread.sleep(500); // Sleep for half a second
} catch (Exception e) {
Log.d(TAG, "Thread interrupted..");
cleanup();
break;
}
}
return bestResult;
}
private void cleanup() {
if (lm != null) {
Log.d(TAG, "Location manager not null - cleaning up");
lm.removeUpdates(singeUpdateListener);
} else {
Log.d(TAG, "Location manager was NULL - no cleanup necessary");
}
}
/**
* This one-off {#link LocationListener} simply listens for a single location
* update before unregistering itself. The one-off location update is
* returned via the {#link LocationListener} specified in {#link
* setChangedLocationListener}.
*/
private LocationListener singeUpdateListener = new LocationListener() {
public void onLocationChanged(Location location) {
Log.d(TAG, "Got a location update");
if (location == null) {
Log.d(TAG, "Seems as if we got a null location");
} else {
bestResult = location;
}
cleanup();
locationListenerWorking = false;
}
public void onStatusChanged(String provider, int status, Bundle extras) {}
public void onProviderEnabled(String provider) {}
public void onProviderDisabled(String provider) {}
};
}
Then in your calling class (i.e. where you need the lat/lon coordinates - you want to do this from an Activity):
private class GetLocationTask extends AsyncTask <Void, Void, Location> {
private Future<Location> future;
private ExecutorService executor = new ScheduledThreadPoolExecutor(5);
private boolean cancelTriggered = false;
protected void onPreExecute() {
Log.d(TAG, "Starting location get...");
}
public Location doInBackground(Void... arg) {
CurrentLocation currLoc = new CurrentLocation(getApplicationContext());
future = executor.submit(currLoc);
long LOCATION_TIMEOUT = 20000; // ms = 20 sec
try {
// return future.get(Constants.LOCATION_TIMEOUT, TimeUnit.MILLISECONDS);
return future.get(LOCATION_TIMEOUT, TimeUnit.MILLISECONDS);
} catch (Exception e) {
Log.w(TAG, "Location get timed out");
future.cancel(true);
return null;
}
}
public boolean killTask() {
cancelTriggered = true;
boolean futureCancelRes = future.cancel(true);
this.cancel(true);
Log.d(TAG, "Result of cancelling task: " +futureCancelRes);
return futureCancelRes;
}
protected void onPostExecute(Location res) {
if (cancelTriggered) {
Log.d(TAG, "User initiated cancel - this is okay");
cancelTriggered = false;
} else if (res == null) {
Log.d(TAG, "Could not get a location result");
} else {
double lat = res.getLatitude();
double lon = res.getLongitude();
Log.d(TAG, "Latitude: " +lat);
Log.d(TAG, "Longitude: " +lon);
}
}
}
Finally to wrap things up, here's how you call it:
GetLocationTask t = new GetLocationTask();
t.execute();
And if you need to kill the location update for whatever reason (if your user switches out of your activity, etc), this will kill the AsyncTask as well as the associated Future task.
t.killTask();
P.S. You may want to get your API keys changed and edit it out of your post.
I need to perform some tasks with google map,
1. first I need the user to be able to place only one marker
2. Then retrieve the city and other details such as street address
Does anyone know about this?
I wrote a minimal example to show how you could achieve what you're looking for:
public void onModuleLoad() {
RootPanel.get().add(new GoogleMaps());
}
private class GoogleMaps extends Composite {
private MapWidget fMap;
private Geocoder fCoder;
private Marker fMarker;
public GoogleMaps() {
fMap = new MapWidget(LatLng.newInstance(47.0559084, 8.3114878), 6);
fMap.setSize("300px", "300px");
fCoder = new Geocoder();
MarkerOptions options = MarkerOptions.newInstance();
options.setDraggable(true);
fMarker = new Marker(LatLng.newInstance(47.0559084, 8.3114878), options);
fMap.addOverlay(fMarker);
fMarker.setVisible(false);
addHandlers();
initWidget(fMap);
}
private void addHandlers() {
fMap.addMapDoubleClickHandler(new MapDoubleClickHandler() {
#Override
public void onDoubleClick(MapDoubleClickEvent event) {
if (event.getLatLng() != null) {
performReverseLookup(event.getLatLng());
}
}
});
fMarker.addMarkerDragEndHandler(new MarkerDragEndHandler() {
#Override
public void onDragEnd(MarkerDragEndEvent event) {
LatLng point = event.getSender().getLatLng();
if (point != null) {
performReverseLookup(point);
}
}
});
}
private void performReverseLookup(final LatLng point) {
fCoder.getLocations(point, new LocationCallback() {
#Override
public void onSuccess(JsArray<Placemark> locations) {
if (locations.length() > 0) {
LatLng point = locations.get(0).getPoint();
fMarker.setLatLng(point);
fMarker.setVisible(true);
fMap.getInfoWindow().open(point, new InfoWindowContent(locations.get(0).getAddress()));
}
}
#Override
public void onFailure(int statusCode) {}
});
}
}
To your first point: Create only one instance of Marker and update its LatLng upon user interaction (done in performReverseLookup()).
Your second question: After performing the reverse lookup you can get the Placemark object out of the locations array and retrieve details like the address.