2015년 10월 29일 목요일

안드로이드 xml에 마크업 문자 넣기(글꼴 속성: 굵기, 이탤릭...)





안드로이드 xml에 마크업 문자 넣기(글꼴 속성: 굵기, 이탤릭...)

안드로이드는 HTML처럼 XML 문자열에서 기본적인 마크업 문자를 사용하여 스팬 문자를 만들수 있는 기능을 아래와 같이 제공한다.


  •  <b>굵게 강조</b>
  •  <i>이탤리체</i>
  •  <tt>프로그램용 MonoSpace 폰트</tt>
  •  <sup>윗첨자</sup>
  •  <sub>아래첨자</sub>
  •  <u>아래밑줄</u>
  •  <strike>취소선</strike>


<TextView 
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:gravity="center_horizontal"
   android:text="@string/styled_text"/>

strings.xml의 내용

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, AAAActivity!</string>
    <string name="styled_text">평범(plain), \n<b>굵게(bold)</b>, \n<i>이탤릭체(italic)
                         </i>, \n<b><i>여긴 굵게 이탤릭체</i></b>
    </string>

    <string name="app_name">안드로이드 리소스 샘플 프로첵트</string>
</resources>

Map과 List에 대한 간단한 이해





Map과 List에 대한 간단한 이해

List는 원소들을 가지고 있는 데이터 집합이다. 순차 자료구조로 순차적으로 메모리에 저장되는 형태이다. 쉽게 배열로 바꾸어서 생각해도 된다. 
따라서 List의 원소에 접근할 때는 index(첨자)로 접근한다.

List는 Generic이라는 옵션이 존재하는데 Generic 옵션이 설정된 List는 Generic에 해당되는 데이터 형만을 담을 수 있다.

List<Integer> myList = new ArrayList<Integer>();

위와 같이 선언된 List는 Generic 옵션으로 Integer 형을 받았다.
myList에 add할 수 있는 자료들은 Integer형의 데이터만 담을 수 있게 된다.

myList.add("data")와 같이 문자열을 넣으려 한다면 에러가 발생하게 된다.

myList.get(i)과 myList.remove(i) 메소드를 사용해서 myList 안에 있는 원소들을 인텍스로 접근, 삭제 등을 할수 있다.

Map은 List와 같은 원소들을 모아 놓은 집합이다.
List와는 달리 index(첨자)로 접근하는 것이 아니라 key로써 데이터를 제어할수 있다.
Map 또한 Generic 옵션을 설정할 수 있다.

Map<String, Object> myMap = new HashMap<String, Object>();
와 같이 Generic을 key와 data형으로 지정한다.

myMap.put("elementA", "Data_1");
과 같은 형태로 String의 key로 myMap에 저장된 Object 데이타를 제어할 수 있게 되며 Generic 형식에 따라야 한다.

put으로 저장된 데이터는 put할 때 지정했던 key로 접근이 가능하며
myMap.get("elementA")을 호출하면 저장된 "Data_1"이 반환된다.
myMap.remove("elementA")을 호출하면 해당하는 key를 가진 원소가 삭제된다.

eclipse(이클립스)에서 코드 힌트 표시되게 설정 하는 법(Template Proposal 기능)





eclipse(이클립스)에서 코드 힌트 표시되게 설정 하는 법(Template Proposal 기능)

이클립스로 코딩을 하다 보면 아래 그림과 같이 현재 변수(혹은 객체)에서 사용 가능한 메소드들 등을 보여주는 코드 힌트 기능이 매우 요긴하게 쓰인다.



보통은 자동으로 표시가 되나 필요시 특정 키를 누름으로 해당 기능을 작동하게 할 필요가 있다. 이에 대한 설정법이다.

Window - Pereferences - General - Keys 에서 필터 부분에 assist를 입력하면 해당 Command 목록이 필터링이 된다. 

