336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

날씨가 따뜻해지고 여름이 찾아오면 창문 사이에 있는 물구멍으로 벌레들이 방안으로 들어오곤 한다. 


여기로 들어오는 벨레를 차단하기 위하여 "다이소"에서 파는 "물구멍 방충망"을 사려고 동네 다이소에 방문했다. 


하지만 발견하지 못하고 요넘을 발견하였다!! 



방충망 보수 테이프



보수 테이프니깐 한쪽에 끈끈이로 처리되어 있어 필름이 붙어있다. 필요한 만큼 잘라서 창문틀 아래에 있는 물구멍에 착~! 



근데 잘못 붙혔다.. 더 바깥쪽에 있는 물구멍을 막아야 했는데 ㅡㅡ; 


어쨌든 올 여름은 벌레들이 방으로 못들어오겠지 ?  



336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드 단말기에 있는 뒤로가기 하드웨어 키를 눌렀을 때, 앱이 종료 여부를 묻는 창을 보여주는 코드를 구현하도록 하겠다. 


1. 뒤로가기(BACK 버튼) 입력을 감지한다. 

2. 다이얼로그를 생성한다. 

3. 다이얼로그의 긍정 이벤트일때 앱을 종료한다.  

 


코드는 아래와 같다. 

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    // TODO 
}
	
@Override
// 1. 뒤로가지 입력을 감지한다. 
public void onBackPressed() {
    // 2. 다이얼로그를 생성한다. 
    Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("알림");
    builder.setMessage("앱을 종료하시겠습니까?");
    builder.setNegativeButton("취소", null);
    builder.setPositiveButton("종료", new DialogInterface.OnClickListener() {
   
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 3. 다이얼로그의 긍정 이벤트일 경우 종료한다. 
          android.os.Process.killProcess(android.os.Process.myPid());
       }
    });
    builder.show();
    }
}
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.


안드로이드 단말기에 있는 뒤로가기 하드웨어 키를 두번 눌렀을 때, 앱이 종료되는 코드를 구현하도록 하겠다. 


1. 뒤로가기(BACK 버튼) 입력을 감지한다. 

2. (현재 시간 - 이전 입력 시간) 이 유지 시간(duration_time) 보다 작다면 앱 종료

3. (현재 시간 - 이전 입력 시간) 이 유지 시간(duration_time) 보다 크다면 현재 시간 저장 및 가이드 메시지 보이기

 


코드는 아래와 같다. 

public class MainActiviry extends Activity {
   private static final long DURATION_TIME = 2000L;
   private long prevPressTime = 0L;

   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      requestWindowFeature(Window.FEATURE_NO_TITLE);
      // TODO 
   }
	
   @Override
   // 1. 뒤로가지 입력을 감지한다. 
   public void onBackPressed() {
// 2. 유지 시간(duration_time) 보다 작다면, 앱 종료
      if (System.currentTimeMillis() - prevPressTime <= DURATION_TIME) {
         android.os.Process.killProcess(android.os.Process.myPid());
      } else {
         // 3. 유지 시간(duration_time) 보다 크다면, 가이드 메시지 보이기. 
         prevPressTime = System.currentTimeMillis();
         Toast.makeText(this, "뒤로가기 버튼을 누르면 앱이 종료됩니다", Toast.LENGTH_SHORT).show();
      }
   }
}
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

minSdkVersion ?

애플리케이션이 실행하는 데 필요한 최소 API 레벨을 지정하는 정수입니다. Android 시스템은 시스템의 API 레벨이 지정된 값보다 낮은 경우 사용자 애플리케이션을 설치하는 것을 방지합니다. 

만약, 이 값을 지정하지 않을 경우 시스템이 애플리케이션이 모든 Android 버전과 호환됨을 나타내는 기본값 '1'을 가정합니다. 애플리케이션이 모든 버전과 호환되지 않고 적절한 minSdkVersion을 선언하지 않은 경우, 지정된 API 레벨 미만의 시스템에 설치된 애플리케이션은 사용할 수 없는 API에 엑세스하려고 시도하면 동작이 중단됩니다. 


