Bài 55: Google Maps Android API – phần 3


Bài 53, 54 bạn đã biết cách đưa Google Map ra ứng dụng Android. Trong bài này Tui sẽ hướng dẫn các bạn cách tương tác nâng cao với Google Map.

Ta tiếp tục với Project LearnGoogleMap ở bài 54.

Để truy xuất đối tượng Google Map trong XML layout ta làm như sau:


GoogleMap map = ((MapFragment)getFragmentManager().findFragmentById(R.id.map)).getMap();

Thông thường khi tải Google Map thường tốn thời gian chờ, vì vậy ta nên dùng Progress control để cho người sử dụng biết là chương trình đang chạy.

GoogleMap cung cấp sự kiện OnMapLoadedCallback để cho phép ta kiểm tra xem Map đã được tải về ứng dụng hoàn thành hay chưa, ta có thể dựa vào sự kiện này để kiểm tra.

Ta sửa code MainActivity như sau:


package tranduythanh.com.learngooglemap;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;

public class MainActivity extends Activity {

//Khai báo đối tượng Google Map
GoogleMap map;
//Khai báo Progress Bar dialog để làm màn hình chờ
ProgressDialog myProgress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Tạo Progress Bar
myProgress = new ProgressDialog(this);
myProgress.setTitle("Đang tải Map ...");
myProgress.setMessage("Vui lòng chờ...");
myProgress.setCancelable(true);
//Hiển thị Progress Bar
myProgress.show();
//Lấy đối tượng Google Map ra:
map = ((MapFragment)getFragmentManager().
findFragmentById(R.id.map)).getMap();
//thiết lập sự kiện đã tải Map thành công
map.setOnMapLoadedCallback(new OnMapLoadedCallback() {

@Override
public void onMapLoaded() {
//Đã tải thành công thì tắt Dialog Progress đi
myProgress.dismiss();
}
});
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
map.getUiSettings().setZoomControlsEnabled(true);
map.setMyLocationEnabled(true);
}
}

Khởi động ứng dụng ta được như sau:

android_55_1– Ta cần biết thêm số chức năng của Google Map như sau:

+ Làm sao biết biết được vị trí hiện tại của ta để di chuyển Map đúng vị trí

+ Cách xoay , quay Map như thế nào

+ Đường đi giữa các địa điểm ra sao….

* Để biết được vị trí hiện tại của ta trên bản đồ ta cần bổ sung thêm Manifest các thông số sau:


<uses-feature android:name="android.hardware.location" android:required="true" />
<uses-feature android:name="android.hardware.location.gps" android:required="true" />

Trong MainActivity bạn bổ sung thêm hàm “TuiDangODau” :


private void TuiDangODau() {

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();

Location lastLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));
if (lastLocation != null)
{
map.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()), 13));

CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude()))      // Sets the center of the map to location user
.zoom(15)                   // Sets the zoom
.bearing(90)                // Sets the orientation of the camera to east
.tilt(40)                   // Sets the tilt of the camera to 30 degrees
.build();                   // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
}

Sau đó trong hàm OnCreate, ta gọi bổ sung thêm hàm TuiDangODau:


protected void onCreate(Bundle savedInstanceState) {
//.....

//Thêm dòng lệnh này:
TuiDangODau();
}

Khi chạy ứng dụng lên, phần mềm sẽ tự động đưa ta về đúng vị trí trên bản đồ …:

android_55_2Bạn muốn thêm ghi chú cho địa điểm của bạn thì bổ sung tiếp MarkerOptions, bạn sửa lại hàm TuiDangODau như sau:


private void TuiDangODau() {

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();

Location lastLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));
if (lastLocation != null)
{
LatLng latLng=new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13));

CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng)      // Sets the center of the map to location user
.zoom(15)                   // Sets the zoom
.bearing(90)                // Sets the orientation of the camera to east
.tilt(40)                   // Sets the tilt of the camera to 30 degrees
.build();                   // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
//Thêm MarketOption cho Map:
MarkerOptions option=new MarkerOptions();
option.title("Chỗ Tui đang ngồi đó");
option.snippet("Gần làng SOS");
option.position(latLng);
Marker currentMarker= map.addMarker(option);
currentMarker.showInfoWindow();
}
}