그 중에서
Content Assist에 대해 Binding의 값을 F6 등과 같이 자신이 원하는 키로 설정하면 된다.



만일 위와 같이 설정해도 안되면 아래 사항을 확인해서 항목을 모두 체크 표시해 주면 된다.

Window - Pereferences - Java - Editor - Content Assist - Advanced에서
항목들을 모두 체크해 주면 된다. 아랫쪽 것도 마찬가지로


eclipse(이클립스)의 개발 환경을 utf-8로 설정하기





eclipse(이클립스)의 개발 환경을 utf-8로 설정하기

이클립스의 기본 인코딩이 euc-kr로 되어 있다. 인코딩 설정을 utf-8로 바꾸는 법.

Windows - Preferences - General - Workspace - Text file encoding에 대해 utf-8로 설정




⊙ 특정 프로젝트만 인코딩을 utf-8로 설정하는 법

먼저 프로젝트를 선택 - 우측 버튼 클릭 - Properties 선택 - Resources 선택 - Text file encoding을 원하는 인코딩으로 설정





2015년 10월 28일 수요일

안드로이드 6.0에서 Apache의 HttpClient가 import안되는 문제 해결





안드로이드 6.0에서 Apche의 HttpClient가 import안되는 문제 해결

안드로이드가 6.0으로 업데이트 되면서 기존에 안드로이드와 서버와의 통신, 데이터 송, 수신에
사용되던 Apache의 HttpClient를 구글이 원천적으로 사용을 못하게 해 놨다. ;;;

아래 클래스들이 서버로의 송, 수신시 필요로 하는 것들인데 원천적으로 import가 안된다.
org.apache.http.HttpEntity;
org.apache.http.HttpResponse;
org.apache.http.client.ClientProtocolException;
org.apache.http.client.HttpClient;
org.apache.http.client.methods.HttpPost;
org.apache.http.entity.StringEntity;
org.apache.http.impl.client.DefaultHttpClient;
org.apache.http.util.EntityUtils;

https://developer.android.com/intl/ko/about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client

따라서 HttpClient를 사용해야할 상황에서는 좀 난감해 진다.
구글 API Reference상에서 설명조차 제공이 안된다.
안드로이드 스튜디오를 사용하는 경우라면 해당 해법들이 검색하면 제법 나오는데
이클립스 상황에서는 땀난다...

해법은 다음 3개의 jar 파일을 libs폴더에 복사해 두면 이제부터 Ctrl-Shift-O로 정상적으로 import가 된다.

httpclient-4.4.1.jar
commons-logging-1.2.jar
httpcore-4.4.1.jar

혹은 구글 API Reference 문서에서 추천하는 방식인 HttpURLConnection을 사용하는 방식도 있겠다.

이클립스(Eclipse)의 몇 가지 유용한 단축키





이클립스의 몇 가지 유용한 단축키

Ctrl-Shift-O
⇒ 이클립스에서 클래스 자동으로 import 시키기

Alt-Shift-O
⇒ 특정 변수가 사용된 위치를 손쉽게 파악하게 하는 토글 기능
특정 변수가 사용된 위치를 찾기 위해서 Ctrl-F로 검색할 변수명을 입력해서 찾을수도 있으나
이클립스는 해당 변수를 마우스롤 클릭하면 해당 변수가 사용된 위치를 아래 그림과 같이 표시해 준다.
그런데 이게 정상적으로 작동이 안될 때가 있다.
이때 Alt-Shift-O를 누르면 정상적으로 작동이 된다.
아래 그림에서 화면 우측 하단의 작은 회색 사각형이 해당 변수가 사용된 위치이다.





2015년 10월 27일 화요일

자바 제네릭스(Generics)에 대해서 - T[], List<T> 등의 의미





자바 제네릭스(Generics)에 대해서 - T[], List<T> 등의 의미

ArrayAdapter의 두 생성자를 보면 다음과 같이 되어있다.
그런데 세 번째 매개 인자의 데이터 타입이 T[] objects로 되어 있다.

