728x90

캄보다이 앙코르왓 여행 준비물에 대해 적어본다.


여행기간 : 2017.4.20 ~ 4.25 (3박 5일)

여행지 : 캄보디아 앙코르왓


캄보디아 여행 준비물


여권

- 여권은 나를 식별해주는 신분증이므로 반드시 챙겨야 한다.

출처: http://link2me.tistory.com/1097 [소소한 일상 및 업무TIP 다루기]
- 여권은 나를 식별해주는 신분증이므로 반드시 챙겨야 한다.

출처: http://link2me.tistory.com/1097 [소소한 일상 및 업무TIP 다루기]

- 여권은 나를 식별해주는 신분증이므로 반드시 챙겨야 한다.

- 패키지 여행을 가면 현지 가이드가 여권을 전부 걷었다가 마지막날 공항으로 가는 버스에서 돌려줬다.

- 여행중에 여권을 분실하면 수도 프놈펜까지 비행기로 가야만 여권 발급이 가능하다고 하니

  절대 여권은 분실하지 말아야 한다.

- 여권 분실을 대비해서 사진 2매를 가져가는게 좋다.


신용카드

- 신용카드는 1개 가져가면 된다.

- 쇼핑 가게에 들를 때 필요하더라.

- 쇼핑으로 들른 곳은 상황버섯, 라텍스 가게다.

  라텍스 베게가 정말 편해서 구입했다.

  라텍스는 베트남에서 들여온 것인거 같은데 베트남보다 약간 더 비싸다.

  전세계적으로 베트남산 라텍스가 가장 품질이 좋단다.

- 다른 분들은 상황버섯을 많이 구입하더라.

  가격이 후덜덜해서 난 도저히 구입을 못하겠더라.

  상황버섯으로 끓인 물은 쉬지 않는다고 한번에 1주일치, 한달치 끓이라고 하더라.

  버섯을 냉장고에 넣는 것은 절대 금하라고 알려준다.

- 베트남에서 구입한 사향 족제비 커피(위즐)이 있는지 문의해봤는데 위즐 커피는 없더라.

  발리 사향 고향이 커피(루악)은 있는데, 구입하지 않았다.

  시엠립 공항 면세점에서 파는 커피는 10달러여서 1개만 사서 가져왔다.

 


현금

- 현금은 미리 은행에서 달러로 환전한다. 공항에서 환전하면 손해를 본다.

  캄보디아 여행시 사용하는 돈은 거의 달러라고 보면 된다.

- 1달러, 5달러, 10달러, 20달러, 50달러, 100달러 짜리 등으로 준비한다.

  2달러 짜리는 사용하지 않는단다.

  오래된 10달러 가지고 갔더니 안받아준다.

  다른 나라에서는 사용할 수 있다면서 캄보디아에서는 안된단다.

- 숙소 1달러, 짐 날라다 주면 1달러

  길거리에서 물건파는 애들 1달러 달라고 한다.

  캄보디아는 GDP가 1천달러 수준으로 정말 못사는 나라인지라 1달러의 가치도 엄청 크다.

  성인 1달 월급이 70달러 수준이고 좀 더 많이 받으면 우리나라 돈 기준 15만원 정도 된단다.



비자발급

- 캄보디아는 공항에서 비자 발급을 받아야 한다.

  수수료는 30불인데 공무원들이 1불을 더 줘야 빨리 처리 해준단다.

  그래서 공항 도착하자마자 31불을 제공해야 한다. 입국 비자 서류는 비행기에서 작성한다.

  필기구(볼펜)은 반드시 준비를 해야한다.

- 비자용 사진 한장은 꼭 여권사진이 아니어도 된다.


- 병원에서 진료 받으면 1천달러는 기본으로 깨진다고 하니 비상약은 꼭 준비해야 한다.

  병원에서 오진도 상당히 많이 하는 가 보다. 병원 검사장비가 노후화된 거라 오진이 나온단다.

- 약, 통/제, 제, 드, 모기퇴치제(선택)

- 상처가 생길 경우를 대비해서 연고도 준비하는게 좋다.