Tiến hành chạy lại ứng dụng ta có kết quả như hình dưới đây:

android_55_3-Tuy nhiên trong nhiều trường hợp ta cần hiệu chỉnh lại MarkerOption theo ý của Ta cho nó đẹp và phục vụ những mục đích khác… Do đó ta cần phải biết hiệu chỉnh InfoWindowAdapter:

Giả sử ta sửa lại Marker Option như sau:

android_55_4Bạn quan sát khi Tui nhấn ngón tay vào núm màu xám xanh thì nó hiển thị lên MarkerOption theo định dạng của riêng Tui, cái này rất hay và tiện dung trong việc quảng bá thương hiệu của một địa điểm nào đó, với những thông tin thật chi tiết và hữu ích.

Bạn để ý Marker Tui hiển thị các thông tin sau:

– Hình Tui tải từ link trên Facebook

– Kinh độ (longtitude)

– Vĩ độ (latitude)

– Title

– Snippet

Bạn thấy háo hức không? Tui thấy rất là háo hức khi các bạn làm được như trên. Nó quá hay và tiện dụng.

Vậy làm sao để có thể coding cho nó hiểu như trên?

Tiếp tục với bài LearnGoogleMap ở trên, bạn tạo thêm lớp ImageLoadTask để tải hình từ Facebook, MyInfoWindowAdapter custom_info.xml để hiển thị thông tin Marker theo ý mình:

android_55_5– Layout để hiển thị Marker Option theo ý mình như sau (custom_info.xml):


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<ImageView
android:id="@+id/img_drthanh"
android:layout_width="400dp"
android:layout_height="200dp"
android:src="@drawable/common_full_open_on_phone" />

<TextView
android:id="@+id/tv_lat"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/tv_lng"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="title:" />

<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="snippet:" />

<TextView
android:id="@+id/tv_snippet"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

</LinearLayout>

Lớp ImageLoadTask để tải hình ảnh từ Facebook về sau đó hiển thị lên Custom Marker Option như sau:


package tranduythanh.com.learngooglemap;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.Marker;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;