ArrayAdapter(Context context, int textViewResourceId, T[] objects)
⇒ T[] objects가 의미하는 것은 어떤 배열이 여기에 올 수 있다는 뜻이다.
T[]가 의미하는 것은 배열은 배열인데 data type은 어떤 data type도 가능하다는 뜻이다.

ArrayAdapter(Context context, int textViewResourceId, List<T> objects)
⇒ List<T> objects가 의미하는 것은 이 매개 인자의 자리에 List라는 interface의 객체가 올수 있다는 뜻이다. 
List<T>이므로 List가 담는 내용물의 data type은 T타입이므로 사용자가 정의하는 data type 뭐든지 올 수 있다. 

그런데 List라는 interface를 보면 List를 implements한(상속받은) 하위 클래스들이 있는데 이들 중 어느 하나가 올수 있다는 뜻이다. 
대표적으로 ArrayList<E>가 올 수 있다는 뜻이다.

public interface List implements Collection<E>
java.util.List<E>

Known Indirect Subclasses
AbstractList<E>, AbstractSequentialList<E>, ArrayList<E>, CopyOnWriteArrayList<E>,
LinkedList<E>, ObservableArrayList<T>,ObservableList<T>, Stack<E>, Vector<E>

2015년 10월 26일 월요일

안드로이드에서 외부 글꼴(font) 적용하기





안드로이드에서 외부 Font를 사용할려면 assets/fonts라는 폴더를 만들어서 여기에 글꼴을 복사해 놓아야 가능하다.
TextView 3개를 만들어 여기에 각각 다른 글꼴을 적용할려면 Typeface(android.graphics.Typeface) 클래스를 이용하면 간단히 구현된다.

Typeface 클래스의 객체를 구하는 방식은 아래의 static 메소드들 중 하나의 방식으로 처리된다.

static Typefacecreate(String familyName, int style)
Create a typeface object given a family name, and option style information.
static Typefacecreate(Typeface family, int style)
Create a typeface object that best matches the specified existing typeface and the specified Style.
static TypefacecreateFromAsset(AssetManager mgr, String path)
Create a new typeface from the specified font data.
static TypefacecreateFromFile(String path)
Create a new typeface from the specified font file.
static TypefacecreateFromFile(File path)
Create a new typeface from the specified font file.
static TypefacedefaultFromStyle(int style)
Returns one of the default typeface objects, based on the specified style

        TextView txt = (TextView)findViewById(R.id.myFont);
        Typeface face = Typeface.createFromAsset(getAssets(), "fonts/arial.ttf");
        txt.setTypeface(face);
        
        TextView txt2 = (TextView)findViewById(R.id.myFont2);
        Typeface face2 = Typeface.createFromAsset(getAssets(), "fonts/FORTE.TTF");
        txt2.setTypeface(face2);
        
        TextView txt3 = (TextView)findViewById(R.id.fontKOR);
        Typeface face3 = Typeface.createFromAsset(getAssets(), "fonts/HYPORM.TTF");
        txt3.setTypeface(face3);
        
Typeface를 이용한 글꼴 적용은 View의 paint에서도 사용이 가능하다.






HTML 링크를 새 창에서 열도록 하는 법





HTML에 있는 링크(<a> 태그의 링크)를 새로운 창에서 여는 법

링크를 클릭했을 때 브라우저의 현재 창에서 링크가 열리지 않고 
새로운 창에서 열리도록 해야 할 때가 있다.

새로운 창에서 열기 위해서는 <a> 태그의 target 속성을 이용하면 된다.
이때 target속성의 값(value)은 반드시 _blank이어야 한다.

새 창에서 열도록 할 때의 잇점은 방문자로 하여금 자신의 사이트에 머물도록 하는 방편이 될 것이다.
아래는 코드 조각이다.