targetSdkVeresion ? 

애플리케이션 대상 API 레벨을 지정합니다. 설정하지 않을 경우 기본값은 minSdkVersion에 주어진 값과 동일합니다. 이 값은 개발자가 대상 버전을 테스트했고 시스템 향후 앱의 대상 버전과의 호환성을 유지하도록 호환성 동작을 활성화해서는 안됨을 시스템에 알립니다. 

안드로이드는 신규 버전에 따라서 몇몇 동작과 심지어 UI까지 변경될 수 있습니다. 그러나 플랫폼의 API 레벨이 앱의 targetSdkVersion 이 선언한 버전보다 높은 경우 시스템은 앱이 예상대로 계속 작동하도록 호환성 동작을 활성화할 수 있습니다.  



여기까지 안드로이드 SDK 홈페이지에 기술된 내용을 옮겨보았다. 


minSdkVersion은 간단히 말하면, 개발자가 개발한 앱이 구동하기 위한 최소한의 안드로이드 플랫폼 버전이다. 즉, android:minSdkVersion = "19"로 기술되어 있다면, 개발자가 API 19 버전을 기반으로 개발했으므로, 그 이하의 단말에서는 설치할 수 없고 구동할 수도 없다는 것이다. 


targetSdkVersion은 기술된 안드로이드 플랫폼 버전까지 해당 앱의 구동을 확인한 것이다. 즉, android:targetSdkVersion = "19"로 기술되어 있다면, 안드로이드 플랫폼 버전 19인 단말에서 정상적으로 구동되었다는 것을 확인하였고, 그 이상 플랫폼 단말에서는 오작동할 수 있으니 하위호환성을 동작하지 못하도록 한다. 


개발자는 최신 안드로이드 버전을 확인하고 이후 신규 버전이 나왔을 때, 오작동하지 않도록 targetSdkVersion 값을 기술하여야 한다. 또한 신규 버전이 나왔을 때, 이상 동작 여부를 확인하여 targetSdkVersion 값을 변경해줘야 한다. 



참고: https://developer.android.com/guide/topics/manifest/uses-sdk-element.html?hl=ko 

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

사회 생활을 시작하고, 카드를 만들기 시작했다. 


그리고 빚쟁이 인생이 5-6년째 계속되고 있다. ㅠㅠ 


매월 지정된 날짜에 한달동안 빚진 금액을 청산하지만, 다시 빚쟁이가 되고있다.


암튼! 이렇게 빚쟁이 인생을 살면서 조금씩 카드포인트가 생겼다. 이렇게 생긴 카드 포인인트를 한번에 조회할 수 있는 방법이 있어서 소개하려고 한다. 



'여신금융협회"에서 제공하는 '카드포인트 통합 조회' 사이트 또는 안드로이드 앱을 이용하면 쉽게 조회할 수 있다. 


1. 카드포인트 통합 조회 사이트 이용하기

  • 이름 / 주민번호 입력

  • 카드회사 체크 및 조회



2. 카드포인트조회 앱(안드로이드) 이용하기

  • 구글플레이에서 "카드포인트조회" 앱 설치
구글플레이에서 "카드포인트조회" 로 검색하여 앱을 설치한다. 



  • 앱 실행하여 이름 / 주민번호 입력
  • 카드회사 체크 및 조회




336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

은행 계좌를 어릴적에 만들고, 대학교가서 만들고, 군대가서 만들고, 취업해서 만들고.... 


저렇게 만든 계좌가 다 동일한 은행이면 좋겠지만, 만들때마다 다른 은행에서 만들게되었다. 


잊고있었던 은행계좌도 존재하지만 확인할 방법이 없었다.


이렇게 잊고있었던 비활성 계좌를 조회하고 해지해주고, 만약 잔고가 있다면 이전까지 해주는 서비스가 있다. 



