2012년 12월 23일 일요일

공돌이식 연애 화법






오빠가 옛날에준 연애편지 보니까 euc-kr이더라…
Utf-8 로 다시써줘.

오빠.. 난 변수야 상수야. 난 대답을 들어야겠어.
변수면 이제 그만 shutdown -h now 해.

오빠. 저 별(*)이 내꺼라면 저게 날 가리키고 있는거야?
내 포인터란 소리지?

-. 어느 블로그에서 퍼온 글입니다.

2012년 12월 5일 수요일

Intent와 PendingIntent 이해하기





Intent와 PendingIntent 이해하기

PendingIntent도 일종의 Intent라고 생각해도 된다. 
그런데 Intent의 기본 개념은 특정 컴포넌트(Activity, Service, Broadcast Receiver, Content Provider)를 실행시키는 메시지라는 것이다.
역시 마찬가지로 PendingIntent도 Intent의 일종이므로 특정 컴포넌트를 실행시키는 기능을 한다는 것이다. 

그런데 PendingIntent는 생성자가 없고 
다음 세 개의 메소드들에 의해서 객체가 생성된다. 
getActivity(Context, int, Intent, int), 
getBroadcast(Context, int, Intent, int), 
getService(Context, int, Intent, int). 

그런데 이들 세 개의 메소드 중 어느 메소드에 의해서 생성된 PendingIntent 객체냐에 따라서 그 객체가 activity를 실행시킬지 서비스를 수행할지, 방송을 실행시킬지가 결정된다는 것이다.

다음은 Intent에 대한 설명이다. 이 설명을 보면 PendingIntent와 개념상 매우 유사함을 볼수가 있다.
Three of the core components of an application - activities, services, and broadcast receivers - are activated through messages, called intents. 
⇒ 안드로이드 애플리케이션에는 3개의 핵심 컴포넌트가 있는데 activities, services, and broadcast receivers이다.그런데 이들을 실행시키는 것은 메시지에 의해서 이루어지는데 바로 그 메시지를 intent라 한다.

Intent messaging is a facility for late run-time binding between components in the same or different applications. 
The intent itself, an Intent object, is a passive data structure holding an abstract description of an operation to be performed - or, often in the case of broadcasts, 
a description of something that has happened and is being announced. 
There are separate mechanisms for delivering intents to each type of component:

ㆍAn Intent object is passed to Context.startActivity() or   
   Activity.startActivityForResult() to launch an activity or get an existing 
   activity to do something new.
   ⇒ 이건 Intent가 Activity를 실행하는 용도로 쓰인다는 뜻이다.

ㆍAn Intent object is passed to Context.startService() to initiate a service 
   or deliver new instructions to an ongoing service. Similarly, an intent 
   can be passed to Context.bindService() to establish a connection 
   between the calling component and a target service.
   ⇒ 이건 Intent가 서비스를 실행하는 용도로 쓰인다는 뜻이다.

ㆍIntent objects passed to any of the broadcast methods (such as
   Context.sendBroadcast(), Context.sendOrderedBroadcast(), or
   Context.sendStickyBroadcast()) are delivered to all interested 
   broadcast receivers.
   ⇒ 이건 Intent가 BR(방송)을 실행하는 용도로 쓰인다는 뜻이다.

이렇게 Intent가 Activity, Service, Broadcast Receiver를 수행하는 기능을 하듯이 PendingIntent도 PendingIntent 객체를 생성하는 세 개의 메소드가
getActivity(Context, int, Intent, int), 
getBroadcast(Context, int, Intent, int), 
getService(Context, int, Intent, int)인데 이들 각각은 순서대로 
activity를 실행, 
Broadcast Receiver를 실행, 
서비스를 실행시키는 용도로 PendingIntent 객체가 생성된다는 것이다.