- 피곤을 풀어줄 종합비타민제를 준비하는 것도 좋다.

  여행중에는 면역력이 약해질 수 있으므로 비타민을 먹어주면 감기 예방에 도움이 된다.


- 여권은 나를 식별해주는 신분증이므로 반드시 챙겨야 한다.

출처: http://link2me.tistory.com/1097 [소소한 일상 및 업무TIP 다루기]


우산

- 태양이 뜨거우므로 양산을 준비하는 것도 좋다. 날씨가 정말 덥다.

- 우산(3단 접이식)은 준비하는 것도 좋다.

  건기에는 비가 거의 안오므로 우산 용도보다는 양산 용도로 활용하게 되더라.

- 우기에 여행을 한다면 우산은 필수 준비물이 되겠다.


- 관광버스 안에 물을 준비하여 언제든지 먹을 수 있게 해준다. (패키지 여행)

  외국여행하면서 물을 잘못 먹으면 배앓이(장티푸스)를 할 수 있으므로

  현지가이드가 준비해준 물만 먹으라고 하더라.

  후진국이다보니 위생문제 등이 취약한 편이라고 보면 된다.


휴대폰 로밍

- 휴대폰 로밍을 해도 캄보디아는 3G 접속이라 인터넷 속도는 엄청 느리다.

- 충전기는 필수, 보조배터리는 반드시 챙겨가는게 좋다.

  보조배터리는 너무 용량이 큰 것보다 가벼운 걸로 사는게 좋다.

  용량이 너무 큰 것을 사다보니 활용도가 떨어진다.


멀티어댑터 

- 3구 어댑터는 준비하면 밤에 충전할 때 편하다.

- 전기는 220V를 사용한다.


옷, 선크림

- 적도 부근에 위치하여 날씨가 사시사철 여름이므로 날씨가 너무 뜨껍다

- 대부분 반팔을 입고 여행을 한다.

  반팔 + 팔토시를 하면 편하게 여행할 수 있다.

- 얼굴이 타는 걸 방지하기 위해 선크림은 필수다.

  약국에서 파는 4만원 주고 산 선크림은 좋은지 전혀 얼굴이 타지 않았다.

  한번 바르면 하루종일 효과가 간다고 하더라.

- 잠바를 준비해서 비가 올 때 걸치면 좋다.

- 속옷, 양말, 반바지, 긴바지, 반팔

  날씨가 너무 더워 속옥을 갈아 입을 경우가 많으므로 충분히 가져가는게 좋다.

  앙코르왓 사원에 갈 때에는 민소매, 짧은 바지, 치마 등은 입을 수 없고, 무릎을 덮은 긴 옷을 입어야 한다.

- 운동화, 샌들 모두 챙기는 것이 좋다.


기타 준비물

- 마스크

  앙코르왓으로 이동할 때 툭툭이(오토바이를 개조하여 사람이 2명 탑승)로 이동할 때 마스크를 쓰는게 좋다.

  패키지 여행은 현지 가이드가 구매해서 나눠준다.

- 배낭은 가벼운 짐을 넣고 다닐 수 있는 백팩으로 준비한다.
- 비누, 린스/샴푸
  후진국이다보니 호텔이라도 비누 품질은 좋지 않다. 그러므로 비누는 별도로 가져가는게 좋다.

  호텔에 린스가 없더라. 린스는 가져가면 유용하게 사용된다.

- 캄보디아에서 가이드가 나눠주는 부채는 금방 망가진다.

  날씨가 더운 만큼 별도로 부채를 준비하면 좋다.

- 모기퇴치제

  호텔에도 모기가 있더라. 모기퇴치제를 몸에 뿌리고 잠을 잤다.

  약국에서 구입하면 1만원 정도 된다.

- 식사 때문에 고생은 하지 않지만, 김은 가져가면 먹는데 조금 낫다.

 


공항

- 저가 항공을 이용하다보니 무인발급기에서 티켓을 발권 받을 수 없더라.


캄보디아 여행회화

캄보다어 회화는 까로나의 유투브 동영상 https://www.youtube.com/watch?v=hy9MsaKWU8E 을 보고 적었다.