계좌정보통합관리서비스 (http://www.accountinfo.or.kr/)


이용 방법은 간단하다. 홈페이지로 이동하고 공인인증서를 이용해서 로그인하면 아래와 같은 화면을 볼 수 있다. 



여기서 비활동성계좌 있는 은행의 상세조회를 하고, 개좌해지/잔고이전 을 실행하면 된다. 


묵혀있던 1,300원 벌었다. 


336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

일반적으로 프로그래밍에서 서비스를 아래와 같이 말 할 수 있다. 


사용자는 모르지만 사용자에게 필요한 기능을 제공하거나, 프로그램에 필요한 기능을 안보이는 곳에서 주기적으로 제공해주는 것


안드로이드 시스템에서 예를 들어, 음악 플레이어 같은 기능을 말할 수 있다. 사용자가 음악을 플레이하고 다른 앱을 구동하여 웹 서핑이라던가 문서 작업을 해도 백그운드에서는 지속적으로 사용자에서 음악을 플레이해주고 있다. 


안드로이드 시스템에서 서비스를 구현하기 위해서는 아래와 같은 절차가 필요하다. 

  1. Service 클래스를 상속받아 새로운 기능을 제공하는 MyService 구현
  2. AndroidManifest.xml 파일에 구현한 MyService 선언
  3. 선언한 MyService 실행


1. Service 클래스를 상속받아 새로운 기능을 제공하는 MyService 구현 


android.app.Service 클래스를 상속받은 MyService 를 구현한다. onBind(...) 메소드에 대한 내용은 다음에 자세히 설명하도록 하겠다. 

안드로이드 서비스를 구현할 때, 아래 안드로이드 서비스 생명주기를 보면 onCreate, onStartCommand, onDestroy의 세 가지 메소드를 생각하여 구현해야 한다. 


  • onCreate(): 서비스를 실행하기 전에 초기화하는 기능을 구현하며, 최초 일회성으로 이미 한번 실행된 상태에서는 다시 호출되지 않는다.
  • onStartCommand(): 서비스가 시작할때 호출되는 메소드로 서비스의 실제 코드를 이곳에 구현하면 된다. 
  • onDestroy(): 서비스가 종료될 때 호출되는 메소드로 서비스가 종료되면 더이상 사용되지 않는 스레드나 리소스를 정리한다.    

여기서 주의해야 할 점이 있는데, 서비스는 기본적으로 메인 스레드에서 동작한다. 서비스가 엑티비티와 상호 작용을 하거나 시간이 오래걸리는 작업을 수행할 경우 해당 서비스때문에 엑티비티가 느려지거나 ANR 에러가 발생할 수 있다. 그러므로 해당 앱의 성능에 영향을 주는것을 방지하기 위하여 새로운 Thread 를 생성하여 시작해야 한다. 


public class MyService extends Service {

	@Override
	public IBinder onBind(Intent intent) {
		throw new UnsupportedOperationException("Not yet implemented");
	}
	
	@Override
	public void onCreate() {
		// 서비스를 실행하기 전에 필요한 초기화를 수행
		super.onCreate();
	}

	@Override
	public void onDestroy() {
        	// 서비스가 종료되면 더이상 사용되지 않는 스레드나 리소드를 정리
        	super.onDestroy();
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// 해당 서비스가 실제로 제공하는 코드를 구현
		return super.onStartCommand(intent, flags, startId);
	}
}


2. AndroidManifest.xml 파일에 구현한 MyService 선언


위에서 구현한 서비스가 실행하기 위해서는 아래와 같이 매니페스트 파일에 선언되어 있어야 한다. 


	
		
	


3. 선언한 MyService 실행


이렇게 구현되고 선언된 서비스를 실행하는 방법은 다른 Activity와 같이 context 정보를 유지하는 곳에서 아래와 같이 작성하면 MyService 를 실행할 수 있다. 

Intent intent = new Intent(this, MyService.class);
startService(intent);


[참고] https://developer.android.com/guide/components/services.html?hl=ko

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

JAVA 프로그래밍(객체지향프로그래밍)을 하다보면 클래스 및 메소드, 변수에 접근을 제어하기 위하여 public, private, protected 선언을 사용한다. 


그렇다면 이러한 선언에 따른 접근 권한이 어떻게되는지 알아보도록 하겠다. 


  • 접근 제어자
    • public: 모든 클래스에서 접근가능함
    • private: 클래스 내에서만 접근가능함
    • protected: 동일한 패키지에 속하는 클래스에서 접근가능함. 또, 자신을 상속받은 클래스에서 접근가능함.
    • (default): 아무것도 선언하지 않은 상태를 표현하며, 동일한 패키지에 속한 클래스에서만 접근 가능함.



336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

서비스의 특성상 지속적으로 제공해야하는 서비스인데 비정상적으로 종료될 경우, 비정상종료의 원인을 파악할 수 있는 로그를 남기고 서비스를 재실행하여 서비스를 계속 제공하면 된다. 


그렇다면, 이런것을 가능하게 하는 방법은 무엇일까? Java 1.5 부터 지원된 기능으로 setDefaultUncaughtExceptionHandlersetUncaughtExceptionHandler 메소드이다. 메소드 이름을 보면 알겠지만, 예상할 수 없는 예외사항을 처리하는 핸들러를 지정하는 것이다. 


static 함수인 setDefaultUncaughtExceptionHandler은 모든 스레드에서 발생하는 uncaught exception을 처리하는 핸들러를 지정할 때 사용하며, setUncaughtExceptionHandler은 해당 스레디에서 발생하는 uncaught exception을 처리하는 핸들러를 지정한다. 


예제 코드는 아래와 같다. 


package kr.yoongi.java.tutorial;

public class TutotialUncaughtExceptionHandler {
    class Task implements Runnable {
        @Override
        public void run() {
            Thread.currentThread().setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                @Override
                public void uncaughtException(Thread thread, Throwable e) {
                    // TODO 처리 코드 입력 
                    System.out.println(thread + " throws exception: "+ e);

                    // TODO 재실행을 위한 스레드 생성
                    // new Thread(new Task()).start();
                }
            }
            throw new RuntimeException();
        }
    }

    public static void main(String[] args) {
        Thread t = new Thread(new Task());
        /*
        Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable e) {
                System.out.println("DefaultUncaughtExceptionHanlder / " + thread + " throws exception: "+ e);
            }
        });
        */
        t.start();
    }
}