즉 PendingIntent 객체가 getBroadcast(Context, int, Intent, int)에 의해서 생성되었으면 그 PendigIntent 객체로는 방송을 실행한다는 것이고 getActivity(Context, int, Intent, int)에 의해서 생성된 PendingIntent 객체는 activity를 실행시킨다는 것이다. 
어느 메소드에 의해서 객체가 생성되었느냐에 따라서 PendingIntent객체가 실행하는 컴포넌트가 달라진다는 것이다.

public static PendingIntent getBroadcast (Context context, int requestCode, Intent intent, int flags)
⇒ Retrieve a PendingIntent that will perform a broadcast, like calling
   Context.sendBroadcast().

context : The Context in which this PendingIntent should perform the 
                 broadcast.
requestCode : Private request code for the sender (currently not used).
intent : The Intent to be broadcast.
flags : May be FLAG_ONE_SHOT, FLAG_NO_CREATE, 
             FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT, or any of 
             the flags as supported by Intent.fillIn() to control which 
             unspecified parts of the intent that can be supplied when the 
             actual send happens.
Returns : Returns an existing or new PendingIntent matching the given 
                 parameters. May return null only if FLAG_NO_CREATE has 
                 been supplied.

요약하면 Intent는 Activity, Service, BR을 실행시키는 message이다. PendingIntent도 일종의 Intent인데 이것의 객체가 getActivity()에 의해서 생성된 것이면 그 PendingIntent 객체는 Activity를 실행시키고 getBroadcast()에 의해서 생성된 객체이면 그 객체는 방송을 실행시킨다.

방송을 내 보낼때 어떤 컴포넌트에게 내보내는지는 Intent가 특정 컴포넌트를 호출하는 기능(명시적, 암시적 호출)이 있으므로 Intent의 이 기능을 PendingIntent가 활용해서 특정 컴포넌트에게 방송을 내보낸다.

이때 특정 컴포넌트가 방송을 수신할 수 있기 위해서는 Menifest에 방송 수신에 대한 정보를 기록해 두어야 한다.

2012년 11월 29일 목요일

홈 키(Home key)로 인한 콜백 메서드 호출 순서






홈 키(Home key)로 인한 콜백 메서드 호출 순서
HomeKey로 인한 호출의 경우 함수가 호출되는 순서가
onUserLeaveHint() ⇒ onPause() 의 순서가 된다.

따라서 홈키가 눌려졌는지를 확인할려면 onUserLeaveHint()에서 플래그 하나를 설정해 주고 onPause()에서 그 플래그를 확인하는 작업을 한다면 Home key가 눌려졌을 때를 알수가 있다.

HttpURLConnection에 대한 개괄적 개념






HttpURLConnection은 인터넷을 통해 원격의 서버에 연결하는 전문 클래스인데 연결 상태를 확인하게 해 주는 전문 클래스로 정리하면 되겠다. 
이때 연결 상태를 알수 있는 메소드는

getResponseCode()와 getResponseMessage()이다.

HttpURLConnection 객체를 얻는 방법은 URL의 메소드인 openConnection()으로 얻어낼 수 있다.

URL url = new URL("http://www.naver.com");
HttpURLConnection con = (HttpURLConnection)url.openConnection();

안드로이드 버전 3.0 이상에서 UI Thread에서 인터넷 연결시 runtime 에러 안 나게 하는 법





안드로이드 버전 3.0 이상에서 UI Thread에서 인터넷 연결시 runtime 에러 안 나게 하는 법

 if (android.os.Build.VERSION.SDK_INT > 9) {
      StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
      StrictMode.setThreadPolicy(policy);

안드로이드 버전 3.0 이상부터는 인터넷 연결은 쓰레드나 핸들러에서 처리하도록 정책이 바뀌었다. 그래서 UI 쓰레스에서 인터넷 연결을
시도하면(HttpURLConnection과 같은 것으로) 실행 타임에서 에러가 발생한다. 그런데 위와 같은 코드를 인터넷 연결을 시도하는 코드 앞에
표시해 두면 안드로이드 버전 3.0 이상에서도 정상적으로 잘 실행이 된다. 
그런데 위 코드를 인터넷을 연결하는 곳 앞에 하지 않고 onCreate()에 다음과 같이 해도 가능하다. 우와 놀랍다. 

    @Override
    public void onCreate(Bundle savedInstanceState) {
     if (Build.VERSION.SDK_INT > 9){
     StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
     StrictMode.setThreadPolicy(policy);
     }
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.get_signature_from_toodledo);
        
        txt = (TextView)findViewById(R.id.txt);
    }