여행하면 현지 가이드가 기본적인 것 몇개는 알려준다.

손의 위치는 가슴에서 코끝 정도까지로 인사를 한다.

- 안녕하세요(잘 지내세요?) : 쏙 써바이, 쏙 써바이 떼

- 잘가 : 쏙 써바이

- 안녕하십니까? : 쭘므리읍 쑤어 (격식있는 인사말)

- 안녕히 계세요 : 쭘므리읍 리어 (격식있는 인사말)

- 감사합니다 : 어 꾼

- 대단히 감사합니다 : 어꾼 쯔라은

- 미안합니다. 실례합니다 : 쏨 또ㅎ

- 천만에요. 괜찮습니다 : 먼 아이 떼, 엇 아이 떼

- 어디 가세요? : 떠으 나?

- 식사 하셨어요? : 냠 바이 하으니 너으?

- 먹었어요 : 냠 하으이

- 아직요, 저 아주 배고파요 : 너으, 크뇸 클리은 나ㅎ

- 다음에 만나요 : 쭈웁 크니어 뻬일 끄라오이

- 다음주에 만나요 : 쭈웁 크니어 아뜯 끄라오이

- 내일 만나요 : 쭈웁 크니어 틍아이 쓰아엑





블로그 이미지

Link2Me

,
728x90

안드로이드 PUSH 서버, 메신저 만드는 방법을 검색해보다가 알게된 내용을 적어둔다.


아파치 웹서버

nginx

  • 쓰레드/프로세스 기반 구조
  • 클라이언트의 요청이 들어오면 쓰레드를 생성
  • 사용자가 많으면 많은 쓰레드 생성 ==> 메모리 및 CPU 낭비, Context-Switching Overhead 발생
  • 비동기(async) 이벤트(ioctl, send, recv, epoll)기반 구조
  • 다수의 연결을 효과적으로 처리
  • 대부분의 코어 모듈이 Apache보다 적은 리소스로 더 빠르게 동작


안드로이드 앱의 구성 요소와 데이터 전달




  • 제작 : 기획부터 개발까지 하나의 서비스를 온전히 만들어내는 것
  • 개발 : 결정된 기획과 디자인을 바탕으로 소프트웨어를 구현하는 것
  • 고객이 불편한 부분을 이해하고 체감해야 한다.
  • UI 쓰레드는 UI만 처리하게 하라.
  • 다양한 화면 해상도를 지원하라
  • 화면 해상도에 맞게 다양한 리소스를 제공하라.
  • 네트워크는 항상 느리다고 가정하라.
  • 다양한 하드웨어에 대비하라. (터치스크린, 키보드, 센서)
  • 좋은 코드를 작성하라 (CPU 사용량 낮고, 메모리 사용량 낮고, 가독성은 높게)
    - 필요한 기능을 최대한 간결히 작성하라
    - 클래스/메소드/변수 이름을 명확히 하라.
    - 코드를 어렵게/복잡하게 작성하지 마라.
  • 객체는 최대한 적게 생성하라
    - static 메소드를 사용해서 객체 생성을 줄일 수 있다.
    - 반복문에서는 객체 생성을 줄여야 한다.
    - 객체를 재사용한다.
  • 불필요한 코드를 제거하라
    - 쓸데없는 캐스팅을 줄여야 한다.
  • 메소드는 정적(static) 메소드로 선언하라.
  • 클래스 내에서는 Getter 와 Setter 를 사용해서 변수에 접근하지 말라.
  • 값이 고정된 변수는 상수로 선언하라.
  • enum은 되도록 사용하지 말아라.
  • 부동소수형은 되도록 사용하지 말아라.
    정수형이 부동소수형보다 일반적으로 2배 더 빠르다.
  • 네티브 코드는 되도록 사용하지 말아라.
    - 디바이스에 따라 호환되지 않을 수 있다.
    - 디버깅을 하는 것이 쉽지 않다.
  • 자바의 코드 노하우가 반드시 안드로이드의 코드 노하우는 아니다.
    - 가독성을 위해 중첩 클래스를 사용하지 마라.
    - 클래스는 되도록 작게 생성하라.
  • 버전은 어떤 범위까지 지정할 것인가?
    - 지원하려는 플랫폼 구버전의 범위를 지정하는 것은 재량이지만,
      최신 버전의 플랫폼을 지원하는 것은 기본으로 한다.
  • 오픈소스로 공개된 많은 커스텀된 GUI 컴포넌트 코드들이 있으며, 이를 구글 검색 등을 통해 쉽게 찾아낼 수 있다. https://github.com/wasabeef/awesome-android-ui
  • 안드로이드 내부에서 기본 이미지를 제공하지만 매우 제한적이다.
    구글이 Material Design 풍의 아이콘 셋들을 오픈소스로 공개했다.
    https://github.com/google/material-design-icons/releases
  • 안드로이드 앱 개발할 시에는 다양한 버전에서의 테스트가 필요한데, Genymotion을 이용하면 쉽게 해결할 수 있다. https://www.genymotion.com/
  • 출시할 때에는 꼭 앱이 디버깅용이 아닌 출시용으로 빌드가 됐는지 확인하고, 서버도 디버깅 모드로 배포되었는지 여부를 확인한다.
  • 모든 준비가 완료되었다면, Play 스토어 등과 같은 모바일 어플리케이션 마켓 플레이스에 배포를 진행하면 된다.