<a href="http://developer-joe.tistory.com">티스토리에 개설한 블로그</a> (현재 창에서 열기)
<p>
<a href="http://developer-joe.tistory.com" target="_blank">티스토리에 개설한 블로그</a> (새 창에서 열기)

2015년 10월 21일 수요일

FragmentTransaction의 replace() 메소드를 통해 동적으로 Fragment 교체하기





FragmentTransaction의 replace() 메소드를 통해 동적으로 Fragment 교체하기
교체하는 코드는 다음과 같다.

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragTransaction = fragManager.beginTransaction();
MyFragment mFrag = new MyFragment();
fragTransaction.add(R.id.layout, mFrag);
fragTransaction.commit(); //이 코드 실행되는 시점에 MyFragment가 비로소 실행된다.


☞ FragmentManager
⇒ Activity안에 있는 Fragment와 상호 작용 및 관리(Activity에 추가, 교체...)를 위한 클래스
이 클래스의 객체는 Activity의 메소드 중 getFragmentManager()를 통해 얻을 수 있다.

☞ fragTransaction.add(R.id.layout, mFrag);
⇒ 새로운 Fragment인 mFrag를 R.id.layout이라는 곳에 추가하는 기능.
R.id.layout이 들어있는 xml파일이 다음과 같다면

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/layout"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="확 인"
        android:onClick="mClick"
        />
</LinearLayout>


fragTransaction.add(R.id.layout, mFrag)과 유사한 것이 replace() 메소드이다.
아래 코드는 R.id.content_frame에 있는 기존의 Fragment를 제거한 후 
두 번째 매개인자인 fragment를 R.id.content_frame에 집어 넣는 기능이다.

fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

2015년 10월 20일 화요일

이클립스(ECLIPSE)의 SHOW VIEW의 항목들이 보이지 않을 때 해법





이클립스(eclipse)의 Show View의 항목들이 보이지 않을 때

이클립스의 Window - Show View - No Applicable View만 보이고
Show View의 여러 하위 항목들이 보이지 않을 때 해결하는 방법이다.

Window - Open Perspective - Java를 클릭하면 해결된다.

FRAGMENT 사용을 위한 개념 정리





Fragment를 사용하기 위해서 개념을 정리해 보았다.

Fragment를 사용하는 건 사용자에겐 편리할지 모르나 개발자에겐 좀 복잡한 작업이다. 
특히 Fragment와 ViewPager와 ActionBar와 
DrawerLayout이 함께 엮이어 돌아갈 경우는 더더욱 머리가 복잡해 진다. 따라서 전체적인 개념이 정리가 필요하다. 
본 포스트는 Fragment를 기본적으로 사용해 본 경험이 있는 분들이라야 의미가 있으리라고 생각된다.
아래는 Fragment의 동작 메커니즘을 정리해 본 내용이다.

-. Activity가 Fragment를 담기 위해서는 일반 Activity로는 안되고
   android.support.v4.app.FragmentActivity를 extends해야한다.
   public class ExViewPagerActivity extends FragmentActivity { ... }

-. 여기서 Fragment간의 이동을 부드럽게 되도록 해 주는 용도로 ViewPager를 채용하면
   된다.  즉 FragmentActivity에 ViewPager를 담으면 된다.
   ViewPager는 Layout manager that allows the user to flip left and right through
   pages of data의 역할을 한다.

-. ViewPager에 담을 데이터와 ViewPager에 보여줄 View를 생성하기 위해서는 adapter
   클래스가 있어야 한다.  마치 ListView에 표시할 데이터와 표현하는 방식(View)를 제공하는
   역할의 adapter를 필요로 하는 것과 같다. 

-. ViewPager가 사용할 adapter 클래스는 두 가지 종류가 있는데
    FragmentPagerAdapter와 
    FragmentStatePagerAdapter가 있다.

-. FragmentPagerAdapter는 표시할 page의 수가 고정되어 있고 몇개 되지 않을 때
   사용하는 용도이고(이 adapter를 사용하면 모든 page를 메모리에 다 로드해 두고서
   page 이동을 하는 방식이다)