public class ImageLoadTask extends AsyncTask<Void, Void, Bitmap> {

//Link url hình ảnh bất kỳ
private String url;
private GoogleMap map;
private Activity context;
private boolean isCompleted=false;
private Marker currentMarker;

public boolean isCompleted() {
return isCompleted;
}

public void setCompleted(boolean isCompleted) {
this.isCompleted = isCompleted;
}

public ImageLoadTask(Activity context, String url,GoogleMap map,Marker currentMarker) {
this.context=context;
this.url = url;
this.map=map;
this.currentMarker=currentMarker;
}

@Override
protected Bitmap doInBackground(Void... params) {
try {
//Tiến hành tạo đối tượng URL
URL urlConnection = new URL(url);
//Mở kết nối
HttpURLConnection connection = (HttpURLConnection) urlConnection
.openConnection();
connection.setDoInput(true);
connection.connect();
//Đọc dữ liệu
InputStream input = connection.getInputStream();
//Tiến hành convert qua hình ảnh
Bitmap myBitmap = BitmapFactory.decodeStream(input);
if(myBitmap==null)
return null;
return myBitmap;
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Bitmap result) {
super.onPostExecute(result);
//thiết lập Info cho Map khi tải hình hoàn tất
map.setInfoWindowAdapter(new MyInfoWindowAdapter(context,result));
//tiến hành hiển thị lên Custom marker option lên Map:
currentMarker.showInfoWindow();
}
}

– Chú ý dòng lệnh 67, 69 là để gán Custom cho Map và hiển thị nó lên.

Coding MyInfoWindowAdapter để custom layout cho Marker option:


package tranduythanh.com.learngooglemap;

import android.app.Activity;
import android.graphics.Bitmap;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.gms.maps.GoogleMap.InfoWindowAdapter;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;


public class MyInfoWindowAdapter implements InfoWindowAdapter {

private Activity context;
private Bitmap btmp;
public MyInfoWindowAdapter(Activity context,Bitmap result)
{
this.context=context;
this.btmp=result;
}
@Override
public View getInfoContents(Marker arg0) {
// Getting view from the layout file info_window_layout
View v = this.context.getLayoutInflater().inflate(R.layout.custom_info, null);

// Getting the position from the marker
LatLng latLng = arg0.getPosition();

// Getting reference to the TextView to set latitude
TextView tvLat = (TextView) v.findViewById(R.id.tv_lat);

// Getting reference to the TextView to set longitude
TextView tvLng = (TextView) v.findViewById(R.id.tv_lng);

TextView tvTitle = (TextView) v.findViewById(R.id.tv_title);

TextView tvSnippet = (TextView) v.findViewById(R.id.tv_snippet);

ImageView imgdrthanh=(ImageView) v.findViewById(R.id.img_drthanh);

// Setting the latitude
tvLat.setText("Latitude:" + latLng.latitude);

// Setting the longitude
tvLng.setText("Longitude:"+ latLng.longitude);

tvTitle.setText(arg0.getTitle());
tvSnippet.setText(arg0.getSnippet());
imgdrthanh.setImageBitmap(btmp);
return v;
}

@Override
public View getInfoWindow(Marker arg0) {

return null;
}

}

– Cuối cùng chỉnh sửa lại MainActivity như sau:


package tranduythanh.com.learngooglemap;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.GoogleMap.OnMapLoadedCallback;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

import android.app.Activity;
import android.app.ProgressDialog;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;

public class MainActivity extends Activity {

//Khai báo đối tượng Google Map
GoogleMap map;
//Khai báo Progress Bar dialog để làm màn hình chờ
ProgressDialog myProgress;
GoogleApiClient googleApiClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Tạo Progress Bar
myProgress = new ProgressDialog(this);
myProgress.setTitle("Đang tải Map ...");
myProgress.setMessage("Vui lòng chờ...");
myProgress.setCancelable(true);
//Hiển thị Progress Bar
myProgress.show();
//Lấy đối tượng Google Map ra:
map = ((MapFragment)getFragmentManager().
findFragmentById(R.id.map)).getMap();
//thiết lập sự kiện đã tải Map thành công
map.setOnMapLoadedCallback(new OnMapLoadedCallback() {

@Override
public void onMapLoaded() {
//Đã tải thành công thì tắt Dialog Progress đi
myProgress.dismiss();
}
});
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
map.getUiSettings().setZoomControlsEnabled(true);
map.setMyLocationEnabled(true);
//lấy lấy được vị trí cuối cùng:

TuiDangODau();
}
private void TuiDangODau() {

LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
Criteria criteria = new Criteria();

Location lastLocation = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, false));
if (lastLocation != null)
{
LatLng latLng=new LatLng(lastLocation.getLatitude(), lastLocation.getLongitude());
map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 13));

CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng)      // Sets the center of the map to location user
.zoom(15)                   // Sets the zoom
.bearing(90)                // Sets the orientation of the camera to east
.tilt(40)                   // Sets the tilt of the camera to 30 degrees
.build();                   // Creates a CameraPosition from the builder
map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
//Thêm MarketOption cho Map:
MarkerOptions option=new MarkerOptions();
option.title("Chỗ Tui đang ngồi đó");
option.snippet("Gần làng SOS");
option.position(latLng);
option.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_VIOLET));
Marker currentMarker= map.addMarker(option);

ImageLoadTask imgTask=new ImageLoadTask(this,"https://scontent-a-lax.xx.fbcdn.net/hphotos-xpa1/v/t1.0-9/1488744_806006112761224_104751868_n.jpg?oh=18c334e98bdbc3454a0b72be9dc3f7dc&oe=55417543",map,currentMarker);
imgTask.execute();
}
}
}

Bạn để ý dòng lệnh 84, là dòng Tui gọi tải hình từ Facebook về, bạn có thể đổi link bất kỳ. Ở đây Tui truyền tham chiếu Map và MarkerOption qua Custom Adapter để hiển thị theo ý mình.

Bạn có thể tải source code phần Custom Marker Option ở đây:

http://www.mediafire.com/download/cha8toku8386wet/LearnGoogleMap_custom_marker_option.rar