블로그 이미지

Link2Me

,
728x90

// Back 버튼을 눌러도 종료되지 않게 처리
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if( keyCode == KeyEvent.KEYCODE_BACK ) {
        return true;
    }       
    return super.onKeyDown(keyCode, event);
 }


// Back 버튼을 누르면 어플 종료여부 확인 처리
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if( keyCode == KeyEvent.KEYCODE_BACK ) {
        new AlertDialog.Builder(this).setIcon(android.R.drawable.ic_dialog_alert).setTitle("Quit").setMessage("어플을 종료하시겠습니까?").setPositiveButton("Yes", new DialogInterface.OnClickListener() {
            @Override
            public void onClick( DialogInterface dialog, int which) {
                moveTaskToBack(true); // 본 Activity finish후 다른 Activity가 뜨는 걸 방지.
                finish();
                //application 프로세스를 강제 종료
                android.os.Process.killProcess(android.os.Process.myPid() );
            }
        }).setNegativeButton( "No", null ).show();
        return true;
    }
    return super.onKeyDown(keyCode, event);
}




블로그 이미지

Link2Me

,
728x90

Android Studio 에서 연락처 저장하는 기능으로 구현에 필요한 내용은 모두 적어둔다.

서버에서 읽어온 사진 이미지까지 저장할 수 있도록 했다.

서버에서 사진 이미지를 읽어오고 나면 Cache에 저장했으므로

MemoryCache memoryCache = new MemoryCache();
Bitmap cachedImage = memoryCache.get(strPhoto);

를 했는데도 불구하고 null 값이 나온다.


연락처(Contacts)에 전화번호를 저장하는 기능은 검사하여 있으면 삭제후 다시 신규 저장하는 방식으로 구현되어 있는데, 이런 로직보다는 데이터가 있으면 비교하여 달라진 것이 있으면 Update 하고 동일하면 패스하는 로직으로 구현하는 것이 바람직하다. 이런 구현방식은 개발자의 몫이기 때문에 여기에는 적어놓지 않는다.


import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.util.Log;
import android.widget.Toast;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;

public class Contacts {
    public Contacts(){
        
    }
    