-. FragmentStatePagerAdapter는 표시할 page의 수가 고정되어 있지않고 또 많을
   경우에 사용하는 adapter이다. 이 경우의 page 이동은 매번 현재 page를 destroy한 후
   새 page를 생성하는 식이다. 

-. 이 두 adapter 클래스를 상속받은 클래스는 
   public int getCount()과 
   public Fragment getItem(int position)를 필요에 맞게 재정의해서 사용하면된다.

-. ViewPager를 setAdapter() 할때 getCount()와 getItem()이 차례로 호출된다.
   public void setAdapter (PagerAdapter adapter)

-. getCount()는 page의 갯수가 몇 개인지를 알려주는 기능이고 getItem()은 adapter에게
   ViewPager에 공급할 Fragment를 반환(제공)해 주는 역할을 한다.

SERIF, SANS-SERIF, MONOSPACE의 차이점






Serif란 문자의 끝 부분에 장식되어 있는 부가적인 짧은 선을 Serif라고 한다. Geogia의 T와 Arial의 T에서 후자는 끝 부분에 부가 된 다른 선이 없다. 

Sans-Serif에서 sans는 without(...이 없는)의 의미이다. 따라서 serif가 '없는'(sans) 글꼴을 말한다. Arial과 Verdana의 경우와 같다. 반면에 Geogia나 Times New Roman의 경우들은 글자의 끝 부분들에 추가적인 짧은 선들로 장식되어 있다. 이렇게 장식된 부분을 serif라고 한다. 따라서 Sans-Serif는 이러한 것이 없는 것을 말한다.

Monospace는 모든 글자들의 폭(width)이 같은 글꼴을 의미한다. non-monospace 글꼴들은 각 글자들마다의 폭(width)이 각각 상이하다.

2015년 10월 19일 월요일

PING을 통해서 네트워크 연결 상태 체크하기 - 안드로이드 소스 코드에서





ping을 통해서 네트워크 연결 상태 체크하기 - 안드로이드 소스 코드에서

Runtime runTime = Runtime.getRuntime();

String host = "192.168.0.13";
String cmd = "ping -c 1 -W 10 "+host; //-c 1은 반복 횟수를 1번만 날린다는 뜻
Process proc = null;

try {
proc = runTime.exec(cmd);
} catch(IOException ie){
Log.d("runtime.exec()", ie.getMessage());
}

try {
proc.waitFor();
} catch(InterruptedException ie){
Log.d("proc.waitFor", ie.getMessage());
}

//여기서 반환되는 ping 테스트의 결과 값은 0, 1, 2 중 하나이다.
// 0 : 성공, 1 : fail, 2 : error이다.
int result = proc.exitValue();

if (result == 0) {
Log.d("ping test 결과", "네트워크 연결 상태 양호");
} else {
Log.d("ping test 결과", "연결되어 있지 않습니다.");
}


※ ping 명령어 옵션들

-4, -6 Force IPv4 or IPv6 hostname resolution
-c CNT Send only CNT pings
-s SIZE Send SIZE data bytes in packets (default=56)
-I iface/IP Use interface or IP address as source
-W timeout Seconds to wait for the first response (default:10)
                 (after all -c CNT packets are sent)
-w deadline Seconds until ping exits (default:infinite)
                 (can exit earlier with -c CNT)
-q               Quiet, only displays output at start and when finished

안드로이드의 기반이 리눅스이기 때문에 DOS에서의 ping 명령어 옵션과는 약간의 차이가 있다.

-c 옵션은 ping을 날릴 횟수이다.
-W 옵션은 ping을 날린 이후 리턴 결과를 기다릴 timeout 시간 값이다. 연결 상태가 끊겼거나 연결 상태가 좋지 않을때 이 대기 시간 동안 응답이 없으면 연결 실패로 간주한다.

