[BlackPoint-Xr] 퍼펙트 튜토리얼 – 2 : SHP 파일로부터 레이어 추가하기

이전 튜토리얼을 통해 블랙포인트 라이브러리를 참조하는 안드로이드 프로젝트를 생성하는 내용을 살펴보았습니다. 이제 이전 튜토리얼에서 만들어진 프로젝트를 시작점으로 하나의 SHP 파일로부터 레이어를 추가해 표시해 보도록 하겠습니다.

레이어로 추가할 SHP 파일을 단말기에 담아야 합니다. 간단히 USB를 연결해 외장 저장장치로 인식하고 다음 폴더에 SHP 파일을 저장합니다. 아래의 이미지는 단말기에 저장된 SHP 파일들입니다.

가장 처음 인식하는 폴더 위치에 mapdata 폴더를 만들고 그 내부에 shp 폴더를 만들었습니다. 그리고 이 shp 폴더에 shp 파일을 복사했습니다. 이 shp 파일 중 TL_SCCO_SIG.shp 하나를 사용할 것이고, 다른 shp 파일을 다른 튜토리얼에서 사용할 것입니다.

레이어는 맵뷰를 대상으로 추가되므로, 먼저 레이아웃에 배치된 맵뷰 객체에 접근할 수 있어야 합니다. 맵뷰가 있는 레이아웃에 대한 엑티비티인 MainActivity 클래스에 다음 지역 변수를 정의합니다.

그리고 MainActivity의 onCreate 함수의 코드 가장 마지막에 다음 코드를 추가합니다.

1번 코드는 맵뷰에 할당된 ID 값을 통해 뷰 객체의 참조를 얻어와 map 변수에 저장합니다. 나머지 3~6번 코드는 정확한 지도 축척값을 계산하기 위해 단말기에 대한 화면 DPI값을 맵뷰에 전달하는 것입니다.

이제 SHP 파일을 통해 레이어를 추가하기 위해 OnMapReady라는 함수에 대해 설명합니다. 이 함수는 OnMapReadyEventListener 인터페이스의 맴버 함수입니다. 이 OnMapReady 함수는 이벤트로써, 맵뷰에 어떤 레이어를 추가할 준비가 되었을 때 호출되는 함수입니다. 아래의 코드처럼 MainActivity 클래스가 OnMapReadyEventListener 인터페이스를 구현하도록 하고, OnMapReadyEventListener의 맴버 함수인 OnMapReady 함수를 선언합니다.

그리고 MainActivity의 onCreate 함수의 마지막에 다음 코드를 추가합니다. 이는 안드로이드의 일반적인 이벤트를 설정하는 과정과 동일합니다.

이제 앞서 선언한 onMapReady 함수 안에 레이어를 추가하는 코드를 넣을 것입니다. 그런데 이 레이어를 추가하는 코드는 시간이 많이 소요될 수 있습니다. 그러므로 스레드를 통해 분리해 두는 것이 적당합니다. 레이어를 추가하는 코드를 실행해주는 코드를 LayerLoadingTask라는 클래스를 만들어 분리합니다. 또한 이 LayerLoadingTask 클래스는 AsyncTask를 상속받음으로써 스레드로 작동됩니다. LayerLoadingTask 클래스를 별도의 Java 코드 파일로 만듭니다.아래 코드가 바로 그것입니다. 코드에 대해서 필요한 Class의 import 문이 빠져 있습니다. 이는 안드로이드 스튜디오의 Alt+Enter 키를 통해 손쉽게 추가해 줄 수 있습니다.

