Create Project
Create new project in Android Studio with steps as below:
Step 1: Input Project Name and Select Project Location
Step 2: Select SDK for Android App
Step 3: Select Default Activity for App
Step 4: Finish create project
Google Map API
Login to https://console.developers.google.com and create Places API key for testing. Create new xml file named google_maps_api.xml in res/values folder contains Places API key:
AIzaSyB9MxxJBmzLHdfsMEZSdV0vORR_MRwirPI
Add Library as Dependencies
Open build.gradle file in Gradle Scripts and add new library as below:
implementation 'com.google.android.gms:play-services-maps:15.0.1'
implementation 'com.google.android.gms:play-services-location:15.0.1'
implementation 'com.google.api-client:google-api-client:1.23.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.4.1'
implementation 'com.squareup.okhttp3:okhttp:3.4.1'
implementation 'com.android.support:cardview-v7:26.1.0'
Add Strings
Open res\values\strings.xml file and add new string as below:
<resources>
<string name="app_name">Learn Android with Real Apps</string>
<string name="keyword">Keyword...</string>
<string name="search">Search</string>
</resources>
Manifest Permissions
Open AndroidManifest.xml file in manifest folder, add permissions and google map api as below:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.demo.learnandroidwithrealapps">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
</application>
</manifest>
Create Entities
Create new package named entities. In this package, create new entities as below:
Location
Create new java class named Location.java as below:
package android.demo.entities;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
public class Location implements Serializable {
@SerializedName("lat")
private Double lat;
@SerializedName("lng")
private Double lng;
public Double getLat() {
return lat;
}
public void setLat(Double lat) {
this.lat = lat;
}
public Double getLng() {
return lng;
}
public void setLng(Double lng) {
this.lng = lng;
}
}
OpeningHours
Create new java class named OpeningHours.java as below:
package android.demo.entities;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class OpeningHours implements Serializable {
@SerializedName("open_now")
private Boolean openNow;
@SerializedName("weekday_text")
private List<Object> weekdayText = new ArrayList<Object>();
/**
* @return The openNow
*/
public Boolean getOpenNow() {
return openNow;
}
/**
* @param openNow The open_now
*/
public void setOpenNow(Boolean openNow) {
this.openNow = openNow;
}
/**
* @return The weekdayText
*/
public List<Object> getWeekdayText() {
return weekdayText;
}
/**
* @param weekdayText The weekday_text
*/
public void setWeekdayText(List<Object> weekdayText) {
this.weekdayText = weekdayText;
}
}
Photo
Create new java class named Photo.java as below:
package android.demo.entities;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Photo implements Serializable {
@SerializedName("height")
private Integer height;
@SerializedName("html_attributions")
private List<String> htmlAttributions = new ArrayList<String>();
@SerializedName("photo_reference")
private String photoReference;
@SerializedName("width")
private Integer width;
/**
* @return The height
*/
public Integer getHeight() {
return height;
}
/**
* @param height The height
*/
public void setHeight(Integer height) {
this.height = height;
}
/**
* @return The htmlAttributions
*/
public List<String> getHtmlAttributions() {
return htmlAttributions;
}
/**
* @param htmlAttributions The html_attributions
*/
public void setHtmlAttributions(List<String> htmlAttributions) {
this.htmlAttributions = htmlAttributions;
}
/**
* @return The photoReference
*/
public String getPhotoReference() {
return photoReference;
}
/**
* @param photoReference The photo_reference
*/
public void setPhotoReference(String photoReference) {
this.photoReference = photoReference;
}
/**
* @return The width
*/
public Integer getWidth() {
return width;
}
/**
* @param width The width
*/
public void setWidth(Integer width) {
this.width = width;
}
}
Geometry
Create new java class named Geometry.java as below:
package android.demo.entities;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
public class Geometry implements Serializable {
@SerializedName("location")
private Location location;
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
Result
Create new java class named Result.java as below:
package android.demo.entities;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class Result implements Serializable {
@SerializedName("geometry")
private Geometry geometry;
@SerializedName("icon")
private String icon;
@SerializedName("id")
private String id;
@SerializedName("name")
private String name;
@SerializedName("opening_hours")
private OpeningHours openingHours;
@SerializedName("photos")
private List<Photo> photos = new ArrayList<Photo>();
@SerializedName("place_id")
private String placeId;
@SerializedName("rating")
private Double rating;
@SerializedName("reference")
private String reference;
@SerializedName("scope")
private String scope;
@SerializedName("types")
private List<String> types = new ArrayList<String>();
@SerializedName("vicinity")
private String vicinity;
@SerializedName("price_level")
private Integer priceLevel;
/**
* @return The geometry
*/
public Geometry getGeometry() {
return geometry;
}
/**
* @param geometry The geometry
*/
public void setGeometry(Geometry geometry) {
this.geometry = geometry;
}
/**
* @return The icon
*/
public String getIcon() {
return icon;
}
/**
* @param icon The icon
*/
public void setIcon(String icon) {
this.icon = icon;
}
/**
* @return The id
*/
public String getId() {
return id;
}
/**
* @param id The id
*/
public void setId(String id) {
this.id = id;
}
/**
* @return The name
*/
public String getName() {
return name;
}
/**
* @param name The name
*/
public void setName(String name) {
this.name = name;
}
/**
* @return The openingHours
*/
public OpeningHours getOpeningHours() {
return openingHours;
}
/**
* @param openingHours The opening_hours
*/
public void setOpeningHours(OpeningHours openingHours) {
this.openingHours = openingHours;
}
/**
* @return The photos
*/
public List<Photo> getPhotos() {
return photos;
}
/**
* @param photos The photos
*/
public void setPhotos(List<Photo> photos) {
this.photos = photos;
}
/**
* @return The placeId
*/
public String getPlaceId() {
return placeId;
}
/**
* @param placeId The place_id
*/
public void setPlaceId(String placeId) {
this.placeId = placeId;
}
/**
* @return The rating
*/
public Double getRating() {
return rating;
}
/**
* @param rating The rating
*/
public void setRating(Double rating) {
this.rating = rating;
}
/**
* @return The reference
*/
public String getReference() {
return reference;
}
/**
* @param reference The reference
*/
public void setReference(String reference) {
this.reference = reference;
}
/**
* @return The scope
*/
public String getScope() {
return scope;
}
/**
* @param scope The scope
*/
public void setScope(String scope) {
this.scope = scope;
}
/**
* @return The types
*/
public List<String> getTypes() {
return types;
}
/**
* @param types The types
*/
public void setTypes(List<String> types) {
this.types = types;
}
/**
* @return The vicinity
*/
public String getVicinity() {
return vicinity;
}
/**
* @param vicinity The vicinity
*/
public void setVicinity(String vicinity) {
this.vicinity = vicinity;
}
/**
* @return The priceLevel
*/
public Integer getPriceLevel() {
return priceLevel;
}
/**
* @param priceLevel The price_level
*/
public void setPriceLevel(Integer priceLevel) {
this.priceLevel = priceLevel;
}
}
PlacesResults
Create new java class named PlacesResults.java as below:
package android.demo.entities;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class PlacesResults implements Serializable {
@SerializedName("html_attributions")
private List<Object> htmlAttributions = new ArrayList<Object>();
@SerializedName("next_page_token")
private String nextPageToken;
@SerializedName("results")
private List<Result> results = new ArrayList<Result>();
@SerializedName("status")
private String status;
public List<Object> getHtmlAttributions() {
return htmlAttributions;
}
public void setHtmlAttributions(List<Object> htmlAttributions) {
this.htmlAttributions = htmlAttributions;
}
public String getNextPageToken() {
return nextPageToken;
}
public void setNextPageToken(String nextPageToken) {
this.nextPageToken = nextPageToken;
}
public List<Result> getResults() {
return results;
}
public void setResults(List<Result> results) {
this.results = results;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
Main Activity Layout
Open res\layout\activity_main.xml file and create layout as below:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/buttonShowLocation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/show_my_location" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="@string/latitude"
android:textStyle="bold" />
<TextView
android:id="@+id/textViewLatitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp" />
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="@string/longitude"
android:textStyle="bold" />
<TextView
android:id="@+id/textViewLongitude"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp" />
</LinearLayout>
Create Custom CardView Layout
Select res\layout folder. In this folder, create new layout named place_row_layout.xml as below:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="0dp"
card_view:cardElevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageViewPhoto"
android:layout_width="100dp"
android:layout_height="match_parent"
android:layout_marginBottom="10dp"
android:layout_marginRight="2dp"
android:layout_weight="1"
android:scaleType="fitStart"
app:srcCompat="@drawable/common_google_signin_btn_icon_dark" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/textViewName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textViewAddress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
Create Custom Adapter
Create new package named adapters. In this package, create new java class named PlacesListAdapter.java as below:
package android.demo.adapters;
import android.content.Context;
import android.demo.entities.Result;
import android.demo.learnandroidwithrealapps.R;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.InputStream;
import java.util.List;
public class PlacesListAdapter extends ArrayAdapter<Result> {
private Context context;
private List<Result> results;
public PlacesListAdapter(Context context, List<Result> results) {
super(context, R.layout.place_row_layout, results);
this.context = context;
this.results = results;
}
@NonNull
@Override
public View getView(int position, @Nullable View view, @NonNull ViewGroup parent) {
try {
ViewHolder viewHolder;
if(view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(context).inflate(R.layout.place_row_layout,null);
viewHolder.textViewName = view.findViewById(R.id.textViewName);
viewHolder.textViewAddress = view.findViewById(R.id.textViewAddress);
viewHolder.imageViewPhoto = view.findViewById(R.id.imageViewPhoto);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
Result result = results.get(position);
viewHolder.textViewName.setText(result.getName());
viewHolder.textViewAddress.setText(result.getVicinity());
Bitmap photo = new ImageRequestAsk().execute(result.getIcon()).get();
viewHolder.imageViewPhoto.setImageBitmap(photo);
return view;
} catch (Exception e) {
return null;
}
}
public static class ViewHolder {
public TextView textViewName;
public TextView textViewAddress;
public ImageView imageViewPhoto;
}
private class ImageRequestAsk extends AsyncTask<String, Void, Bitmap> {
@Override
protected Bitmap doInBackground(String... params) {
try {
InputStream inputStream = new java.net.URL(params[0]).openStream();
return BitmapFactory.decodeStream(inputStream);
} catch (Exception e) {
return null;
}
}
}
}
Retrofit API
Create new package named api. In this package, create new api as below:
APIClient
Create new java class named APIClient.java as below:
package android.demo.api;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class APIClient {
private static Retrofit retrofit = null;
public static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("https://maps.googleapis.com/maps/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
GoogleMapAPI
Create new interface named GoogleMapAPI.java as below:
package android.demo.api;
import android.demo.entities.PlacesResults;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface GoogleMapAPI {
@GET("place/nearbysearch/json")
Call<PlacesResults> getNearBy(
@Query("location") String location,
@Query("radius") int radius,
@Query("type") String type,
@Query("keyword") String keyword,
@Query("key") String key
);
}
Main Activity Class
Add code to MainActivity.java file in android.demo.learnandroidwithrealapps package as below:
package android.demo.learnandroidwithrealapps;
import android.Manifest;
import android.content.pm.PackageManager;
import android.demo.adapters.PlacesListAdapter;
import android.demo.api.APIClient;
import android.demo.api.GoogleMapAPI;
import android.demo.entities.PlacesResults;
import android.demo.entities.Result;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private EditText editTextKeyword;
private Button buttonSearch;
private ListView listViewPlaces;
private Spinner spinnerType;
private LocationManager locationManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
loadData();
}
private void initView() {
editTextKeyword = findViewById(R.id.editTextKeyword);
buttonSearch = findViewById(R.id.buttonSearch);
buttonSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
buttonSearch_onClick(view);
}
});
listViewPlaces = findViewById(R.id.listViewPlaces);
spinnerType = findViewById(R.id.spinnerType);
}
private void buttonSearch_onClick(View view) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2 * 1000, 1, locationListener);
} else {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 12);
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 13);
}
}
}
private LocationListener locationListener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
String keyword = editTextKeyword.getText().toString();
String key = getText(R.string.google_maps_key).toString();
String currentLocation = location.getLatitude() + "," + location.getLongitude();
int radius = 1500;
String type = spinnerType.getSelectedItem().toString();
GoogleMapAPI googleMapAPI = APIClient.getClient().create(GoogleMapAPI.class);
googleMapAPI.getNearBy(currentLocation, radius, type, keyword, key).enqueue(new Callback<PlacesResults>() {
@Override
public void onResponse(Call<PlacesResults> call, Response<PlacesResults> response) {
if (response.isSuccessful()) {
List<Result> results = response.body().getResults();
PlacesListAdapter placesListAdapter = new PlacesListAdapter(getApplicationContext(), results);
listViewPlaces.setAdapter(placesListAdapter);
} else {
Toast.makeText(getApplicationContext(), "Failed", Toast.LENGTH_LONG).show();
}
}
@Override
public void onFailure(Call<PlacesResults> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
@Override
public void onStatusChanged(String s, int i, Bundle bundle) {
}
@Override
public void onProviderEnabled(String s) {
}
@Override
public void onProviderDisabled(String s) {
}
};
private void loadData() {
List<String> types = new ArrayList<>();
types.add("ATM");
types.add("Cafe");
types.add("Hotel");
types.add("Restaurant");
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.support_simple_spinner_dropdown_item, types);
spinnerType.setAdapter(arrayAdapter);
}
}
Structure of Project
Run App
Load Main Activity
Select Place Type and Input Keyword
Result