xml의 layout_gravity에 대한 숨겨진 규칙






xml의 layout_gravity에 대한 숨겨진 규칙

안드로이드 앱 개발을 하다보면 xml 레이아웃 파일에서 조정하는 작업들이 생각처럼 잘 안 먹혀 들어갈 때가 있다.
특히 layout_gravity에 대해 작업할 때 그런 경험을 자주 하게 된다.

그 이유는 이런 개념 때문이다.

<?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" >
    <Button
           android:id="@+id/btnPlus"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:padding="10dip"
           android:text=" 테스트 "
           android:layout_gravity="center"
           android:textSize="25sp" />
</LinearLayout>

LinearLayout의 orientation이 vertical일 경우 
Button의 layout_gravity는 수평 관련 속성만 적용이 된다.
예를 들어 layout_gravity="left" 혹은 center_horizontal 혹은 right와 같이 수평 관련 속성만 적용이 된다.
수직 관련 속성은 적용이 안된다. 
예를 들어서 layout_gravity="bottom", 혹은 top...은 적용이 안된다.

만일 orientation이 horizontal이라면 
Button의 layout_gravity는 수직 관련 속성만 적용이 된다.
bottom, top, center_vertical

이 이야기의 핵심은 LinearLayout에서 첫 번째 방향을 설정했으면(만일 수평이면) 두 번째 방향 설정(layout_gravity)에서는 수평인 상태에서 그 수편 중 어느 위치로 움직일 것인지를 결정하는 것만 허용이 된다는 것이다. 
즉 수평이 첫 번째 설정 값이면(LinearLayout에서) 그 수평 중 top에 놓일지, bottom에 놓일지, center_vertical에 놓일지만 결정한다는 뜻이다.

2012년 11월 22일 목요일

Context에 대한 이해





Context를 이해하는 걸 다들 어려워 한다. 질문글에 답을 달다가 갑자기 정리가 깔끔하게 되서....

하나의 application이 실행되기 위해서는 그 밑바탕에 깔려져야 하는 많은 정보들과 환경들이 필요하다. 
그 정보들과 환경들을 안드로이드 시스템이 제공해 준다.
application 실행을 위해 밑바탕에 깔려져 있는 정보들과 환경들을 Context라 한다.
따라서 이 Context에는 안드로이 시스템이 제공해주는 유용한 많은 정보들이 있다.
따라서 이 Context를 통해서 안드로이드 시스템이 제공해주는 많은 유용한 정보들을 
꺼집어 낼수 있다(getSystemService() 메소드로).

근데 Context를 필요로하는 곳에 Activity 객체인 this를 념길수 있는 이유는  
Activity가  Context를 상속 받았기 때문에 Activity는 Context의 모든 정보를 가지고 있는 것이이다. 
그래서 Context를 필요로 하는 곳에서 Activity의 객체를 넘길수 있는 것이다.

Context를 얻을 수 있는 몇 가지 방법
-. Activity 객체를 통해서. Activity 객체 자체가 Context이기도 하기 때문에 Context를   
   필요로하는 곳에 Activity 객체인 this를 사용하면 된다.
-. View의 객체가 있으면 View의 getContext()를 통해서. View의 객체가 없는 상황이면 
   View v = new View(activity.this);로 만들면된다. 이때 View를 전역적으로 선언하면
   된다.
