Android Google Maps: Show your current location
Xin chào!
Đây là bài số 2 trong chuỗi bài về Google Maps. Chúng ta sẽ cần nội dung và project trong bài cũ, nên trường hợp bạn chưa đọc bài trước thì xin mời ghé qua link sau nhé:
https://labs.flinters.vn/android-2/android-google-maps/
Trong bài số 1 đó tôi đã hướng dẫn bạn thiết lập và hiển thị Google Maps trong ứng dụng Android của mình rồi. Khi chạy ứng dụng lên bạn sẽ thấy bản đồ hiển thị tại châu Úc và có 1 điểm pin ở Sydney. Ồ, tôi đang ở Việt Nam (ở Hà Nội chẳng hạn), tôi cần biết thông tin ở khu vực quanh vị trí hiện tại của tôi, nhưng bản đồ bây giờ lại hiển thị ở tận nơi phương xa như vậy thì không ổn. Tôi và bạn sẽ cùng nhau thiết lập để Google Maps hiển thị ví trí hiện tại nhé. Hãy mở project lên nào.
Add file LocationUtils.java dưới đây vào project.
package com.app.mymap;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.LocationListener;
import android.location.LocationManager;
import androidx.core.app.ActivityCompat;
public class LocationUtils {
private final long MIN_TIME = 30000; // milliseconds
private final float MIN_DISTANCE = 20; // meters
private static LocationUtils instance = new LocationUtils();
public static LocationUtils getInstance() {
return instance;
}
private LocationListener locationListener;
public boolean isEnableLocationService(Context context) {
if (context == null) return false;
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null) return false;
boolean gpsEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean networkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
return gpsEnable || networkEnable;
}
public void requestUpdateLocation(Context context, LocationListener locationListener) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null) return;
if (this.locationListener != null) locationManager.removeUpdates(this.locationListener);
int permissionLocationNetwork = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION);
boolean networkEnable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (networkEnable && permissionLocationNetwork == PackageManager.PERMISSION_GRANTED) {
this.locationListener = locationListener;
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME, MIN_DISTANCE, this.locationListener);
return;
}
int permissionLocationGPS = ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION);
boolean gpsEnable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (gpsEnable && permissionLocationGPS == PackageManager.PERMISSION_GRANTED) {
this.locationListener = locationListener;
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, MIN_TIME, MIN_DISTANCE, this.locationListener);
}
}
public void removeUpdateLocation(Context context) {
if (context == null) return;
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (locationManager == null) return;
if (this.locationListener != null) locationManager.removeUpdates(this.locationListener);
this.locationListener = null;
}
}
LocationUtils.java sẽ giúp bạn kiểm tra thiết bị đã bật dịch vụ định vị hay chưa, yêu cầu cập nhật vị trí hiện tại của thiết bị và huỷ bỏ yêu cầu đó khi không cần thiết.
Tiếp theo, vì ứng dụng sẽ sử dụng dịch vụ Location trên thiết bị nên bạn cần request quyền truy cập Location từ người dùng. Hãy khai báo permission trong AndroidManifest.xml. Thông thường khi tạo project như trong bài trước thì việc khai báo này đã được tự động thêm vào rồi, tuy nhiên để chắc chắn bạn nên kiểm tra lại một lần nữa.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Với những thiết bị chạy Android 6 trở lên thì việc khai báo permission như trên là chưa đủ, chúng ta cần request permission khi chạy ứng dụng. Bây giờ chúng ta sẽ xử lý việc này và các phần còn lại để hiển thị vị trí hiện tại trên bản đồ trong file MapsActivity.java. Các bước implement như sau:
– Khi khởi chạy ứng dụng, trong hàm onCreate tôi kiểm tra xem nếu người dùng chưa cấp location permission sẽ thực hiện request. Sau đó tôi sẽ xử lý kết quả của việc request này trong hàm onRequestPermissionsResult. Nếu kết quả vẫn chưa được cấp permission, ứng dụng sẽ không thể lấy được vị trí hiện tại, và sẽ thông báo cho người dùng biết điều này.
– Khi ứng dụng đã được cấp location permission, sử dụng LocationUtils ở trên, tôi kiểm tra nếu thiết bị chưa bật dịch vụ location sẽ thực hiện request người dùng bật nó lên. Việc xử lý kết quả trả về trong hàm onActivityResult. Nếu kết quả dịch vụ vẫn chưa được kích hoạt tôi cũng sẽ thông báo cho người dùng.
– Khi ứng dụng đã được cấp location permission, đồng thời thiết bị đã bật dịch vụ định vị. Tôi tiến hành xác định vị trí hiện tại thông qua LocationUtils và hiển thị trên Google Maps.
File MapsActivity.java được update như dưới đây.
package com.app.mymap;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.os.Bundle;
import android.provider.Settings;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import java.util.ArrayList;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, LocationListener {
private static final int REQUEST_CODE_LOCATION_PERMISSION = 1;
private static final int REQUEST_CODE_ENABLE_LOCATION_SERVICE = 2;
private GoogleMap mMap;
/**
* Check location service is enabled or disabled.
*
* @return true if location service is enabled.
*/
private boolean checkLocationService() {
boolean isEnable;
if (!LocationUtils.getInstance().isEnableLocationService(this)) { // Location service not enable, request it.
isEnable = false;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Request location service");
builder.setMessage("Turn on location service for updating your location");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
startActivityForResult(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), REQUEST_CODE_ENABLE_LOCATION_SERVICE);
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
isEnable = true;
}
return isEnable;
}
/**
* Request location permission.
*
* @param permissionsArrayList list of permissions to request.
*/
private void requestLocationPermission(ArrayList<String> permissionsArrayList) {
String[] stringPermissionArray = new String[permissionsArrayList.size()];
ActivityCompat.requestPermissions(this, permissionsArrayList.toArray(stringPermissionArray), REQUEST_CODE_LOCATION_PERMISSION);
}
/**
* Check location permission then get current location.
*/
private void tryGetCurrentLocation() {
// ask for the permission in android M
ArrayList<String> permissionsArrayList = new ArrayList<>();
int permissionLocationGPS = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
int permissionLocationNetwork = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
if (permissionLocationGPS != PackageManager.PERMISSION_GRANTED && permissionLocationNetwork != PackageManager.PERMISSION_GRANTED) {
permissionsArrayList.add(Manifest.permission.ACCESS_FINE_LOCATION);
permissionsArrayList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
requestLocationPermission(permissionsArrayList);
} else { // Already has at least ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION
// Check location service.
if (checkLocationService()) getCurrentLocation();
}
}
/**
* Get current location.
*/
private void getCurrentLocation() {
if (!LocationUtils.getInstance().isEnableLocationService(this)) return;
LocationUtils.getInstance().requestUpdateLocation(this, this);
}
/**
* Set current location on map and move map to it.
*
* @param lat the latitude.
* @param lng the longitude.
*/
private void setCurrentLocationOnMap(double lat, double lng) {
LatLng defaultLocation = new LatLng(lat, lng);
mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(defaultLocation, 18));
mMap.setMyLocationEnabled(true);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
tryGetCurrentLocation();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ENABLE_LOCATION_SERVICE) {
if (LocationUtils.getInstance().isEnableLocationService(this)) {
getCurrentLocation();
} else {
Toast.makeText(this, "Cannot get current location!", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (REQUEST_CODE_LOCATION_PERMISSION == requestCode) {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay!
// Check location service.
if (checkLocationService()) getCurrentLocation();
} else {
// permission denied, boo!
Toast.makeText(this, "Cannot get current location!", Toast.LENGTH_SHORT).show();
}
}
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
}
@Override
public void onLocationChanged(Location location) {
if (location == null || mMap == null) return;
setCurrentLocationOnMap(location.getLatitude(), location.getLongitude());
LocationUtils.getInstance().removeUpdateLocation(this);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
Cuối cùng bạn chỉ cần chạy ứng dụng lên và xem kết quả nhé.
Tôi cũng xin dừng bài viết lần này ở đây. Bài tiếp theo, cũng trong chuỗi bài về Google Maps, tôi sẽ hướng dẫn bạn tìm 1 địa điểm bạn muốn đến và chỉ đường đến đó ngay trong ứng dụng của bạn.
Cùng chờ đón nhé!