     // 전화번호부에 존재하는 데이터인지 여부 검사
    // 표시 이름과 휴대폰번호를 기준으로 ContactId 구하기
    public long
ContactsIDExistCheck(ContentResolver cr, String display_name, String number) {
        long rawContactId = -1;

        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
        String[] projection = { PhoneLookup._ID, PhoneLookup.TYPE, PhoneLookup.DISPLAY_NAME };
        Cursor cursor = null;
        try {
            cursor = cr.query(contactUri, projection, null, null, null);
            if (cursor.moveToFirst()) {
                do {
                    String PhoneName = cursor.getString(cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME));
                    if (display_name.equals(PhoneName)) {
                        rawContactId = cursor.getLong(cursor.getColumnIndex(PhoneLookup._ID));
                        System.out.println(" ContactId = " + rawContactId + " 성명 : " + PhoneName);
                    }
                } while (cursor.moveToNext());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return rawContactId;
    }
   

    public void ContactsIDdelete(ContentResolver cr, Context context, Integer contactId){
        // 전화번호부 삭제
        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
           
        //remove contact from raw_contact table
        ops.add(ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI).
        withSelection(ContactsContract.RawContacts.CONTACT_ID + "=?", new String[]{String.valueOf(contactId)}).
        build());              
               
        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void ContactsIDinsert(ContentResolver cr, Context context, String strName, String strMobileNO) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, strMobileNO)
                .withValue(Phone.TYPE, Phone.TYPE_MOBILE)
                .build());

        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
            Toast.makeText(context, "연락처가 저장되었습니다.", Toast.LENGTH_LONG).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }
           
    }
    
    public void ContactsIDinsert(ContentResolver cr, Context context, String strName, String strMobileNO, String strOfficeNO, String strEmail, String strPhoto) {

        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, strName)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, strMobileNO)
                .withValue(Phone.TYPE, Phone.TYPE_MOBILE)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
                .withValue(Phone.NUMBER, strOfficeNO)
                .withValue(Phone.TYPE, Phone.TYPE_WORK)
                .build());

        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
                .withValue(Email.DATA, strEmail)
                .withValue(Email.TYPE, Email.TYPE_WORK)
                .build());

        MemoryCache memoryCache = new MemoryCache();
        Bitmap cachedImage = memoryCache.get(strPhoto);
        System.out.println("cachedImage ===" + cachedImage);
        if (cachedImage != null) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            cachedImage.compress(Bitmap.CompressFormat.JPEG, 60, bos);

            byte[] bytes = bos.toByteArray();

            ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.Photo.DATA15, bytes)
                    .build());
            try {
                bos.flush();
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
            Toast.makeText(context, "연락처가 저장되었습니다.", Toast.LENGTH_LONG).show();
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            Log.e("ContactsAdder", "Exceptoin encoutered while inserting contact: " + e);
        }          
    }   
}


메모리 캐쉬 파일을 수정했다.

import android.graphics.Bitmap;
import android.util.Log;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

public class MemoryCache {
    private static final String TAG = "MemoryCache";
    public static  Map<String, Bitmap> cache= Collections.synchronizedMap(
            new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
    private long size=0;//current allocated size
    private long limit=1000000;//max memory in bytes

    public MemoryCache(){
        //use 25% of available heap size
        setLimit(Runtime.getRuntime().maxMemory()/4);
    }

    public void setLimit(long new_limit){
        limit=new_limit;
        Log.i(TAG, "MemoryCache will use up to "+limit/1024./1024.+"MB");
    }

    public static Bitmap get(String id){
        try{
            if(!cache.containsKey(id))
                return null;
            return cache.get(id);
        }catch(NullPointerException ex){
            ex.printStackTrace();
            return null;
        }
    }

    public void put(String id, Bitmap bitmap){
        try{
            if(cache.containsKey(id))
                size-=getSizeInBytes(cache.get(id));
            cache.put(id, bitmap);
            size+=getSizeInBytes(bitmap);
            checkSize();
        }catch(Throwable th){
            th.printStackTrace();
        }
    }

    private void checkSize() {
        Log.i(TAG, "cache size="+size+" length="+cache.size());
        if(size>limit){
            Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
            while(iter.hasNext()){
                Entry<String, Bitmap> entry=iter.next();
                size-=getSizeInBytes(entry.getValue());
                iter.remove();
                if(size<=limit)
                    break;
            }
            Log.i(TAG, "Clean cache. New size "+cache.size());
        }
    }

    public void clear() {
        try{
            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
            cache.clear();
            size=0;
        }catch(NullPointerException ex){
            ex.printStackTrace();
        }
    }

    long getSizeInBytes(Bitmap bitmap) {
        if(bitmap==null)
            return 0;
        return bitmap.getRowBytes() * bitmap.getHeight();
    }
}


MainActivity.java 파일 내에 ListViewAdapter 부분