위의 옵션들은 대소문자를 구분한다.
따라서 ping -C xxx.xxx.x.x는 잘못된 사용법이다.

PING을 통해서 네트워크 연결 상태 체크하기 - 커맨더 창(DOS 창)에서





ping을 통해서 네트워크 연결 상태 체크하기 - 커맨더 창(DOS 창)에서

예를들어서 내 PC에서 폰의 연결 네트워크 상태를 체크할려면 우선 내 폰의 IP를 알아야 한다.
폰의 IP가 192.168.0.12이라고 할 경우

D:\>ping -n 5 192.168.0.12

여기서 -n은 ping을 날릴 횟수를 의미한다. 여기서는 5회.
아래 그림과 같은 결과를 보이면 정상적으로 연결된 상태이다.



만일 DDNS가 살아있는지 연결 상태를 체크하고자 한다면
(DDNS가 mycom.iptime.org라고 한다면)

D:\>ping mycom.iptime.org
를 하면 위의 이미지와 같은 결과를 보이면 네트워크가 정상적으로 연결된 상태이다.

안드로이드 앱에서 구글, 네이버, 다음 검색 기능을 이용하여 웹 검색하기





안드로이드 앱에서 구글, 네이버, 다음의 검색 기능을 이용한 웹 검색하는 기능은 Intent를 이용해서 구현할 수 있다.

Intent의 action 가운데 Intent.ACTION_WEB_SEARCH가 이 기능을 안드로이드 시스템에 요청하는 action이다.
이 action을 Intent에 담아서 startActivity로 날리면 안드로이드 시스템은 웹 search를 위한 동작을 수행하게 된다.
기본적으로는 구글 검색을 수행하지만 만일 디바이스(폰)에 네이버 앱이나, 다음 앱이 설치되어 있다면 이들 셋 중에서 선택하는 창이 뜨고 이 창에서 구글, 네이버, 다음의 검색 기능을 이용해서 특정 웹 검색을 수행할 수 있다.


이때 검색할 단어(내용)을 설정하는 것은 Intent의 extra에 담아서 수행하면 된다.
이때 putExtra에 사용할 key를 안드로이드 시스템에서 미리 설정해 두고 있다. 
그것이 SearchManager.QUERY라는 key값이다.
구글(네이버, 다음...)의 웹 검색 창에서 무엇을 검색할지를 안드로이드 시스템에게
알리는데 key 값이다.

Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, "검색할 단어");

if (intent.resolveActivity(getPackageManager()) != null) {
         startActivity(intent);
} else {
     String msg = "Sorry, there is no web browser available"; 
     Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}

Context 클래스의 메소드인 getPackgaeManager() 메소드는 다음과 같다.

public abstract PackageManager getPackageManager () 
⇒ Return PackageManager instance to find global package information.

디바이스에 있는 전 패키지 정보를 획득하기 위한 PackageManger 객체를 반환해 주는 메소드이다.

public ComponentName resolveActivity (PackageManager pm) : Intent 클래스의 메소드
⇒ Return the Activity component that should be used to handle this intent. 

resolveActivity() 메소드는 Intent를 수행할 Activity를 반환한다. 만일 수행할 Activity가 없으면 null을 반환한다.
이럴때 startActivity()를 수행하면 앱이 강제종료를 먹게된다.

그런데 아래 코드의 경우 웹 검색할 앱(Activity)가 구글, 네이버, 다음이 폰에 설치되어 있다면
아래 코드에서는 com.android.internal.app.ResolverActivity가 반환이 된다.
ResolverActivity는 안드로이드 API reference에서 search를 해도 보이지 않는다.
통상적인 클래스들은 API reference에서 search를 하면 자동완성 기능으로 제시가 되는데
ResolverActivity는 표시가 안된다. 
결론적으로 ResolverActivity는 여러개의 Activity가 Intent에 매칭될때 이를 관리하는
클래스이다.