AsyncTask 클래스는 특성상, 별도의 스레드로 구동되는 코드를 doInBackground 함수에서 실행됩니다. 그리고 이 doInBackground 함수가 실행되기 직전에 onPreExecute 함수가 실행되고 doInBackground 함수가 종료되면 onPostExecute 함수가 실행됩니다. 참고로 onPreExecute와 onPostExecute 함수는 UI 스레드단에서 실행되므로 화면 뷰 UI에 접근할 수 있습니다. 반면 doInBackground 함수는 UI 스레드가 아닌 별도의 스레드에서 호출되므로 UI에 접근할 수 없습니다. 레이어를 추가하기 직전에 맵뷰의 마우스 모드를 MouseMode.Node으로 지정해 사용자가 레이어가 추가되는 도중에는 화면 터치에 대해 맵뷰가 반응하지 않도록 합니다. 그리고 doInBackground 함수에서 실제 레이어를 추가하게 되는데요. 23번 코드를 통해 shp 파일을 저장된 디렉토리를 얻습니다. 25번 코드가 SHP 파일을 통해 레이어를 생성하는 코드인데, ShapeLayer 클래스의 생성자의 첫번째 인자는 레이어의 고유 ID값이고 두번째는 SHP 파일의 전체 경로 값입니다. 레이어의 고유 ID 값을 통해 추후 레이어 객체를 찾고 접근할 수 있게 됩니다.27번 코드에서는 이렇게 생성된 레이어 객체를 맵뷰에 추가하는 코드입니다. 레이어 추가에 대한 스레드 코드의 실행이 완료되면 onPostExecute 함수가 실행됩니다. 먼저 추가된 레이어를 화면에 가득 채울 수 있는 MBR을 35~37 코드를 통해 얻습니다. 38번 코드에서는 이렇게 얻은 MBR 값을 지정해 주고 39번 코드에서 실제 지도를 화면에 그려주게 됩니다. 41번 코드는 맵뷰의 마우스 모드를 MouseMode.MapViewMode로 변경해 줌으로써 사용자가 화면 터치를 통해 지도를 확대하고 이동할 수 있도록 합니다.

이제 MainActivity의 onMapReady 함수를 다음처럼 개선합니다.

실행하기에 앞서, 안드로이드에서는 외부 저장장치의 파일을 읽기 위해서는 퍼미션이 필요합니다. 이를 위해서 AndroidManifest.xml 파일에 퍼미션을 추가합니다.

이제 실행하면, 문제 없이 실행되는 경우도 있고, 그렇지 않은 경우도 있을 것입니다. 실행되지 않는 경우에 대한 문제는 역시 퍼미션입니다. 분명히 AndroidManifest.xml에 퍼미션을 추가했음에도 실행되지 않았다는 것인데요. 이는 Android SDK API 버전 번호가 23부터에서는 AndroidManifest.xml 뿐만아니라 실제 사용자가 이러한 퍼미션을 허락해줄 수 있는 과정이 필요하기 때문입니다. 만약 실행되지 않는 경우라면 아래의 코드를 MainActivity 클래스에 선언합니다.

그리고 MainActivity의 onCreate 함수의 코드 중 super.onCreate(..); 코드 바로 다음에 다음 코드를 추가합니다.

이제 실행하면, 방금 실행된 앱이 파일에 접근하는 것을 허용할 것인지를 묻는 대화상자가 표시됩니다. 허용 버튼을 터치하면 다음과 같은 실행 화면을 볼 수 있습니다.

일단 간단한 SHP 파일 하나만을 기본 색상으로 추가해 보았습니다. 다음 튜토리얼에서는 많은 SHP 파일을 통해 여러가지 심벌로 레이어를 구성해 보는 내용을 살펴 보겠습니다.

“[BlackPoint-Xr] 퍼펙트 튜토리얼 – 2 : SHP 파일로부터 레이어 추가하기”에 대한 6개의 댓글

    1. jar는 eclipse에서 생성할 수도 있는데요.
      굳이 jar로 만들지 않고 소스코드 자체를 프로젝트에 그대로 추가해 사용하는 것을 추천드립니다.

  1. 안드로이드 에뮬레이터에서 LocationManager 에러가 떠서 단말기에 연결해보았는데도 계속 에러가 뜹니다.. 이유를 모르겠네요.. gps는 켜둔 상태입니다..
    그리고 저는 여기서 쓰신 shp 파일을 못 찾아서 대한민국 행정구역 shp 파일로 실행중인데 레이어 로딩완료 토스트는 뜨는데 레이어는 뜨지 않습니다. LayersLoadingTask.java에서 파일명도 수정하였습니다..

    1. 안녕하세요, 김형준입니다.
      gps 관련 문제는 퍼미션 때문이 아닌지 싶습니다.
      몇년전부터 안드로이드 버전이 업되면서 퍼미션이 더욱 강화되어졌거든요.
      그리고.. 지도가 표시되지 않는 것은.. 소스코드를 어떻게 작성하셨는지 모르니.. 답변드리기 어렵네요..
      코드 문제가 대부분인데.. 한번 해당 글의 코드와 입력한 코드를 비교해 보시기 바랍니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다