 private class ListViewAdapter extends BaseAdapter {
    ImageLoader imageLoader;
    Context context;

    public ListViewAdapter(Context context) {
        this.context = context;
        imageLoader = new ImageLoader(context);
    }

    @Override
    public int getCount() {
        return arrayList.size(); // 데이터 개수 리턴
    }

    @Override
    public Object getItem(int position) {
        return arrayList.get(position);
    }

    // 지정한 위치(position)에 있는 데이터 리턴
    @Override
    public long getItemId(int position) {
        return position;
    }

    // position에 위치한 데이터를 화면에 출력하는데 사용될 View를 리턴
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        final Context context = parent.getContext();

        // 화면에 표시될 View
        if(convertView == null){
            viewHolder = new ViewHolder();

            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.address_item,parent,false);

            convertView.setBackgroundColor(0x00FFFFFF);
            convertView.invalidate();

            // 화면에 표시될 View 로부터 위젯에 대한 참조 획득
            viewHolder.profile_Image = (ImageView) convertView.findViewById(R.id.profile_Image);
            viewHolder.tv_name = (TextView) convertView.findViewById(R.id.child_name);
            viewHolder.tv_mobileNO = (TextView) convertView.findViewById(R.id.child_mobileNO);
            viewHolder.tv_officeNO = (TextView) convertView.findViewById(R.id.child_officeNO);
            viewHolder.child_btn = (ImageView) convertView.findViewById(R.id.child_Btn);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        // PersonData 에서 position 에 위치한 데이터 참조 획득
        final Address_Item addressItem = arrayList.get(position);

        // 아이템 내 각 위젯에 데이터 반영
        // 선택된 row의 데이터를 표시한다. 표시될 view는 address_itemm.xml 의 각 항목을 이용하여 표시한다.
        //System.out.println("imageurl==" + addressItem.getProfile_image());
        if(addressItem.getProfile_image().equals("")){
            final Bitmap Base_Profile = PHPComm.autoresize_decodeResource(getResources(), R.mipmap.photo_base, 160);
            viewHolder.profile_Image.setImageBitmap(Base_Profile);
        } else {
            String photoURL = Value.IPADDRESS + "/photos/" + addressItem.getProfile_image();
            imageLoader.DisplayImage(photoURL, viewHolder.profile_Image);
        }

        viewHolder.tv_name.setText(addressItem.getName());
        viewHolder.tv_mobileNO.setText(PhoneNumberUtils.formatNumber(addressItem.getMobileNO()));
        viewHolder.tv_officeNO.setText(PhoneNumberUtils.formatNumber(addressItem.getOfficeNO()));

        final String[] items ={"휴대폰 전화걸기","사무실전화 걸기", "연락처 저장"};
        final AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("해당작업을 선택하세요");
        builder.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //Toast.makeText(context, items[which] + "선택했습니다.", Toast.LENGTH_SHORT).show();
                switch (which){
                    case 0:
                        if(addressItem.getMobileNO().length() ==0){
                            Toast.makeText(context, "전화걸 휴대폰 번호가 없습니다.",Toast.LENGTH_SHORT).show();
                            break;
                        }
                        AlertDialog dialog1 = new AlertDialog.Builder(context)
                                .setTitle(addressItem.getName())
                                .setMessage(PhoneNumberUtils.formatNumber(addressItem.getMobileNO()) + " 통화하시겠습니까?")
                                .setPositiveButton("예",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog, int which) {

                                                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + PhoneNumberUtils.formatNumber(addressItem.getMobileNO())));
                                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                                                   // TODO: Consider calling
                                                   if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
                                                       requestPermissions(new String[]{Manifest.permission.CALL_PHONE},1000);
                                                   }

