엑셀 파일이 존재해야 하고, xls 형식이어야 한다.
1. assets 폴더를 생성해 엑셀파일(xls)을 넣는다.
2. 내부 DB (SQLite)에 엑셀 내용들을 저장한다.
3. Cursor를 이용해 엑셀 내용들을 읽어온다.
4.(추가구현) 구글맵에 마커 표시한다.
*구글맵 마커 표시는 제 개인 프로젝트 겸 해본 것입니다.
1. 엑셀파일 삽입
- assets 폴더 생성하는 법
- 공공데이터 포털에서 다운로드받은 엑셀파일이다.
2. 내부 DB에 엑셀내용 저장
참고로 내 엑셀파일은 이런 식으로 생겼다.
2-1) DatabaseHelper 클래스 생성
public class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table IF NOT EXISTS incheon_medicine ("
+ "_id integer primary key autoincrement,"
+ "번호 INTEGER," + "약국 TEXT," + "읍면 TEXT," + "주소 TEXT," + "전화번호 INTEGER);";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
String sql = "DROP TABLE IF EXISTS incheon_medicine";
db.execSQL(sql);
onCreate(db);
}
}
2-2) setDatas() 함수 생성
앞서, 우선 내부DB를 읽고 쓰게 할 수 있는 permission을 선언한다.
그리고 참고로, 나는 fragment 를 사용했기 때문에 코드가 살짝 다를 수 있다. 적당히 변환시켜주자.
public void setDatas() {
ContentValues values = new ContentValues();
Workbook workbook = null;
Sheet sheet = null;
//db파일 생성
dh = new DatabaseHelper(this.getActivity(), "incheon_medicine.db", null, 1);
db = dh.getWritableDatabase();
//파일 불러와서 db에 저장하기
try {
InputStream is = getActivity().getBaseContext().getResources().getAssets().open("incheon_medicine.xls");
workbook = Workbook.getWorkbook(is);
if (workbook != null) {
sheet = workbook.getSheet(0);
if (sheet != null) {
int colTotal = sheet.getColumns();
int rowIndexStart = 1;
int rowTotal = sheet.getColumn(colTotal - 1).length;
for (int row = rowIndexStart; row < rowTotal; row++) {
for (int col = 0; col < colTotal; col++) {
String contents = sheet.getCell(col, row).getContents();
switch (col) {
case 0:
values.put("번호", contents);
break;
case 1:
values.put("약국", contents);
break;
case 2:
values.put("읍면", contents);
break;
case 3:
values.put("주소", contents);
break;
case 4:
values.put("전화번호", contents);
break;
}
}
//db의 incheon_medicine 테이블에 values 값 넣어줌
db.insert("incheon_medicine", null, values);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
3. 내부 DB의 ___테이블의 내용을 읽어온다. - ReadDatas 함수
커서를 이용해 옆으로 읽어오면서 번호/약국이름/읍면/주소/전화번호를 가져온다.
public void ReadDatas(GoogleMap googleMap) {
Context context = this.getContext();
//테이블 incheon_medicine를 읽음
db = dh.getReadableDatabase();
Cursor c = db.query("incheon_medicine", null, null, null, null, null, null);
while(c.moveToNext()) {
Integer num = c.getInt(c.getColumnIndex("번호"));
String name = c.getString(c.getColumnIndex("약국"));
String town = c.getString(c.getColumnIndex("읍면"));
String address = c.getString(c.getColumnIndex("주소"));
Integer phoneNum = c.getInt(c.getColumnIndex("전화번호"));
Location location = addrToPoint(context, name);
LatLng loc = new LatLng(location.getLatitude(), location.getLongitude());
MarkerOptions marker = new MarkerOptions();
marker.position(loc); //마커 위치
marker.title(name);
// 마커 이미지 설정
BitmapDrawable bitmapdraw = (BitmapDrawable) getResources().getDrawable(R.drawable.med);
Bitmap b = bitmapdraw.getBitmap();
Bitmap smallMarker = Bitmap.createScaledBitmap(b, 200, 200, false);
marker.icon(BitmapDescriptorFactory.fromBitmap(smallMarker));
googleMap.addMarker(marker).showInfoWindow();
}
c.moveToFirst();
}
4. (추가구현) 구글맵에 마커표시
여기서 살짝의 난관이 있었다....
GoogleMap 안에서 기존의 LatLng 객체를 사용하려면 경도와 위도를 구해와야하는데,
너무나도 양이 많고 귀찮은 것이다.
그래서 주소내용만으로 위도경도를 알아낼 수 있는 geocoding 을 사용하였다.
geocoder는, 주소내용을 가지고 __가지 위도/경도를 찾아내 array에 저장하는 방식이다. (나는 3가지로 함)
이를 위해서는 안드로이드 스튜디오 내 인터넷 연결이 필수이다.
// geocoding 주소 변환
public static Location addrToPoint(Context context, String place) {
Location location = new Location("");
Geocoder geocoder = new Geocoder(context);
List<Address> addresses = null;
try {
addresses = geocoder.getFromLocationName(place,3);
} catch (IOException e) {
e.printStackTrace();
}
if(addresses != null) {
for(int i = 0 ; i < addresses.size() ; i++) {
Address lating = addresses.get(i);
location.setLatitude(lating.getLatitude());
location.setLongitude(lating.getLongitude());
}
}
return location;
}
OnMapReady 함수는 다음과 같다.
일단 서울로 초기 화면을 잡아주었다.
//맵뷰 설정
@Override
public void onMapReady(GoogleMap googleMap) {
Context context = this.getContext();
//마커찍기(위도,경도)
ReadDatas(googleMap);
//서울 찍기(중심)
Location seoul = addrToPoint(context, "서울시청");
LatLng SEOUL = new LatLng(seoul.getLatitude(), seoul.getLongitude());
MarkerOptions markerOptions = new MarkerOptions();
markerOptions.position(SEOUL);
markerOptions.title("서울");
markerOptions.snippet("서울시청");
googleMap.addMarker(markerOptions);
//인포윈도우 클릭
googleMap.setOnInfoWindowClickListener(this);
//맵뷰 카메라위치, 줌 설정 (서울)
googleMap.moveCamera(CameraUpdateFactory.newLatLng(SEOUL));
googleMap.animateCamera(CameraUpdateFactory.zoomTo(10));
googleMap.getUiSettings().setZoomControlsEnabled(true);
}
이렇게 하면 어찌저찌 마커가 표시되긴 하는데, 아주 느리다.
그리고 메인 쓰레드에서 너무 많은 작업을 한다며 안드로이드 스튜디오에서 불평을 한다.ㅋㅋ
결과화면) 인천 내 폐의약품 수거함이 있는 약국 위치 표시
마커이미지는 내가 그린 것이 아니다. 팀원이...
오래 걸리는 시간이 내부DB를 읽어오는 것 때문인 지, geocoding 때문인 지 정확히는 모르겠으나,
아마 geocoding 때문 같다.
(내부 DB만 읽어오는 것 자체는 그리 오래 걸리지 않았던 기억이 있다.)
'프로젝트' 카테고리의 다른 글
[안드로이드 스튜디오] 파이어베이스 storage에 이미지 업로드하기 / 불러오는 함수 (0) | 2021.08.29 |
---|---|
[안드로이드 스튜디오] 엑셀파일 읽어오기 (0) | 2021.08.28 |
[안드로이드 스튜디오] 커스텀 리스트뷰 검색기능 (0) | 2021.08.24 |
[Android Studio] 파이어베이스를 활용한 키워드 구독 / FCM (Firebase Cloud Messaging) (0) | 2021.07.15 |
[Android Studio] 학교 홈페이지 웹 크롤링 (0) | 2021.07.15 |