LayoutInflater 객체를 얻는 3가지 방법

 

LayoutInflater는 레이아웃 XML 파일로부터(XML로 작성된 layout 파일로부터) 

그에 해당하는 View 객체를 획득하는데 유용하게 사용되는 클래스이다.

현재의 레이아웃 view에(setContentView()로 얻은 view에) 

동적으로 특정 layout XML 파일의 내용을 view에 추가하고 싶을 때 유용하게 사용이 된다.


다음과 같이 3가지 방식으로 객체를 얻을수 있다.


  • LayoutInflater inflater = 
                    (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);

  • LayoutInflater inflater = Activity.getLayoutInflater();

  • LayoutInflater inflater = LayoutInflater.from(Context context);


내가 작성한 TextView를 AlertDialog에 채용해서 내가 원하는 형태로 AlertDialog를 보여주고자 할 경우 

아래와 같이 LayoutInflater를 이용하면 된다.


alert_text.xml의 내용이 다음과 같을 경우 


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

<TextView xmlns:android="http://schemas.android.com/apk/res/android"

    android:id="@+id/spnTxt"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:padding="15dp"

    android:textColor="#FF99FF"

    android:textSize="20sp"

    />


이 레이아웃(alert_text.xml)을 AlertDialog의 view로 사용 할려면 LayoutInflater를 이용해서 다음과 같이 하면 된다.


LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);


TextView spnTxt = (TextView)inflater.inflate(R.layout.alert_text, null);

spnTxt.setText("필요한 문자열...");


AlertDialog.Builder adb = new AlertDialog.Builder(this);

adb.setView(spnTxt);

adb.setPositiveButton("확인", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialog, int which) {

//원하는 기능

}

)};


adb.show();





안드로이드 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을 사용하는 방식도 있겠다.





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


Ctrl-Shift-O

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


Alt-Shift-O

⇒ 특정 변수가 사용된 위치를 손쉽게 파악하게 하는 토글 기능

특정 변수가 사용된 위치를 찾기 위해서 Ctrl-F로 검색할 변수명을 입력해서 찾을수도 있으나

이클립스는 해당 변수를 마우스롤 클릭하면 해당 변수가 사용된 위치를 아래 그림과 같이 표시해 준다.

그런데 이게 정상적으로 작동이 안될 때가 있다. 

이때 Alt-Shift-O를 누르면 정상적으로 작동이 된다.

아래 그림에서 화면 우측 하단의 작은 회색 사각형이 해당 변수가 사용된 위치이다.







안드로이드에서 외부 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에서도 사용이 가능하다.




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

교체하는 코드는 다음과 같다.


FragmentManager fragmentManager =
                                       getFragmentManager();
FragmentTransaction fragTransaction = 

                          fragManager.beginTransaction();
MyFragment mFrag = new MyFragment();

fragTransaction.add(R.id.layout, mFrag);

//아래 코드 실행되는 시점에 

//MyFragment가 비로소 실행된다.

fragTransaction.commit(); 



☞ 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();




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를 반환(제공)해 주는 역할을 한다.





 

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();


+ Recent posts