위의 코드를 실행하면 아래와 같이 콘솔에 출력됩니다. 


Thread[Thread-0,5,main] throws exception: java.lang.RuntimeException


여기까지는 Java 에서 사용하는 방법을 설명하였다. 만약 Android 에서 사용한다면 아래와 같은 상황을 고려해야 한다. 

  • 예외 사항을 처리한 후 앱 종료 방법
  • 앱 종료의 비정상종료를 나타는 UI를 표현하는 방법
  • 앱 종료 후 재실행하는 방법

Android 에서 사용하는 방법은 다시 작성하도록 하겠다. 


[참고]

1) https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html

2) https://developer.android.com/reference/java/lang/Thread.UncaughtExceptionHandler.html


336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

윈도우에서 버츄얼 박스를 이용하여 우분투를 설치하고 공유폴더를 설정하여 윈도우(host)와 버츄얼박스에 설치된 우분투(guest) 간의 파일을 공유하려고 했는데, '허가 거부'라는 에러가 발생하여 이를 해결하는 방법을 설명하려고 한다. 


먼저, 버츄얼박스에 우분투를 설치하고 공유폴더를 설정하는 방법을 설명하고 에러를 해결하는 방법을 설명한다. 


1. 버츄얼박스에 설치된 우분투에 공유폴더 생성


버츄얼박스에 우분투를 설치하고 공유폴더 및 확장(?) 기능을 사용하기 위해서는 '게스트 확장' 프로그램을 우분투(guest)에 설치해야 한다. 설치하는 방법은 매우 간단하다. 


