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 글꼴

Georgia  : T

Times New Roman  : T



SANS-SERIF 글꼴

Arial  : T

Verdana : T



MONOSPACE 글꼴

Courier New : T 


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)이 각각 상이하다.





 

1) RectF의 생성자


public RectF (float left, float top, float right, float bottom)

⇒ Create a new rectangle with the specified coordinates.
Note: no range checking is performed, so the caller must ensure that left <= right and top <= bottom.

주어진 좌표 값을 이용해서 새로운 사각형을 만드는 클래스이다. 주의할 점은 left 값이 right 값보다 작아야 되는데 이러한 값의 범위가 올바른지는 체크해야 한다는 이야기가 있고요.


Parameters

left : The X coordinate of the left side of the rectangle

top : The Y coordinate of the top of the rectangle

right : The X coordinate of the right side of the rectangle

bottom : The Y coordinate of the bottom of the rectangle


⇒ 사각형 그리는 클래스


2) Path의 메소드

public void arcTo (RectF oval, float startAngle, float sweepAngle)

⇒ Append the specified arc to the path as a new contour. If the start of the path is different from the path's current last point, then an automatic lineTo() is added to connect the current contour to the start of the arc. However, if the path is empty, then we call moveTo() with the first point of the arc.

원호를 그릴 경로(path)를 미리 지정해 놓는 메소드이다. 


Parameters

oval : The bounds of oval defining shape and size of the arc

       : 원호를 그릴 영역, 원호의 크기를 결정하는 경계선 역할

startAngle : Starting angle (in degrees) where the arc begins

                : 원호가 시작되는 지점. 각도로 표시

sweepAngle : Sweep angle (in degrees) measured clockwise

                  : 시계방향으로 원호를 그리는 각도 지정


⇒ 그림을 그릴 경로를 미리 지정. Canvas 클래스의 drawPath()를 이용해서 Path로 지정된 경로를 따라 그리기를 한다.


3) Canvas의 메소드 

public void drawPath (Path path, Paint paint)

⇒ Draw the specified path using the specified paint. The path will be filled or framed based on the Style in the paint. 앞에서 설정된 경로(path)대로 그림을 실제 그리는 역할


Parameters

path : The path to be drawn

paint : The paint used to draw the path



예제)

RectF rf = new RectF();


//좌에서 우로 50만큼 이동된 x축 위치와 위에서 아래쪽으로           

//50만큼 이동된 y축 위치와 좌에서 우로 100만큼 이동된 

//x축 위치와 위에서 아래쪽으로 100만큼 이동된 y축 위치를 잇는 

//사각형. 이 영역이 그림이 그려질 영역이다.

rf.set(50, 50, 100, 100);                      


Path path = new Path();


//그림을 그릴 path를 지정해 두고 나중에 drawPath()로 이 

//path를 따라 원호를 그린다.

//원호의 크기는 두 번째, 세 번째 인자가 지정하는 크기만큼 그린다.

//rf는 그림을 그릴 영역이고, 0은 그림을 시작할 위치인데 각도로 

//표시한다. 시계로 3시 지점이 0도이고

//6시 지점이 90도이고 9시 지점이 180도이고 12시 지점이 270도

//이다. 방향은 시계 방향으로 돌아가는 방식으로 각도를 지정한다.

path.arcTo(rf, 0, 180); 

                                 

public void onDraw(Canvas canvas) 

{

   Paint paint = new Paint();

   paint.setFlags(Paint.ANTI_ALIAS_FALG); 

   paint.setStrokeWidth(2); //선의 굵기를 2로 지정


   RectF rf = new RectF();

   rf.set(50, 50, 100, 100);


   Path path = new Path();


   //3시 지점에서 시작해서 시계 방향으로 9시 지점까지 

   //원호를 그린다.

   path.arcTo(rf, 0, 180); 

                                     

   canvas.drawPath(path, paint);

}





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에 방송 수신에 대한 정보를 기록해 두어야 한다.





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

안드로이드 버전 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);

    }





HttpURLConnection에 대한 개괄적 개념


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

이때 연결 상태를 알수 있는 메소드는


getResponseCode()와 getResponseMessage()이다.


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


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

HttpURLConnection con = null;

con = (HttpURLConnection)url.openConnection();



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 창)에서


예를들어서 내 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에 매칭될때 이를 관리하는

클래스이다.




현재 시간을 24시간제로 표시하고자 한다면 android.text.format.DateFormat라는 클래스를 이요하면 된다.

이 클래스가 제공하는 메소드 중에서 다음 메소드가 이 기능을 제공한다.


public static CharSequence format (CharSequence inFormat, long  inTimeInMillis)


첫 번째 매개인자 inFormat에 사용되는 형식은 아래 표의 규칙대로 하면된다

(http://developer.android.com/reference/java/text/SimpleDateFormat.html 참조)


SymbolMeaningKindExample
Dday in year(Number)189
Eday of week(Text)E/EE/EEE:Tue, EEEE:Tuesday, EEEEE:T
Fday of week in month(Number)(2nd Wed in July)
Gera designator(Text)AD
Hhour in day (0-23)(Number)0
Khour in am/pm (0-11)(Number)0
Lstand-alone month(Text)L:1 LL:01 LLL:Jan LLLL:January LLLLL:J
Mmonth in year(Text)M:1 MM:01 MMM:Jan MMMM:January MMMMM:J
Sfractional seconds(Number)978
Wweek in month(Number)2
Ztime zone (RFC 822)(Time Zone)Z/ZZ/ZZZ:-0800 ZZZZ:GMT-08:00 ZZZZZ:-08:00
aam/pm marker(Text)PM
cstand-alone day of week(Text)c/cc/ccc:Tue, cccc:Tuesday, ccccc:T
dday in month(Number)10
hhour in am/pm (1-12)(Number)12
khour in day (1-24)(Number)24
mminute in hour(Number)30
ssecond in minute(Number)55
wweek in year(Number)27
yyear(Number)yy:10 y/yyy/yyyy:2010
ztime zone(Time Zone)z/zz/zzz:PST zzzz:Pacific Standard Time
'escape for text(Delimiter)'Date=':Date=
''single quote(Literal)'o''clock':o'clock

예를들면


MM : 11, 10과 같이 월 표시를 두 자리 숫자로 표현

MMM : Nov, Oct...와 같이 월 표시를 영문 약어로. 

          한글 폰에서는 그냥 '월'이라는 글자로 표시


MMMM : November, October...와 같이 월 표시를 영문 full name으로 표시


yyyy-MM-dd h:mm => 2013-11-25 3:25


yyyy-MM-dd h:mm a => 2013-11-25 3:25 pm


yyyy-MM-dd k:mm => 2013-11-25 15:25 (24시간제로 표시)



예제 소스는...


String crrTime = System.currentTimeMillis().toString();

String now = DateFormat.format("yyyy MMM dd k:mm", crrTime);

        

TextView txt = (TextView)findViewById(R.id.txt);

txt.setText(now);


여기서 DateFormat은 자바의 DateFormat(

java.text.DateFormat)이 아니라 안드로이드의 DateFormat이다. 

클래스 이름이 동일한 DateFormat은 자바에도 있고 안드로이드에도 있다.


android.text.format.DateFormat;




+ Recent posts