                                                   return;
                                                }
                                                startActivity(intent);
                                            }
                                        })
                                .setNegativeButton(
                                        "아니오",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog,int which) {
                                                dialog.dismiss();
                                            }
                                        }).create();
                        dialog1.show();
                        break;
                    case 1:
                        if(addressItem.getOfficeNO().length() ==0){
                            Toast.makeText(context, "전화걸 사무실 번호가 없습니다.",Toast.LENGTH_SHORT).show();
                            break;
                        }
                        AlertDialog dialog2 = new AlertDialog.Builder(context)
                                .setTitle(addressItem.getName())
                                .setMessage(PhoneNumberUtils.formatNumber(addressItem.getOfficeNO()) + " 통화하시겠습니까?")
                                .setPositiveButton("예",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog, int which) {

                                                Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + PhoneNumberUtils.formatNumber(addressItem.getOfficeNO())));
                                                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                                if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
                                                    // TODO: Consider calling
                                                    return;
                                                }
                                                startActivity(intent);
                                            }
                                        })
                                .setNegativeButton(
                                        "아니오",
                                        new DialogInterface.OnClickListener() {
                                            public void onClick(DialogInterface dialog,int which) {
                                                dialog.dismiss();
                                            }
                                        }).create();
                        dialog2.show();
                        break;
                    case 2:
                        // 연락처 저장 함수 호출
                        AlertDialog.Builder SaveContact = new AlertDialog.Builder(context);
                        SaveContact.setMessage("전화번호를 저장하시겠습니까?");
                        DialogInterface.OnClickListener save = new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                int rawContactId = 0;
                                Contacts phonebook = new Contacts(); // 전화번호부 객체 생성
                                ContentResolver cr = getContentResolver();
                                String strContactName = addressItem.getName();
                                String strMobileNO = addressItem.getMobileNO();
                                String strofficeNO =addressItem.getOfficeNO();
                                String strEmail ="";
                                String strPhoto ="";
                                if(addressItem.getProfile_image().length()>0){
                                    strPhoto =Value.IPADDRESS + "/photos/" + addressItem.getProfile_image();
                                }
                                //System.out.println("strPhoto ==="+ strPhoto);

                                rawContactId = phonebook.ContactsIDExistCheck(cr, strContactName,strMobileNO);
                                if(rawContactId > 0){
                                    // 기존 전화번호가 존재하면 삭제하고 새로 입력
                                    phonebook.ContactsIDdelete(cr, context, rawContactId);
                                }
                                phonebook.ContactsIDinsert(cr, context, strContactName, strMobileNO, strofficeNO, strEmail, strPhoto);
                            }
                        };

                        DialogInterface.OnClickListener cancel = new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        };
                        SaveContact.setPositiveButton("저장", save);
                        SaveContact.setNegativeButton("취소", cancel);
                        SaveContact.show();
                        break;
                }
            }
        });
        builder.create();

        viewHolder.child_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                builder.show();
            }
        });

        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(getApplicationContext(), "상세보기를 눌렀습니다 ==="+ addressItem.getUid(), Toast.LENGTH_SHORT).show();
            }
        });

        return convertView;
    }

    // 아이템 데이터 추가를 위한 메소드
    public void addItem(String profile_image, String uid, String name, String mobileNO, String officeNO){
        Address_Item item = new Address_Item();
        item.setProfile_image(profile_image);
        item.setUid(uid);
        item.setName(name);
        item.setMobileNO(mobileNO);
        item.setOfficeNO(officeNO);

        arrayList.add(item);
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == 1000) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "권한 요청을 승인했습니다.", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "권한 요청을 거부했습니다.", Toast.LENGTH_SHORT).show();
            }
        }
    }

}


블로그 이미지

Link2Me

,
728x90

같은 PC에서 Android Studio 와 Eclipse 를 같이 사용하다보니 SDK 를 같이 사용하면 문제가 생기더라.

그래서 SDK 를 각각 설치해서 사용하는데 간혹 Android Studio 에서 만든 예제가 Eclipse 기반 SDK를 사용하는 것이 있는지 헷갈린다.

그래서 아예 경로를 변경해버렸다.





이렇게 변경하면 나중에 백업할 때 파일 용량이 커서 문제가 좀 되기도 한다.


Eclipse 나 Android Studio 모두 설치된 경로를 그대로 백업하고 나중에 같은 경로에 폴더를 설치하면 그냥 동작한다.


블로그 이미지

Link2Me

,