-. Context 클래스의 getApplicationContext()를 통해서
이정도면 Context를 못 구할 일이 별로 없을 것이다.

이클립스에서 변수명 한번에 모두 바꾸기





현재 자바 소스에 있는 특정 변수명을 변경할 경우 소스가 클 경우 다소 복잡한 작업이 된다. 이 문제를 한번에 해결하는 단축키가 이클립스에서 제공한다.


alt-shift-r : 변수명 변경(이 변수를 사용한 모든 곳의 변수를 모두 바꿈)

바꾸고자 하는 변수명에 커서를 둔 상태에서 alt-shift-r을 누른 후 변경하면 이 변수를 사용하는 모든 곳의 변수를 모두 바꾼다.
아주 유용한 팁이다.

이클립스에서 소스코드 앞에 라인넘버 숫자 붙이기





이클립스로 개발시 소스 코드에 라인 번호가 붙여지는 건 매우 필요하고 요긴하다.
근데 이클립스의 디폴트가 코드의 라인 번호가 안 붙여지는 것으로 되어 있다.
해법은, 

Window  ⇒  Pereference  ⇒  General  ⇒  Editors  ⇒  Text Editors 
  ⇒  Show line numbers를 체크 표시


지역변수에 final이 붙을 때의 의미에 대해(Cannot refer to a non-final variable 문제)





지역변수에 final이 붙을 때의 의미에 대해

만일 아래 코드에서 mText에 final이 붙지 않은 상태에서  
layout.setOnTouchListener()에서 mText를 사용하고자 하면
컴파일 단계에서 아래와 같은 에러가 발생한다.

Cannot refer to a non-final variable mText inside an inner class defined in a different method

이유가 뭘까? 같은 onCreate() 메소드 안에 있는 변수인데...?
그 이유는...

public class AAAActivity extends Activity  {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        final TextView mText = (TextView)findViewById(R.id.textV);
        
        LinearLayout layout = (LinearLayout)findViewById(R.id.linear);
        layout.setOnTouchListener(new View.OnTouchListener() {
          public boolean onTouch(View v, MotionEvent e) {
              mText.setText("Touched"); //에러 발생
                return true;
          }
        });
    }


  • mText는 전역변수도 아니고, onTouch()의 지역 변수도 아니며 onCreate()의 지역 변수로 선언되어 있다.
  • 리스너인 onTouch()는 onCreate()에 속한 지역 메서드가 아니라는 점을 주의해야 한다. onCreate()가 실행시에 onTouch()가 같이 실행되는 것이 아니라 터치 이벤트 발생시 실행할 메스드로 등록만 할 뿐이다.
  • 에러가 발생하는 이유는 mText 변수는 onCreate()가 리턴되면 사라지는 지역 변수이다.  반면 onTouch()는 터치 리스너로 등록되며 onCreate()가  리턴된 후에라도 이벤트가 발생하면 언제든지 호출될 수 있다. onTouch()가 호출되었을 때는 mText 변수가 존재하지 않으므로 mText의 실제값을 참조할 길이 없다. 미래에 호출될 리스너에게 현재의 지역 변수값을 전달하는 것은 불가능하다.
  • 그런데 여기서 지역 변수에 final을 붙이면 더 이상 변경할 수 없는 상수가 되므로 onTouch()를 등록하는 시점에 그 값을 분명히 전달할 수 있다. 

영어 발음기호와 같은 특수문자 나올수 있게 하는 arial.ttf 폰트 지정하는 법





        EditText engW = (EditText)findViewById(R.id.engWordUser);
      
        ... 중간 생략 ...
       
        //발음기호와 같은 특수문자가 EditText에 정상적으로 보이도록 하는 기능.
        //사전에 assets/fonts폴더를 만들어서 arial.ttf 폰트를 복사해 놓아야 함.
        Typeface face = Typeface.createFromAsset(getAssets(), "fonts/arial.ttf");
        engW.setTypeface(face);