"화면해상도별 아이콘 제작하기"

안드로이드 Device는 제각각이기때문에, 해상도별로 Icon을 각각 제작하길 권장합니다. 
보통은 "low/medidum/high" 이 3가지 Type의 아이콘을 만들어야 합니다. 

Resourcedirectory qualifiers for screen size and density. 에서 알수 있듯이 다른 Type도 존재 하기 때문에, 필요 하다면 그에 대한 고려도 필요 합니다.

안드로이드 Device의 기준 해상도는 mdpi(medium) 입니다. 
그래서 안드로이드용 Icon 을 제작할때는 아래의 절차에 따라 제작하는것이 좋습니다.

1. 먼저 BaseLine 해상도(mdpi)로 먼저 아이콘을 재작합니다.
2. AVD나 HVGA( e.g T-Mobile G1) 의 Device 에 올려서 테스트 하고. 조정합니다.
4. mdpi 용 icon 제작이 끝나면 hdpi 와 ldpi용 아이콘을 제작합니다.
  • hdpi 용 아이콘은 mdpi 용 icon을 150%정도로 upscale합니다.
  • ldpi용 아이콘은 mdpi용 icon을 75%정도로 downscale합니다.
  • 5. 해상도 별로 AVD혹은 Device에 올려서 테스트 합니다.

    Table 1. 해상도별 아이콘 사이즈 요약정리

    Icon Type Standard Asset Sizes (in Pixels), forGeneralized Screen Densities
    Low density screen (ldpi) Medium density screen (mdpi) High density screen (hdpi)
    Launcher 36 x 36 px 48 x 48 px 72 x 72 px
    Menu 36 x 36 px 48 x 48 px 72 x 72 px
    Status Bar 24 x 24 px 32 x 32 px 48 x 48 px
    Tab 24 x 24 px 32 x 32 px 48 x 48 px
    Dialog 24 x 24 px 32 x 32 px 48 x 48 px
    List View 24 x 24 px 32 x 32 px 48 x 48 px
     
    Android R Class는 AndroidManifest를 기준으로 자동 생성되는 Class 파일이다.

    고로, AndroidManifest에서 Package를 변경할 수 있다.

    <manifest></manifest> 를 보면,

    packge라는 attribute 가 있고, 그 값을 수정해주고, 저장하면 자동으로 변경된다. 

    단, R Class를 사용하는 소스의 import는 알아서 정리해줘야 한다. 




    오늘 오래간만에, Android New Project를 만들려고하는데,

    proguard.cfg 가 없다는 에러가 발생 ;ㅂ;

    이건 도 뭐야 하면서 짜증내는데,, stackoverflow.com 을 보니까, Android SDK Tool을 Upgrade해보라고 했다. 


    update 하니까 잘된다 ㅎㅎ






    Twitter는 회원 인증과 OAuth 와 XAuth를 지원합니다. 
    사실 XAuth로 인증 하는것이 Mobile에서 보편화된 방법인데, XAuth는 ID/Password를 3rd-Party Application에서 입력 받기에,  
    개인적으로는 OAuth를 선호 합니다. 

    Twitter에서 OAuth는 oauth_verifier를 Pin Code라는 개념으로, 유저에게 HTML 화면으로 노출시키고, 그것을 입력하도록 하고 있습니다. 
    "휴대폰 인증번호" 쯤으로 생각하면 될듯합니다. 

    사용자에게 입력하게 한다. 사용자는 이미 아이디와 비밀번호를 입력했는 데 또 입력하게 해야 한다니, 
    별로 좋지 않군요. 

    오늘의 목표는 저 Pin Code값을 자동으로 가져오는 것입니다 ! 

    그래서 HTML 을 Parsing해서 가져와보자고 생각을 했습니다. 

    Pin 값이 <div id="oauth_pin"> 으로 되어 있어서, HTML DOM Element Parsing으로 가져 올수 있을꺼 같다는 생각을 했습니다.

    그러나..

    Android WebView에 HTML 을 가져 오는게 존재 하지 않습니다 ;ㅂ;

    그래서 WebView에 Javascript 를 집어 넣어서, Java Code를 호출 하여, dom의 값을 넣기로 했습니다. 


    class MyJavaScriptInterface  

    {  

        public void showHTML(String pin) throws TwitterException  

        {  

        if(pin.length() > 0 ) {

        Log.i("Javascript Interface","pin = " + pin);

        AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, pin);

        Log.i("Javascript Interface", "AccessToken = " + accessToken);

        }

        else {

        Log.i("Javascript Interface","get pin failed...");

        }

        }  

    }  

     webview.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");


    이런식으로 Java Code와 연결된, Javascript Interface를 WebView에 삽입 할수 있습니다. 

    view.loadUrl("javascript:window.HTMLOUT.showHTML(document.getElementById('oauth_pin').innerHTML);");  

    view.loadUrl("javascript:window.HTMLOUT.showHTML(document.getElementsByTagName('code')[0].innerHTML);");

    WebViewClient의 onPageFinisehd() Method를 Override하여, 삽입한 Javascript를 실행해주면
    Page가 로딩 될때마다, 호출되고,oauth_pin 값을 얻는 순간이 인증이 끝난 순간이됩니다. 

    그것을 통해서 AccessToken을 가져오면 Twitter OAuth 인증은 끝난 셈이죠. 

    Java Code내에서 끝나지 않고, Javascript 를 통한다는게 좀 마음에 안드는 방식이긴 합니다. 
    더 좋은 방법을 알게 되면 후딱 후딱 넘어가야죠. 어쨌든 잘 동작합니다. 


    Android File I/O를 살펴본 이유는 POJO 를 저장하기 위해서다. 

    사실 SharedPreference를 통해서 POJO를 저장할 수 있길 기대 했지만, SharedPreference는 Java Object를 저장할 수 없게 되어 있다.

    그래서 결국 POJO를 Serialize 해서, File로 떨구기로 결정했기에, Android File I/O에 대해서 살펴 보기로 하였다. 

    Android에서 File I/O의 Target Directory는 두가지일수 있다. 
    하나는 Internal Storage이고, 다른 하나는 External Stroage(SD Card)이다. 
    POJO를 저장하는 건 보통 매우 작은 단위의 Data이기 때문에, Internal Storage로 결정했다.

    File I/O 역시, Context Class를 통해서 해결한다. 
    Context Class를 살펴 보면 openFileInput/openFileOutput이 있다. 

    abstract FileInputStream openFileInput(String name)
    Open a private file associated with this Context's application package for reading.
    abstract FileOutputStream openFileOutput(String name, int mode)
    Open a private file associated with this Context's application package for writing.

    보통 Java Application 에서 FileInputStream을 직접 사용하는것과 다리 
    Context의 openFileInput Method를 통해서 internal Storage에서 해당 App의 SandBox Directory로 부터 File Stream을 열수 있다. 

    그외에 FileXXXXStream을 사용하는 방법은 일반 Java Programming과 동일 함으로 생략.

    여기서 한가지 더 필요 했던게, 만든 파일을 어떻게 지울것인가 이다. 

    지우는 Method도 Context Class에 있다. 

    abstract boolean deleteFile(String name)
    Delete the given private file associated with this Context's application package.
    뭐 역시나 별로 어려운건 없다 ㅎ

    Android는 Context단위로, 만위 움직이기때문에, API 사용시에 Context를 사용할 일이 많다. 
    그래서 JUnit에서 Context의 접근은 꼭 필요 한일이다. 

    결론부터 말하면 org.junit.TestCase대신에 android.test.AndroidTestCase 를 사용하라는 것이다. 


    위에서 보는 바와 같이 AndroidTestCase에서는 이미 Mock Context Object를 제공하고 있음으로,
    AndroidTestCase 를 상속받아서, TestCase Class를 정의하고, 
    내부적으로 getContext() Method를 이용해서 바로 쓰면 된다. 


    Android에서, 화면은 Activity단위로 움직인다.

    특정 Context에서 또다른 Activity를 실행시키고, 현재의 Activity를 종료 시키는 방법에 대해서 알아 보려고 한다. 

    Context Class를 찾아 보면 startActivity라는 녀석이 있다. Context Class에 정의 되어 있기 때문에, Context의 SubClass인, Activity는 물론 Service Object에서도 특정 Activity를 실행 시킬 수 있다. 

    public abstract void startActivity (Intent intent)

    Since: API Level 1

    Launch a new activity. You will not receive any information about when the activity exits.

    Note that if this method is being called from outside of an Activity Context, then the Intent must include the FLAG_ACTIVITY_NEW_TASK launch flag. This is because, without being started from an existing Activity, there is no existing task in which to place the new activity and thus it needs to be placed in its own separate task.

    This method throws ActivityNotFoundException if there was no Activity found to run the given Intent.

    Parameters
    intentThe description of the activity to start.
    Throws
    ActivityNotFoundException

    startActivity()를 통해서, activity를 실행시키게 되면, 현재의 Activity 는 Pause상태에 접어 들게 된다. 

    특정 Activity()를 종료 시키기 위해서는 Activity Class내의 finishXXX() Method들을 사용하면 된다. 
    가장 기초적인것만 살펴보면, finish()가 있다. 

    public void finish ()

    Since: API Level 1

    Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via onActivityResult().


    finish() 가 호출되면, 현재 Activity가 Destroy 상태가 되며, (OnDestroy() 호출됨 )  이전 Activity 가 다시 Active상태가 된다 ( onResume() 호출됨 )

    이런식으로 대강 Activity의 흐름이 흘러간다. 

    나중에 finishActivity(Intent, int ) 와 같은 함수들이 쓸일이 생기면 그때 걔네들을 좀 살펴봐야 겠다.



    일단 Strings 에 정의된 String값들도, layout등과 같이 각자의 식별자를 가진다. 

    <?xml version="1.0" encoding="utf-8"?>

    <resources>

        <string name="hello">Hello World</string>

    </resources>


    위와 같이 정의된 string파일이 있다면, "Hello World"라는 String은 "R.string.hello" 에 id가 정의된다. 

    Java Source Code에서 string자원을 접근할때는,  Context Class의 getString() Method를 사용한다. 
     

    위에서 보는 바와 같이 각종 Activity/Service등이 모두 Context의 SubClass임으로, 
    Activity나 Service를 구현할때는 바로 getString을 사용할 수 있다.

    아래 코드는 "R.string.hello"을 사용하는 예제 코드 이다 .

    someTextView.setText(getString(R.string.hello));




    <EditText android:layout_height="wrap_content" 

    android:id="@+id/TimeEditText" android:layout_weight="1" android:layout_width="fill_parent"

    android:inputType="number"

    >

    </EditText>


    android:inputType으로 입력받을 수 있는 값을 강제 할수 있다. 생각보다 쉽죠? ㅎ
    그러나,  맘에 안드는게 있는데, AVD에서 보면

    우외 같이 키보드가 다 나온다는 얘기다. 
    터치를 누를수는 있는데, 값은 입력이 안된다. 

    그럼 이렇게 숫자만 있는 것을 어떻게 사용할까? 이건 뭐 Java 기초 ㅎ

    Integer.parseInt(String .. ) 를 이용한다. 

    EditText editText = (EditText) mAlertLayout.findViewById(R.id.TimeEditText);

    mins = Integer.parseInt("" + editText.getText());


    editText의 값이 null 일것을 대비해서 "" + 를 붙혀서 넣는걸 잊지 말자. 


    string.xml 에서 '(apostrophe)를 사용하면 에러가 발생한다.

    언제나 그렇듯, 에러 문구를 잘 보면 답이 있는데, 
    답은 바로 apostrophe를 사용하기 전에 '\' 를 써줘야 한다는것이다.

    위의 스크린 샷 처럼 '\'를 앞에 추가 해주면 에러가 말끔히 사라진다.
    아마도 몇몇 특수 문자들은 '\'를 추가 해주어야 하는것 같다.

    + Recent posts