Như vậy bạn đã biết được thao tác nâng cao với Google Map control, bài tiếp theo Tui sẽ hướng dẫn các bạn cách sử dụng các Autoshape trên Map (line, polyline, Rectangle, circle…)

Bạn cần phải làm lại bài này nhiều lần để hiểu được cơ chế làm việc của nó, đặc biệt là cách Custom Layout cho marker Option.

Chúc các bạn thành công

18 responses

  1. […] tục bài 55, bài 54, bài 53 bạn đã cơ bản lập trình được với Google Map. Trong bài này Tui […]

  2. lastLocation của hàm TuiDangODau() trả về null ? Đã bật quyền truy cập thông tin vị trí trên điện thoại.

  3. Hihi…e cám ơn thầy nhiều lắm bài này rất là hửu ích với e…

  4. Không có phần hướng dẫn tìm đường đi giữa 2 địa chỉ ạ?

  5. cảm ơn thầy rất nhiều. Đúng thứ tôi đang cần ! Rất cảm ơn .

  6. em làm giống như hướng dẫn của thầy mà sao vẫn không lấy đc vị trí hiện tại nhỉ

  7. thầy ơi em làm thấy kết quả của vị trí là null. thầy xem nguyên nhân có thể là ở đâu thầy ?

  8. Em cũng đang bị lỗi như 2 bạn trên , trả về null, có ai test thành công trên AVD chưa nhỉ 😦

  9. không lấy được vị trí hiện tại thầy ơi, có ai giúp với

  10. Nguyễn Đức Anh | Reply

    Các bạn sử dụng thêm đoạn code này nhé là ok :
    if(myLocation != null){
    latitude = myLocation.getLatitude();
    longitude = myLocation.getLongitude();
    }else{
    Location getLastLocation = locationManager.getLastKnownLocation
    (LocationManager.PASSIVE_PROVIDER);
    longitude = getLastLocation.getLongitude();
    latitude = getLastLocation.getLatitude();
    }

  11. thầy ơi cho em hỏi vì sao khi hiển thị vị trí trên genymotion thì nó lại không đúng vị trí của mình ?

    1. Hi em, không phải không đúng mà có thể do sai số hoặc chưa update vị trí mới nhất.

      1. Thầy ơi em không hiểu cái chỗ lấy hình từ facebook, em ko biết lấy link ở đâu mặc dù em vào facebook chép link và dán vào mà nó không ra. Thầy có thể chỉ em được không ? Em cảm ơn thầy nhiều.

        P/S: Thầy có thể làm nhiều bài chỉ về google map này thêm được không thầy ? Ví dụ như chỉ đường ngắn nhất hay hiện hình ảnh của vị trí mà mình đến.

  12. Nguyễn Quốc Anh | Reply

    Thưa thầy!

    Thấy cho em hỏi tại sao marker không hiển thị hình ảnh của em mặc dù đã load thành công. Em biết được điều đó là vì marker hiển thị đúng chiều dài và chiều rộng của hình nhưng chỉ hiển thị màu trắng. Mong thầy giúp em ạ

    Cám ơn thầy!

  13. Hi em
    Em phải mô tả chi tiết hơn, như vậy không biết giải quyết như thế nào
    – Show code và hình muốn hình thị tại vị trí marker nào đó
    Thầy Thanh

    1. Nguyễn Quốc Anh | Reply

      Dạ. Em cám ơn thầy. Em đã làm được rồi ạ. Code em sử dụng như thầy mình họa chỉ thay đổi 1 số thuộc tính cho phù hợp với ứng dụng của em. Em không biết nguyên nhân như thế nào. Sau khi e sử dụng thu viên Picasso cho kết quả tương tự thì em quay lại sử dụng code của thầy thì hình ảnh hiển thị ạ. Nhưng có 1 điểm là hình của em hiển thị không có background màu trắng đẹp như của thầy ạ. Mình có thể tùy chỉnh cái background đó khộng ạ. Em cảm ơn thầy.

      Hình ảnh hiển thị của em như thế này đây ạ
      https://drive.google.com/open?id=0BzUnsZZ8EGOXTlpNTno1NllhSjQ

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s