This post describes how to use Android location API and how to search a city using openweathermap to get weather conditions. There are two way we can use to find a city:
- Using name pattern
- Using geographic coordinates (Android Location API)
We will introduce, moreover, some concepts about Android location API and Location-based service.
Searching city by name
In this kind of search, an user inserts a part of city name and the app will show all the possible result matching the pattern. From the UI perspective, we want to obtain something like the image shown below:
As first step, we can use EditText so that the user can insert the city name:
android:layout_width=”match_parent”
android:layout_height=”match_parent”>
….
<EditText
android:id=”@+id/cityEdtText”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_alignParentLeft=”true”
android:layout_below=”@+id/textView1″
android:layout_marginTop=”5dp”
android:imeOptions=”actionSearch”
android:inputType=”text” >
<requestFocus />
</EditText>
…
<ListView android:id=”@+id/cityList”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_below=”@id/txt1″
android:layout_marginTop=”3dp”/>
</RelativeLayout>[/xml]
Notice that at line 13, we used imeOptions with “actionSearch” value to specify search action when an user completes inserting the city name pattern.
Now in the Activity that holds this layout we have:
[java]final EditText edt = (EditText) findViewById(R.id.cityEdtText);edt.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
bar.setVisibility(View.VISIBLE);
JSONSearchTask task = new JSONSearchTask();
String pattern = edt.getEditableText().toString();
task.execute(new String[]{pattern});
return true;
}
return false;
}
});[/java]
So when an user clicks on the search icon, we start searching for matching city names and at the end, we will populate a ListView (line 18) . As you can notice, we start an AsyncTask, because the search operation can require quite long time and we don’t want to have ANR problems.
Now it is time to implement the logic that calls the remote openweathermap service and retrieve the cities. We know from API that the URL to call is:
http://api.openweathermap.org/data/2.5/find?mode=json&type=like&q=...&cnt=10
where after q we will add our pattern name and cnt represents the number of items we want to get (in our case we want 10 results at maximum).
Once we have the data, we parse it. We look for list tag that holds the result and for each item in the result we look for name tag that holds the name, the id and the country. The parser is very simple:
[java]public static List<City> getCityList(String data) throws JSONException {JSONObject jObj = new JSONObject(data);
JSONArray jArr = jObj.getJSONArray(“list”);
List<City> cityList = new ArrayList<City>();
for (int i=0; i < jArr.length(); i++) {
JSONObject obj = jArr.getJSONObject(i);
String name = obj.getString(“name”);
String id = obj.getString(“id”);
JSONObject sys = obj.getJSONObject(“sys”);
String country = sys.getString(“country”);
City c = new City(id,name,country);
cityList.add(c);
}
return cityList;
}[/java]
..and finally, we populate the ListView to show the results to the user. This happens in onPostExecute method of the AsyncTask. Notice that you can create a custom Adapter to show this information or you can use a standard Adapter.
Search city using geographic coordinates: Android Location API
Another way to look for the city is using the current user position. We can use Location based service to find the current device position using GPS or WI-FI or cell network. There are two main elements when implementing Location based service:
- Location Manager that is the entry point to the Location based service
- Location Provider representing the location technology used to find the device position
The first step is getting the LocationManager reference. This is a system service, then we can use:
LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
once we have our Location Manager reference we can find the provider. In our case, we don’t want to specify a specific provider (like GPS for example) but let the system find the best matching the search criteria we set:
[java]private static Criteria searchProviderCriteria = new Criteria();// Location Criteria
static {
searchProviderCriteria.setPowerRequirement(Criteria.POWER_LOW);
searchProviderCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
searchProviderCriteria.setCostAllowed(false);
}[/java]
and then we are ready to get the provider:
String provider = locManager.getBestProvider(searchProviderCriteria, true);
and:
[java]Location loc = locManager.getLastKnownLocation(provider);[/java]Now we have to check if the location is null or is too old, in this case we get a new position:
[java]if (loc == null || (SystemClock.elapsedRealtime() – loc.getTime()) &gt; timeOut) {// We request another update Location
Log.d(“SwA”, “Request location”);
locManager.requestSingleUpdate(provider, locListener, null);
}
else {
JSONSearchTask task = new JSONSearchTask();
task.execute(new Location[]{loc});
}[/java]
otherwise, we simply call the service to get the city. Notice at line 4, that we need a listener that implements some callback methods, that will be called when the current position is available:
[java]private LocationListener locListener = 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) {
Log.d(“SwA”, “Location changed!”);
String sLat = “” + location.getLatitude();
String sLon = “” + location.getLongitude();
Log.d(“SwA”, “Lat [“+sLat+”] – sLong [“+sLon+”]”);
LocationManager locManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locManager.removeUpdates(locListener);
JSONSearchTask task = new JSONSearchTask();
task.execute(new Location[]{location});
}
};[/java]
The last step is creating the URL that will be called to retrieve the city from the geographic coordinates. In this case the url to call is:
http://api.openweathermap.org/data/2.5/find?lat=%lat%&lon=%lon%
where the %lat% and &lon% will be substituted by the real value extracted from the current position.
Using emulator to test the app
The last step is testing the app passing the coordinates. We can use DDMS and pass the coordinates:
Please notice that you should separate the decimal part according to your language and number format.
Another way is using
[plain]telnet iphost port[/plain]and when connected send
[plain]geo fix <longitude value> <latitude value>[/plain]At the end of this post, you gained the knowledge about how to use android location api.
Nice tutorial! But it would be great to get the whole source code… is that be possible? 🙂
You can find the source code at github (https://github.com/survivingwithandroid/WeatherLib
this page showme page not found!! 🙁
I use this code but i have an error: ” JSONSearchTask cannot be resolved to a type”, why?
https://github.com/survivingwithandroid/WeatherLib
perfect !! 🙂
I still cant seem to fix the problem, there is to many files to look at when i got to github. How do I fix the issue where it says page not found
Even i’m getting the same error. Could you please let me know how you solved it?
Nice tutorial! But it would be great to get the whole source code… is that be possible? 🙂
You can find the source code at github (https://github.com/survivingwithandroid/WeatherLib)
this page showme page not found!! 🙁
I use this code but i have an error: " JSONSearchTask cannot be resolved to a type", why?
What page? Can u send me the url
perfect !! 🙂
Even i'm getting the same error. Could you please let me know how you solved it?
thanks for this tutorial. but how to add this lib to our project it is full of files and folder!! which on exactly?
thanks for this tutorial. but how to add this lib to our project it is full of files and folder!! which on exactly?
I downloaded it and I got this message:
ERROR: Unsupported method: GradleProject.getProjectDirectory().
The version of Gradle you connect to does not support that method.
To resolve the problem you can change/upgrade the target version of Gradle you connect to.
Alternatively, you can ignore this exception and read other information from the model.
So I will keep searching for more city autofill weather app tutorials until I find one that works, hopefully one with the simplest code, fewest classes, and not so many Gradle errors and needs to download more stuff.
Probably you have to upgrade the project. It could be a little bit old.