버츄얼박스의 우분투를 실행하고 아래와 같이 버츄얼박스 메뉴의 [장치 -> 게스트 확장 CD 이미지 삽입] 를 선택한다. 



CD 이미지가 삽입되면 아래와 같은 팝업창이 나온다. 여기서 [실행] 버튼을 클릭한다. 



[실행] 버튼을 클릭하면 터미널 창이 나타나고 '인증'이라는 팝업창이 나타나고 관리자 권한이 필요한 동작을 수행하기 위한 관리자 암호 입력을 요청한다. 이 때, 관리자 암호 (또는 최초 생성한 계정의 암호)를 입력하면 설치가 진행된다. 진행이 완료되면 시스템을 재부팅시켜준다. 




재부팅 후 버츄얼박스 창의 화면을 변경하였을 때, 우분투 화면이 100% 동일하게 변경되면 '게스트 확장 프로그램'이 정상적으로 설치된 것이다. (설치전 상태를 캡쳐안해서 설명할 방법이 없네요;)



게스트 확장 프로그램이 설치 안되어 있을 때 버츄얼박스 프로그램 창의 크기를 크게하면, 위의 이미지에서 빨강색 부분이 희색(?)으로 보이게 된다. 하지만 게스트 확장 프로그램이 정상적으로 설치되며 회색부분이 없이 꽉찬화면으로 보여지게 된다. 



2. 버츄얼박스의 우분투에서 공유폴더 접근하는 방법


먼저 윈도우(host)에 공유할 폴더를 생성합니다. 예를 들어, 'D;\sample\AndroidShare' 라는 폴더를 생성한다. 



공유할 폴더를 생성 후 버츄얼박스 메뉴 중 [장치 -> 공유 폴더 -> 공유 폴더 설정]을 선택한다. 



설정이라는 팝업 창이 보이고 오른쪽 상단에  아이콘을 선택하면 아래와 같은 설정 화면이 나온다. 



'폴더 경로' 는 윈도우(host)의 경로를 지정한다. 예를 들어, 이전에 생성한 'D;\sample\AndroidShare' 폴더를 탐색기를 이용하여 선택한다. 

'폴더 이름' 은 우분투(guest)에 표시되는 디렉토리명이다. 예를 들어, 위의 폴더를 지정하면 자동으로 AndroidShare 라는 이름이 입력되는데, 이를 변경해도 된다. 

그 외 옵션은 사용자가 알맞게 설정하면 되는데, 마지막 옵션인 '항상 사용하기'를 체크하면 다음 부팅시에도 적용되는 것이고 체크되지 않는다면 이번 한번만 설정하여 사용하는 것이다. 


설정이 끝나고 우분투 화면에서 해당 폴더에 접근하려고 하면 아래와 같은 오류 메시지를 확인할 수 있다. 


$ cd /media/sf_AndroidShare/

bash: cd: /media/sf_AndroidShare/: 허가 거부 


그래서 권한을 확인해보면, 아래와 같이 sf_AndroidShare 디렉토리는 사용자 root, 그룹 vboxsf 로 되어 있고, 현재 사용 계정의 그룹에는 vboxsf 가 설정되어 있지 않아서 접근이 안되는 것을 확인할 수 있다.  


$ ls -al /media/

합계 12

drwxr-xr-x    4    root    root        4096    7월    8    10:58    .

drwxr-xr-x    25    root    root        4096    7월    8    10:58    ..

drwxr-x---+   2    root    root        4096    7월    8    10:58    android

drwxrwx---    1    root    vboxsf        0    7월    8    10:58    .sf_AndroidShare


$ groups

android adm cdrom sudo dip plugdev lpadmin sambashre


$



아래와 같이 현재 사용중인 계정에 vboxsf 그룹을 추가하면 접근할 수 있다. 


$ sudo usermod -G vboxsf -a android {현재 사용 계정먕}

[sudo] password for android: {암호}

$ groups 

android adm cdrom sudo dip plugdev lpadmin sambashre vboxsf

$ cd /media/sf_AndroidShare/

$ pwd 

/media/sf_AndroidShare/