'Mobile/Android'에 해당되는 글 22건

  1. 2012.11.09 Fragment를 이용한 TabActivity
  2. 2012.11.09 Fragment(1)
  3. 2012.11.08 생명주기 메소드를 Override할때 super의 위치
  4. 2012.11.06 IntentService
  5. 2012.11.06 weight값설정시 최적화
  6. 2012.11.02 한 앱에서 라이브러리와 값 공유
  7. 2012.11.02 BroadcastReceiver
  8. 2012.10.30 Push에 대한 것!
  9. 2012.09.24 TweenAnimation
  10. 2012.09.21 AsyncTask
posted by Kyleslab 2012. 11. 9. 17:57

MainActivity.java

package com.example.hellotabfragment;

import java.util.HashMap;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.View;
import android.widget.TabHost;

import com.example.hellotabfragment.fragment.Fragment1;
import com.example.hellotabfragment.fragment.Fragment2;
import com.example.hellotabfragment.fragment.Fragment3;

/**
 * This demonstrates how you can implement switching between the tabs of a
 * TabHost through fragments.  It uses a trick (see the code below) to allow
 * the tabs to switch between fragments instead of simple views.
 */
public class MainActivity extends FragmentActivity {
    TabHost mTabHost;
    TabManager mTabManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        mTabHost = (TabHost)findViewById(android.R.id.tabhost);//Container for a tabbed window view.
        mTabHost.setup();

        mTabManager = new TabManager(this, mTabHost, R.id.realtabcontent);// tab host와 탭을 눌렀을때 바뀌어야하는 부분의 id
        mTabManager.addTab(mTabHost.newTabSpec("simple").setIndicator("Simple"), Fragment1.class, null);	//새로운 탭을 만든다.
        //tabspec -> A tab has a tab indicator, content, and a tag that is used to keep track of it
        mTabManager.addTab(mTabHost.newTabSpec("contacts").setIndicator("Contacts"), Fragment2.class, null);
        mTabManager.addTab(mTabHost.newTabSpec("custom").setIndicator("Custom"), Fragment3.class, null);


        if (savedInstanceState != null) {
            mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));	// 방향 전환 전에 선택된 탭이 있다면 가져와서 설정
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString("tab", mTabHost.getCurrentTabTag());	// 방향 전환될때 넣어준다.
        Log.e("tab", mTabHost.getCurrentTabTag());
    }

    /**
     * This is a helper class that implements a generic mechanism for
     * associating fragments with the tabs in a tab host.  It relies on a
     * trick.  Normally a tab host has a simple API for supplying a View or
     * Intent that each tab will show.  This is not sufficient for switching
     * between fragments.  So instead we make the content part of the tab host
     * 0dp high (it is not shown) and the TabManager supplies its own dummy
     * view to show as the tab content.  It listens to changes in tabs, and takes
     * care of switch to the correct fragment shown in a separate content area
     * whenever the selected tab changes.
     */
    public static class TabManager implements TabHost.OnTabChangeListener {
        private final FragmentActivity mActivity;	//context
        private final TabHost mTabHost;
        private final int mContainerId;	
        private final HashMap mTabs = new HashMap();	// tag기준으로 tab에대한 정보가 들어있다.
        TabInfo mLastTab;

        static final class TabInfo {
            private final String tag;
            private final Class clss;
            private final Bundle args;
            private Fragment fragment;

            TabInfo(String _tag, Class _class, Bundle _args) {
                tag = _tag;
                clss = _class;
                args = _args;
            }
        }

        static class DummyTabFactory implements TabHost.TabContentFactory{ // Makes the content of a tab when it is selected. 
        	// 굳이 필요 없어 보이는 듯
            private final Context mContext;

            public DummyTabFactory(Context context) {
                mContext = context;
            }

            @Override
            public View createTabContent(String tag) {
                View v = new View(mContext);
                v.setMinimumWidth(0);
                v.setMinimumHeight(0);
                return v;
            }
        }

        public TabManager(FragmentActivity activity, TabHost tabHost, int containerId) {
            mActivity = activity;
            mTabHost = tabHost;
            mContainerId = containerId;
            mTabHost.setOnTabChangedListener(this);
        }

        public void addTab(TabHost.TabSpec tabSpec, Class clss, Bundle args) {	// tab추가하기
            tabSpec.setContent(new DummyTabFactory(mActivity));
            String tag = tabSpec.getTag();

            TabInfo info = new TabInfo(tag, clss, args);	// 그닥 필요없어 보이긴함

            // Check to see if we already have a fragment for this tab, probably
            // from a previously saved state.  If so, deactivate it, because our
            // initial state is that a tab isn't shown.
            info.fragment = mActivity.getSupportFragmentManager().findFragmentByTag(tag);	//tag로 프래그먼트 찾아서 넣어준다.
            if (info.fragment != null && !info.fragment.isDetached()) {	//frament가 null이아니고 떨어져있지 않으면 떼준다.
            	
                FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
                ft.detach(info.fragment);
                ft.commit();
            }

            mTabs.put(tag, info);	//자료형에 넣어준다. 이것도 불필요함
            mTabHost.addTab(tabSpec);	// 탭호스트에 실제로 탭을 넣어준다.
        }

        @Override
        public void onTabChanged(String tabId) {
            TabInfo newTab = mTabs.get(tabId);	// 넣어놨던 tabinfo찾아온다.
            if (mLastTab != newTab) {//라스트탭이 뉴탭과 같지 않다면
                FragmentTransaction ft = mActivity.getSupportFragmentManager().beginTransaction();
                if (mLastTab != null) {	//라스트탭이 널이 아니면
                    if (mLastTab.fragment != null) {	//라스트탭의 프래그먼트가 널이 아니면
                        ft.detach(mLastTab.fragment);	//떼어낸다
                    }
                }
                if (newTab != null) {	// 뉴탭이 널이 아니면
                    if (newTab.fragment == null) {	//프래그먼트가 널이면
                        newTab.fragment = Fragment.instantiate(mActivity,
                                newTab.clss.getName(), newTab.args);//새로 만들어준다
                        ft.add(mContainerId, newTab.fragment, newTab.tag);	//추가해준다
                    } else {
                        ft.attach(newTab.fragment);	//널이 아니면 그대로 붙여준다.
                    }
                }

                mLastTab = newTab;	//새로운탭이 라스트탭이 된다.
                ft.commit();
                mActivity.getSupportFragmentManager().executePendingTransactions();
            }
        }
    }
}
activity_main.xml


    

        

        

        
    





'Mobile > Android' 카테고리의 다른 글

fragment에서 attach, detach method!  (0) 2012.11.12
Fragment 에서 방향 전환시 null 체크  (0) 2012.11.09
Fragment(1)  (0) 2012.11.09
생명주기 메소드를 Override할때 super의 위치  (0) 2012.11.08
IntentService  (0) 2012.11.06
posted by Kyleslab 2012. 11. 9. 15:42

개인적인 생각으로 Fragment는 객체화시킬수 있는 서브 액티비티라는 생각이다. 

액티비티자체는 객체화 시킬수 없어 사용에 불편함이 있다. 

그러나 프래그먼트는 객체화가 가능하여 유연성있게 사용할 수 있다. 그리고 단독으로는 사용할 수 없다. 액티비티안에 사용할 수 있다.

액티비티 끼리는 인텐트를 주고받지만 프래그먼트는 argument로 값을 주고 받는다.

그런데 프래그먼트를 생성할때마다 Bundle을 만들어 아규먼트를 전달 받고 전달하는 것은 낭비라는 생각이 들어 메소드를 만든다.

static TextFragment newInstance(String _msg){
		TextFragment tf = new TextFragment();
		Bundle bundle = new Bundle();
		bundle.putString("msg", _msg);
		tf.setArguments(bundle);

		return tf;
	}

	public String getMsg(){
		if(getArguments().getString("msg")!=null){
			return getArguments().getString("msg");
		}
		return "msg";
	}


이런 식으로 메소드를 만들고 실제로 Fragment 객체를 생성할때는 new가 아닌

TextFragment tf = TextFragment.newInstance(((TextView)v).getText().toString());

이런 식으로 메소드를 호출하여 사용한다.

new로 생성하는 것외에 Fragment 에서 자체적으로 지원해주는 메소드도 있다. new로 생성하는 것과 차이는 없지만

인스턴스화가 실패했을 경우 에러 처리를 해준다.

public static Fragment instantiate (Context context, String fname, Bundle args)

Added in API level 11

Create a new instance of a Fragment with the given class name. This is the same as calling its empty constructor.

Parameters
contextThe calling context being used to instantiate the fragment. This is currently just used to get its ClassLoader.
fnameThe class name of the fragment to instantiate.
argsBundle of arguments to supply to the fragment, which it can retrieve with getArguments(). May be null.
Returns
  • Returns a new fragment instance.
Throws
InstantiationExceptionIf there is a failure in instantiating the given fragment class. This is a runtime exception; it is not normally expected to happen.



'Mobile > Android' 카테고리의 다른 글

Fragment 에서 방향 전환시 null 체크  (0) 2012.11.09
Fragment를 이용한 TabActivity  (0) 2012.11.09
생명주기 메소드를 Override할때 super의 위치  (0) 2012.11.08
IntentService  (0) 2012.11.06
weight값설정시 최적화  (0) 2012.11.06
posted by Kyleslab 2012. 11. 8. 10:26

전부터 궁금했던것 Override를 하였을때 부모의 원메소드를 호출할때 super를 사용한다.

그런데 super를 먼저 사용하기도 하고 나중에 사용하기도 한다. 

안드로이드 경우 보통 생명주기에 관한 메소드를 오버라이드 할때 자주 사용하는데 이때에 한해 언제 사용하는게 좋은지 궁금했다. 

안드로이드쪽으로 유명한 블로거 커니님이 관련된 내용의 포스트를 하셔서 자세한 내용을 물어보았다.

http://androidhuman.tistory.com/entry/안드로이드를-위한-자바-오버로딩Overloading-오버라이딩Overriding의-이해

오버라이드인 경우 꼭 super.onCreate(); 라인 밑에다가 자신이 해야할 일들을 작성해야 하는 이유가 있나요?
작성된 소스들을 보거나 실제로 해봐도 그전이나 그후에 해도 작동에 차이를 안보이는 듯했습니다.
또한 이클립스에서 오버라이드를 하면 TODO주석이 super라인 전에 달립니다.
먼저 부모 메소드의 일을 진행하고 내일을 하는 것과 내일을 하고 부모일을 진행하는 것 어떤 차이가 있는지요?
쓰다보니 먼가 따지듯이 적은 것 같지만 정말 궁금해서 댓글 남겨봅니다.

2012/11/06 17:44 ADDR : EDIT/ DEL : REPLY ]
  • 결론부터 말씀드리자면 상황에 따라 다 다릅니다.
    구현에 따라 부모 메서드를 먼저 호출하지 않으면 제대로 동작하지 않는 것도 있을 것이고, 어떤 경우에는 상황에 따라 자식 메서드와 부모 메서드 둘 중 하나만을 호출하도록 할 수도 있습니다. 

    간단히 예를 들자면

    if(condition){ // 어떤 상황에선
    // 자식 메서드의 구현으로 처리하지만
    }else{ // 그 밖의 상황은
    super.method(); // 부모 메서드의 방식 사용
    }

    이렇게 구현될 수도 있겠죠.

    액티비티의 Lifecycle 메서드를 오버라이드 할 때, 일반적으로는 순서를 바꿔도 별 상관이 없지만 액티비티 상태 저장/복귀가 일어나는 경우 순서를 바꾸면 오동작할 가능성이 있습니다. 때문에 개인적으로 부모 메서드 호출을 가장 먼저 하는 것을 권장합니다.

    2012/11/06 21:52 ADDR : EDIT/ DEL ]

결론은 상황에 따라 다르지만 안드로이드의 경우는 먼저 하는것을 추천해주었다.


일반적인 경우라면 상황에 따라 다른 것이 맞다. 부모메서드가 해야할일이 있다면 super를 부르는 것이 당연하고 그전에 무언가 처리해야할일이 있다면 super를 나중에 부르고 부모가 먼저 해줘야하는 일이 있다면 super를 먼저 부르면 된다.





'Mobile > Android' 카테고리의 다른 글

Fragment를 이용한 TabActivity  (0) 2012.11.09
Fragment(1)  (0) 2012.11.09
IntentService  (0) 2012.11.06
weight값설정시 최적화  (0) 2012.11.06
한 앱에서 라이브러리와 값 공유  (0) 2012.11.02
posted by Kyleslab 2012. 11. 6. 18:43

IntentService
이것은 모든 start요청을 한번에 하나씩 처리하기 위해 worker thread를 사용하는 서비스의 서브클래스이다. 이것은 서비스가 다중 요청들을 동시에 처리해야하는 경우가 아니라면 최적의 선택사항이다. 할 일은 onHandlerIntent()를 구현하는 것이다. 이 메소드는 백그라운드 작업을 할 수 있도록 각각의 시작요청을 위한 인텐트를 수신한다. 

다음 섹션은 이러한 클래스들 중 하나를 사용해서 서비스를 구현하는 방법을 설명한다.

Extending the IntentServie class
대부분의 시작된 서비스들은 동시에 다중 요청(사실상 위험한 다중스레딩 시나리오가 될 수 있다.)을 처리할 필요가 없기 때문에 IntentService 클래스를 사용하여 서비스를 구현하는 것이 아마도 최선일 것이다.

IntentService는 다음과 같은 것을 한다.

1. onStartCommand()에 전달된 모든 인텐트들을 실행하는 어플리케이션의 메인 스레드에서 분리된 디폴트 worker thread를 생성한다.
2. 한번에 하나의 인텐트를 통과시키는 작업 큐를 생성한다. 그러므로 다중 스레딩에 대해 걱정할 필요가 없다.
3. 모든 시작 요청들이 처리된 후에 서비스를 정지시킨다. 그러므로 stopSelf() 메소드를 호출할 필요가 없다.
4. 널을 리턴하는 onBind()의 디폴트 구현을 제공한다.
5. 작업 큐와 그 다음으로 onHandleIntent() 구현에 인텐트를 전송하는 onStartCommand()의 디폴트 구현을 제공한다.

할 일은 클라이언트에 의해 제공된 작업을 하기 위해 onHandleintent()를 구현하는 것이다. ( 어쨋든 서비스를 위해 작은 생성자를 제공할 필요가 있다.)


출처 : 브린과 페이지(http://brinpage.blogspot.kr/2011/11/services.html)

'Mobile > Android' 카테고리의 다른 글

Fragment(1)  (0) 2012.11.09
생명주기 메소드를 Override할때 super의 위치  (0) 2012.11.08
weight값설정시 최적화  (0) 2012.11.06
한 앱에서 라이브러리와 값 공유  (0) 2012.11.02
BroadcastReceiver  (0) 2012.11.02
posted by Kyleslab 2012. 11. 6. 16:27


이렇게 LinearLayout으로 감싼 뷰중 하나를 남은 공간에 꽉차게 할때

보통 뷰의 속성에 weight 값을 설정해서 하곤한다. 

이때 아래와 같이 설정해줬다면 width는 0으로 설정해주는 것이 좋다. 

(LinearLayout의 orientation이 vertical인경우에는 height를 0으로 설정)



그 이유는 

weight값은 남은 공간을 채우기 위한 다른 width계산이 필요한데 wrap_content을 사용하는것은 시스템은 결국 상관없는 width를 계산하게 되기 때문이다.

'Mobile > Android' 카테고리의 다른 글

생명주기 메소드를 Override할때 super의 위치  (0) 2012.11.08
IntentService  (0) 2012.11.06
한 앱에서 라이브러리와 값 공유  (0) 2012.11.02
BroadcastReceiver  (0) 2012.11.02
Push에 대한 것!  (0) 2012.10.30
posted by Kyleslab 2012. 11. 2. 17:45

한 앱에서 이미 라이브러리화된 곳으로 값을 공유할때 전달인자를 사용하는 것도 가능하지만

SharedPreference를 이용하는 것이 가능하다.

'Mobile > Android' 카테고리의 다른 글

IntentService  (0) 2012.11.06
weight값설정시 최적화  (0) 2012.11.06
BroadcastReceiver  (0) 2012.11.02
Push에 대한 것!  (0) 2012.10.30
TweenAnimation  (0) 2012.09.24
posted by Kyleslab 2012. 11. 2. 15:32

어느정도 결론을 내리긴 했지만 역시나 찝찝하다.

- broadcast 즉 보내는 쪽에서는 어떻게 권한을 실어보내고 받는 쪽은 어떻게 검사를 할까?

- 보내는 쪽에서는 

public abstract void sendBroadcast (Intent intent, String receiverPermission)

Added in API level 1

Broadcast the given intent to all interested BroadcastReceivers, allowing an optional required permission to be enforced. 

이것을 이용하면 될듯 싶은데 Manifest파일에 

<permission android:name="com.test.Permission.send"></permission>

   <uses-permission android:name="com.test.Permission.send"/>

이것도 반드시 작성해야했다.


#. 그런데 sendBroadcast(intent)로 작성하고 Manifest파일에 uses-permission만을 이용해도 가능했다. 그런데 어느 순간부터 또 안된다.


- 받는 쪽에서는 

        <receiver

            android:name="com.example.receiver.TextReceiver"

            android:permission="com.test.Permission.send" >

            <intent-filter>

                <action android:name="com.test.SEND" >

                </action>


                <category android:name="sender" >

                </category>

            </intent-filter>

        </receiver>

이런식으로 정의해주면 된다.


#. 신기한 점은 이 리시버에 퍼미션이 없다면 무조건 통과가 된다.

마치 인텐트의 액션이 아무것도 정의되있지 않다면 모든 인텐트 필터를 통과하는 것처럼 말이다.

단 카테고리는 정확히 일치해야한다.


#. 또한 보내는 쪽에서 sendBroadcast(intent) 메소드를 이용하여 권한없고 ManifestFile에는 위와 같이 적용되어있을때도 리시버가 브로드캐스트를 받는다. 이것을 미루어볼때 굳이 메소드를 이용하지 않고 브로드캐스트를 하면 안드로이드쪽에서 알아서 Manifestfile을 검사하여 권한을 실어 보내는 듯 하다. 그러나 과연 진실은 어디에?



위와 같이 적용해서 사용하기는 했지만 역시 권한을 적용해주는 정확한 방법이 없고 경우의 수도 많아서 조금 혼란스럽다. 다른 블로그에도 정확한 설명이 없다. 레퍼런스에는 단편적인 정보뿐이다.


생각하다보니 리시버와 서비스는 둘다 켜있지 않아도 인텐트를 받아 처리할 수 있다. 이런 면에서 볼때 차이점이 없어 보여 혼동이 되었다. 그러나 생각해보니 리시버에서 받은 인텐트는 그렇게 전달하고 끝이 아니라 관심있는 모든 리시버들에게 줄수 있고 확실히 이런 알림 되는 것들을 받아 간단한 작업을 빠르게 처리하는데 특화되어 있다는게 생각이다. 

서비스와 달리 개발자가 볼수 있는 부분도 onRecieve()메소드 하나로 제한한점이나, 10초안에 처리를 완료하지 않으면 ANR로 자동으로 종료해준다던지 등등 말이다. 실제 레퍼런스에서도 이런 작업을 하기위해 제일 작은 비용을 소모하게 되어 있다고 한다. 



### 더 공부하다보니 확실해졌다. 보내는 쪽의 매니페스트 파일안에는 permission을 정의하고  use-permission이 반드시 있어야하고 받는 쪽에서는 매니페스트파일이나 리시버에 반드시 있어야한다.




'Mobile > Android' 카테고리의 다른 글

weight값설정시 최적화  (0) 2012.11.06
한 앱에서 라이브러리와 값 공유  (0) 2012.11.02
Push에 대한 것!  (0) 2012.10.30
TweenAnimation  (0) 2012.09.24
AsyncTask  (0) 2012.09.21
posted by Kyleslab 2012. 10. 30. 20:45

- nPush


- Subscribe()시 npushService를 통해서 tagetId를 받는데 자체내에서 생성한다. 한 기기당 고유 ID를 생성하게 되고 그 ID앞에 각각 nhn앱들의 패키지명을 붙여 실제 targetId를 생성한다.


- 자체 생성인데 서비스로 돌리는 이유는 이것이 여러 nhn앱들을 깔아도 실행되는 서비스는 하나로 유지하기 위함이다.


- permission이  protectionLevel:signature로 설정되어있는 것은 이 퍼미션은 한가지의 시그니쳐로 서명된 앱들끼리만 사용할 수 있다는 말이된다. 이미 한가지 서명으로 이 퍼미션을 사용하는 앱이 있다면 다른 서명을 가졌지만 같은 퍼미션을 사용하는 앱은 이 퍼미션을 사용할 수 없게된다. 그러므로 이 퍼미션을 사용하는 시그니쳐로 된 앱들을 다죽여야지만 다른 시그니쳐로 서명된(예로 디버그 시그니쳐) 앱이 이 퍼미션을 사용할 수 있게 된다.


- <intent-filter android:priority="13"

priority는 이 인텐트 필터에 대한 인텐트를 받게 된다. 브로드캐스트 리시버의 경우는 우선순위에 따라 차례대로 모든 리시버의 onReceive를 실행하게 되지만 서비스는 최상위 priority를 가진 서비스 하나만 실행하게 된다. 그래서 새로 만든 npush라이브러리를 적용할때 이 priority를 하나씩 증가하게 된다면 nhn앱들중에 이 최신 npush라이브러리를 사용한 어플이 하나만 있어도 모든 nhn앱들이 그것이 적용되는 것이다. 


android:process="com.nhn.android.npush" 

서비스가 실행될 때의 서비스의 이름이 된다. 그러므로 어느 nhn앱이던지 다른 nhn앱이 실행하고 있는 이 서비스를 찾아갈 수 있게 된다. 이 프로세스이름을 통일해줌으로써 글로벌 서비스가 되는 것이다.  nhn앱마다 npush서비스가 탑재되어있어서 자신이 startService할경우 중복으로 서비스를 실행하는 것이 아니라 안드로이드 시스템자체에서 이미 실행중이라는 것을 알아차리고 기존 서비스에 인텐트만 전달해주게 된다.


- android:exported="true"

다른 어플리케이션에서 이 서비스를 실행시킬수 있게 된다. 이 값은 설정하지 않아도 서비스가  인텐트 필터를 갖는다면 관련된 인턴트는 실행시킬수 있다.


- npush test App으로 npush service를 돌렸을 경우는 어느 서버에 물리느냐에 따라 푸시가 오는지 안오는지 결정된다.


- targetID등을 갖는 것은 Sharedpreference이다. 여러 앱에서 공유해서 사용하게 하기 위함이다.


- 자신이 아닌 다른 앱이 이 서비스를 실행하고 있는 경우에 이 서비스와의 정보교환은 모두 인텐트로 이루어진다.




android:name
The name of the class that implements the broadcast receiver



android:permission
The name of a permission that broadcasters must have to send a message to the broadcast receiver.

결국 리시버나 서비스나 이 옵션을 가진 송신자(인텐트)만이 이 리시버나 서비스를 실행시킬수 있게된다. 브로드캐스트 같은 경우는 sendBroadcast(intent, receiverPermission) 여기에서 퍼미션을 설정하여 보내게 되고 서비스는 매니페스트 파일의 use-permission 옵션을 가진 앱에서만 사용이 가능하다.



- receiver 의 permission

receiver 가 permission 값을 가지고 있으면, sendBroadcast 를 하는 쪽에서 permission 이 필요합니다. 보내는 쪽에서 permission 을 주지 않고 해당 broadcast intent 를 날리면, broadcast 가 받아지지 않습니다. 만약 Application tag 쪽에 permission 을 가지고 있고, receiver 쪽에는 기술되어 있지 않다면, receiver 는 application 의 permission 을 상속합니다.
센더의 매니페스트 파일에 use-permission으로 작성하고 인텐트로 서비스나 브로드캐스트리시버를 실행하면 인텐트에 퍼미션을 같이 실어서 보내는 건가? 아니면 인텐트를 쏜앱을 찾아서 퍼미션을 검사하는 것인가?


- NNI subscribe시
알림을 받고자 등록시에 호출한다.
NPushMessaging.requestSubscribe(context, "naverapp"); targetId를 만들때 조합할 서비스명이 된다. 호출후 브로드캐스트리시버로 타겟아이디를 전달받는다.

- GCM은 NPush서비스와는 별개로 자신의 서비스로 돌게된다 레지스터 요청, 메시지 받는것 등등




'Mobile > Android' 카테고리의 다른 글

한 앱에서 라이브러리와 값 공유  (0) 2012.11.02
BroadcastReceiver  (0) 2012.11.02
TweenAnimation  (0) 2012.09.24
AsyncTask  (0) 2012.09.21
Context  (0) 2012.09.21
posted by Kyleslab 2012. 9. 24. 16:03

1. 트윈 애니메이션의 종류 및 설명
 
    트윈 애니메이션은 주어진 정보를 이용하여 뷰의 출력 영역을 연산하는 방법을 사용하며 이러한
    방법으로 이동, 회전, 투명화, 크기 변경을 구현할 수 있습니다. 하지만 뷰의 출력에 대한 부분만
    연산하여 출력시키기 때문에 뷰가 화면에 보이지 않더라도 지속적으로 터치 이벤트를 받는 등
    뷰 자체가 애니메이션에 영향을 받지 않으므로 추가적인 처리를 해야할 수도 있습니다.
  
 
    1.1 투명화 적용
 
        트윈 애니메이션으로 투명화를 적용하면 화면에서 뷰가 점점 사라지도록 표현할 수 있고, 반대로
        보이지 않는 뷰가 점점 나타나도록 표현할 수도 있습니다. XML 에서 투명화를 표현할 때 사용하는
        요소 및 속성은 아래와 같습니다.
 
        요소명 - alpha
        속성
            - android:fromAlpha : 애니메이션 시작시 적용될 투명도입니다. 0.0 으로 설정하면 완전한
                                        투명화가 적용되며 1.0 으로 하면 투명도가 적용되지 않습니다.
            - android:toAlpha : 애니메이션 종료시 적용될 투명도입니다. 0.0 으로 설정하면 완전한
                                        투명화가 적용되며 1.0 으로 하면 투명도가 적용되지 않습니다.
 
        투명화 애니메이션은 애니메이션 설정한 시간동안 fromAlpha 속성에 지정한 투명도에서 toAlpha
        속성에 지정한 투명도로 뷰를 변형시킵니다.
 
 
    1.2 크기 변경 ( scale )
  
        크기 변경은 뷰의 크기를 변경하는 것입니다. 시작시 뷰의 크기와 애니메이션이 종료될 때의
        크기를 지정할 수 있으며 크기 변경시 뷰의 어느 위치를 기준으로 변경이 되는지도 설정할 수
        있습니다.
 
        요소명 - scale
        속성
            - android:fromXScale : 애니메이션 시작시 뷰의 너비입니다. 1.0 이 온전한 뷰의 크기를
                        의미하며 1.0 보다 작으면 뷰의 너비가 작아지고, 1.0 보다 크면 뷰의 너비가 커집니다.
            - android:toXScale : 애니메이션 종료시 뷰의 너비입니다. 1.0 이 온전한 뷰의 크기를
                        의미하며 1.0 보다 작으면 뷰의 너비가 작아지고, 1.0 보다 크면 뷰의 너비가 커집니다.
 
            - android:fromYScale : 애니메이션 시작시 뷰의 높이입니다. 1.0 이 온전한 뷰의 크기를
                        의미하며 1.0 보다 작으면 뷰의 너비가 작아지고, 1.0 보다 크면 뷰의 너비가 커집니다.
            - android:toYScale : 애니메이션 종료시 뷰의 높이입니다. 1.0 이 온전한 뷰의 크기를
                        의미하며 1.0 보다 작으면 뷰의 너비가 작아지고, 1.0 보다 크면 뷰의 너비가 커집니다. 
 
            - android:pivotX : 뷰의 크기가 변경될 때 뷰의 위치를 의미합니다. 0% 이면 뷰의 좌측이
                        고정된 상태로 크기가 변경되며 50% 이면 뷰의 중점을 중심으로 뷰의 크기가 변경
                        됩니다. 즉, 뷰가 커질 땐 좌우로 함께 커지고, 작아질때에도 좌우로 줄어듭니다.
            - android:pivotY : 뷰의 크기가 변경될 때 뷰의 위치를 의미합니다. 0% 이면 뷰의 상단이
                        고정된 상태로 크기가 변경되며 50% 이면 뷰의 중점을 중심으로 뷰의 크기가 변경
                        됩니다. 즉, 뷰가 커질 땐 상하로 함께 커지고, 작아질때에도 상하로 줄어듭니다.
            
 
    1.3 이동 ( translate )
 
        두개의 위치 값을 지정하여 시작 위치에서 이동 종료 위치로 뷰를 이동시킵니다.
 
        요소명 - translate
        속성
            - android:fromXDelta : 뷰의 X 좌표상 시작 위치입니다. 수치값을 직접 입력하면 픽셀단위의
                        위치로 판단하여 해당 위치에서 시작하며 퍼센트값을 입력하면 뷰의 너비에서 해당
                        퍼센트를 연산한 위치에서 시작합니다. 또, 퍼센트 뒤에 p 를 붙이면 뷰를 소유한
                        부모 객체의 너비에서 퍼센트를 연산한 위치에서 시작하게 됩니다.
            - android:toXDelta : 뷰의 X 좌표상 이동 종료 위치입니다. 해당 속성이 가질 수 있는 값은
                        fromXDelta 와 같습니다.
            - android:fromYDelta : 뷰의 Y 좌표상 시작 위치입니다. 해당 속성이 가질 수 있는 값은
                        fromXDelta 와 같습니다.
            - android:toYDelta : 뷰의 Y 좌표상 이동 종료 위치입니다. 해당 속성이 가질 수 있는 값은
                        fromXDelta 와 같습니다.
 
 
    1.4 회전 ( rotate )
 
        애니메이션의 시작 시점과 종료 시점의 뷰의 각도, 위치를 지정하여 뷰를 회전 시킵니다.
 
        요소명 - rotate
        속성
            - android:fromDegrees : 애니메이션이 시작될 때 뷰에 적용되는 각도입니다.
            - android:toDegrees : 애니메이션이 종료될 때 뷰에 적용되는 각도입니다.
            - android:pivotX : 회전 애니메이션이 이루어질 X 좌표상의 기준 위치입니다. 이 요소에
                        수치값을 직접 입력하면 픽셀단위의 위치로 판단하여 해당 위치에서 시작하며
                        퍼센트값을 입력하면 뷰의 너비에서 해당 퍼센트를 연산한 위치에서 시작합니다.
                        또, 퍼센트 뒤에 p 를 붙이면 뷰를 소유한 부모 객체의 너비에서 퍼센트를 연산한
                        위치에서 시작하게 됩니다.
            - android:pivoxY : 회전 애니메이션이 이루어질 Y 좌표상의 기준 위치입니다. pivotX 속성과
                        동일하게 값을 설정할 수 있습니다.
   
     
2. set 요소와 부가적인 속성들
   
    XML 형식으로 애니메이션을 정의할 때에는 반드시 set 요소 안에 애니메이션 요소들을 정의해야
    합니다. set 요소는 여러개의 애니메이션을 하나로 그룹짓는 역할을 하며 애니메이션의 효과를
    정의할 수 있는 interpolator 속성을 포함하고 있습니다. 아래의 코드는 이동 애니메이션을 구성하는
    간단한 XML 코드입니다.
  
    <?xml version="1.0" encoding="utf-8"?>
    <set
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:anim/bounce_interpolator">

        <translate 
            android:fromYDelta="0%" 
            android:toYDelta="50%"
            android:duration="2000"
            />
    </set>
 
    루트의 set 요소에는 어플리케이션에서 레이아웃을 구성할 때처럼 요소와 속성명들을 해석할 수
    있도록 네임스페이스를 정의해줍니다. set 요소의 interpolator 속성은 뷰의 이동시 어떤 효과를
    부가적으로 표현할지를 정의하는데 set 요소에서 모든 애니메이션에 동일하게 효과를 적용시킬
    수도 있습니다. interpolator 속성으로 정의 가능한 값과 효과는 다음과 같습니다.
  
    @android:anim/accelerate_decelerate_interpolator
 
        애니메이션이 점점 빠르게 동작하다가 점점 천천히 동작합니다.
 
 
    @android:anim/accelerate_interpolator
 
        애니메이션이 점점 빠르게 동작합니다.
 
 
    @android:anim/anticipate_interpolator
 
        애니메이션이 시작할 때 반대 방향으로 동작을 한 후에 본래의 방향으로 동작합니다.
 
 
    @android:anim/anticipate_overshoot_interpolator
 
        애니메이션이 시작할 때 반대 방향으로 동작을 한 후에 종료 지점을 지나갔다가 종료 지점으로
        돌아옵니다. 예를 들어 왼쪽에서 오른쪽으로 이동하는 애니메이션이 있다면 시작할 때 뷰가
        왼쪽으로 조금 움직인 후 오른쪽으로 이동하고, 원래 도착해야할 위치를 지났다가 다시 왼쪽으로
        이동합니다.
 
 
    @android:anim/bounce_interpolator
 
        애니메이션이 종료될 때 튕기면서 스프링 효과를 표현합니다.
 
 
    @android:anim/cycle_interpolator
  
        애니메이션을 동작한 후에 반대 방향으로 한번 더 동작합니다. 만약 오른쪽으로 50 위치까지
        이동하는 애니메이션에 이 효과가 적용되면 오른쪽으로 50 만큼 이동한 후에 왼쪽으로 -50
        위치까지 이동하게됩니다.
       
       
    @android:anim/decelerate_interpolator
 
        애니메이션의 움직임이 점점 느려집니다.
 
 
    @android:anim/linear_interpolator
 
        특별한 효과 없이 일정하게 애니메이션이 동작합니다.
 
 
    @android:anim/overshoot_interpolator
 
        애니메이션이 동작할 때 멈춰야할 위치를 지난 후에 다시 돌아옵니다.
  
 
    set 요소에서는 interpolator 속성과 함께 shareInterpolator 속성을 설정해주어야 합니다.
    shareInterpolator 속성는 interpolator 속성에 설정한 효과를 내부의 다른 애니메이션들이 공유하여
    사용할 것인지 여부를 설정하는 것입니다. 이 속성값은 기본이 true 이며 true 로 설정하면 set 요소
    내의 애니메이션이 interpolator 속성에 설정한 효과로 일괄 적용되며 false 로 설정하면 내부의
    애니메이션에서 설정한 interpolator 속성을 따로따로 적용하게 됩니다.
 
    그래서 애니메이션마다 각기 다른 interpolator 속성을 적용하더라도 set 요소에서 shareInterpolator
    속성에 true 를 지정하면 각자의 애니메이션에서 설정한 효과가 적용되지 않습니다.
 
    또 애니메이션에 startOffset 속성과 duration 속성을 설정할 수 있는데 startOffset 속성은 지정한
    밀리초 시간 후에 애니메이션을 동작하겠다는 것이고, duration 속성은 지정한 밀리초 시간만큼
    애니메이션을 동작하겠다는 것입니다. 기본적으로 set 요소 내부에 정의된 애니메이션은 동시에
    애니메이션이 수행되기 때문에 애니메이션간에 시간 차를 두고싶을 때 startOffset 속성을 사용하며
    duration 속성은 지정하지 않으면 애니메이션이 동작할 수 있는 시간이 설정되지 않는 것이므로
    반드시 지정해주어야합니다.
 
 
3. 간단한 예제 
 
    아래의 코드는 네 종류의 애니메이션을 볼 수 있도록 네개의 버튼을 구성하여 각 버튼을 누를때마다
    하단의 뷰가 동작하도록 구성한 것입니다.
 
    // rotation.xml - 회전
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/cycle_interpolator">
        <rotate
            android:fromDegrees="0"           
            android:toDegrees="-45"           
            android:toYScale="0.0"           
            android:pivotX="0%"           
            android:pivotY="0%"           
            android:duration="1000" 
            />
    </set>
 
    // size.xml - 크기 변경
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/cycle_interpolator">
        <scale
            android:fromXScale="1.0"
            android:toXScale="1.4"
            android:fromYScale="1.0"
            android:toYScale="0.6"
            android:pivotX="50%"        
            android:pivotY="50%"   
            android:duration="1000" 
            />   
    </set>
 
    // transparent.xml - 투명화
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
        <alpha
            android:fromAlpha="1.0"
            android:toAlpha="0.5"
            android:duration="1000"
            />
    </set>
 
    // move.xml - 뷰 이동
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:shareInterpolator="false">
        <translate 
            android:interpolator="@android:anim/bounce_interpolator"
            android:fromYDelta="0%" 
            android:toYDelta="50%"
            android:duration="2000"
            />
    </set>
 
    // mix.xml - 복합 애니메이션
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:shareInterpolator="false">
        <scale
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"
            android:fromXScale="1.0"
            android:toXScale="0.5"
            android:fromYScale="1.0"
            android:toYScale="0.5"
            android:pivotX="50%"
            android:pivotY="50%"
            android:duration="2000" 
            />
        <alpha
            android:fromAlpha="1.0"
            android:toAlpha="0.5"
            android:duration="2000"
            />
        <set android:interpolator="@android:anim/accelerate_interpolator">
            <scale
                android:fromXScale="0.5"
                android:toXScale="0.0"
                android:fromYScale="0.5"
                android:toYScale="0.0"
                android:pivotX="50%"
                android:pivotY="50%"
                android:startOffset="2000"
                android:duration="2000" 
                />
            <rotate
                android:fromDegrees="0"
                android:toDegrees="-45"
                android:toYScale="0.0"
                android:pivotX="50%"
                android:pivotY="50%"
                android:startOffset="2000"
                android:duration="2000" 
                />
        </set>
    </set>
  
    // 소스 코드 - 버튼을 클릭하여 OnClickListener 인터페이스의 onClick 메소드가 호출되었을 때
    public void onClick(View view)
    {
        int id = view.getId();
        
        if(id == R.id.rotation_btn) {
            // rotation.xml 에 정의된 애니메이션을 불러온다.
            Animation ani = AnimationUtils.loadAnimation(this, R.anim.rotation);
            // 애니메이션을 동작시킨다.
            m_tween_view.startAnimation(ani);         
  
        } else if(id == R.id.size_btn){
            // size.xml 에 정의된 애니메이션을 불러온다.
            Animation ani = AnimationUtils.loadAnimation(this, R.anim.size);
            // 애니메이션을 동작시킨다.
            m_tween_view.startAnimation(ani); 
          
        } else if(id == R.id.transparent_btn) {
            // transparent.xml 에 정의된 애니메이션을 불러온다.
            Animation ani = AnimationUtils.loadAnimation(this, R.anim.transparent);
            // 애니메이션을 동작시킨다.
            m_tween_view.startAnimation(ani); 
          
        } else if(id == R.id.move_btn) {
            // move.xml 에 정의된 애니메이션을 불러온다.
            Animation ani = AnimationUtils.loadAnimation(this, R.anim.move);
            // 애니메이션을 동작시킨다.
            m_tween_view.startAnimation(ani);          
 
        } else if(id == R.id.mix_btn) {
            // mix.xml 에 정의된 애니메이션을 불러온다.
            Animation ani = AnimationUtils.loadAnimation(this, R.anim.mix);
            // 애니메이션을 동작시킨다.
            m_tween_view.startAnimation(ani);           
        }
    }
 

'Mobile > Android' 카테고리의 다른 글

BroadcastReceiver  (0) 2012.11.02
Push에 대한 것!  (0) 2012.10.30
AsyncTask  (0) 2012.09.21
Context  (0) 2012.09.21
UI쓰레드와 Handler  (0) 2012.09.21
posted by Kyleslab 2012. 9. 21. 19:06

전 포스트에서 설명했던 여러 스레드 구현방법들은 비록 아무 문제가 없지만 구현방법이 복잡해서 코드를 읽기 힘들게 만드는 경향이 있었다. Background작업에 관한 모든 사항(스레드 객체 생성, 사용, UI스레드와 통신 등)이 Activity 코드에 포함 되고 특히 background 스레드가 UI위젯과 빈번한 통신을 할수록 Activity 코드의 복잡함은 점점 배가 된다. 

 

안드로이드에서는 이런 문제를 해결하기 위해 API level 3 (1.5 version) 부터 AsyncTask라는 클래스를 제공하고 있다. 


AsyncTask클래스는 background작업을 위한 모든 일(스레드생성, 작업실행, UI와 통신 등)을 추상화 함으로 각각의 background작업을 객체 단위로 구현/관리 할 수 있게 하는것이 목적이다. 그림으로 표현하면 다음과 같다.




참고로 1.0과 1.1 version의 API를 사용하는 디바이스에서는 구글 code에 공개되어 있는 UserTask 라는 클래스를 어플리케이션 프로젝트에 복사해 넣어 사용할 수 있다. 기능과 사용법은 AsyncTask와 완전히 동일하다.

 

그럼 AsyncTask에 관해 자세히 살펴보자.


 

 

1. AsyncTask 클래스 소개

 

AsyncTask라는 클래스 이름은 Asynchronous Task의 줄임이며, UI스레드의 입장에서 볼 때 비동기적으로 작업이 수행되기 때문에 붙여진 이름이다. (Ajax: Asynchronous javascript and XML 에서 사용된 의미와 같다)

 

AsyncTask의 상속관계는 다음과 같다.

 

Object로부터 상속하는 AsyncTask는 Generic Class이기 때문에 사용하고자 하는 type을 지정해야 한다.


AsyncTask클래스의 사용시 지정해야 하는 generic type은 각각 다음의 용도로 사용된다.

  • Params: background작업 시 필요한 data의 type 지정
  • Progress: background 작업 중 진행상황을 표현하는데 사용되는 data를 위한 type 지정
  • Result: background 작업 완료 후 리턴 할 data 의 type 지정

 

 

그림으로 각 generic type이 결정하는 것들을 표현하면 다음과 같다.

(각 메소드의 자세한 정보는 다음 단락의 예제 코드와 설명 참조)

 

 

만약 type을 정할 필요가 없는 generic이 있다면 void를 전달하면 된다.

예. …AsyncTask<void, void, void> {…}

 

 

 

 

2. AsyncTask의 사용

 

우선 AsyncTask가 어떻게 사용되는지 예제 소스를 보자.

AsyncTask 클래스의 사용 예

접기

001package com.holim.test;
002 
003import android.app.Activity;
004import android.os.AsyncTask;
005import android.os.Bundle;
006import android.os.SystemClock;
007import android.view.View;
008import android.widget.Button;
009import android.widget.ProgressBar;
010import android.widget.TextView;
011 
012public class AsyncTaskDemo extends Activity
013                implements View.OnClickListener {
014     
015    ProgressBar progressBar;
016    TextView textResult;
017    Button btnExecuteTask; 
018     
019    /** Called when the activity is first created. */
020    @Override
021    public void onCreate(Bundle savedInstanceState) {
022        super.onCreate(savedInstanceState);
023        setContentView(R.layout.main);
024     
025        progressBar = (ProgressBar)findViewById(R.id.progressBar);
026        textResult = (TextView)findViewById(R.id.textResult);
027        btnExecuteTask = (Button)findViewById(R.id.btnExecuteTask);
028         
029        btnExecuteTask.setOnClickListener(this);
030    }
031     
032    public void onClick(View v) {
033         
034        // AsynchTask를 상속하는 DoComplecatedJob 클래스를 생성하고
035        // execute(...) 명령으로 background작업을 시작함.
036        // (예제에 구현된 AsynchTask는 String 형의 인자를 받음)
037        new DoComplecatedJob().execute("987",
038                                        "1589",
039                                        "687",
040                                        "399",
041                                        "1722",
042                                        "50");     
043    }
044     
045     
046    // AsyncTask클래스는 항상 Subclassing 해서 사용 해야 함.
047    // 사용 자료형은
048    // background 작업에 사용할 data의 자료형: String 형
049    // background 작업 진행 표시를 위해 사용할 인자: Integer형
050    // background 작업의 결과를 표현할 자료형: Long
051    private class DoComplecatedJob extends AsyncTask<String, Integer, Long> {      
052    
053     
054        // 이곳에 포함된 code는 AsyncTask가 execute 되자 마자 UI 스레드에서 실행됨.
055        // 작업 시작을 UI에 표현하거나
056        // background 작업을 위한 ProgressBar를 보여 주는 등의 코드를 작성.
057        @Override
058        protected void onPreExecute() {
059            textResult.setText("Background 작업 시작 ");           
060            super.onPreExecute();
061        }
062 
063        // UI 스레드에서 AsynchTask객체.execute(...) 명령으로 실행되는 callback
064        @Override
065        protected Long doInBackground(String... strData) {
066            long totalTimeSpent = 0;
067             
068            // 가변인자의 갯수 파악 (이 예제에서는 5개)
069            int numberOfParams = strData.length;
070             
071            // 인자들을 이용한 어떤 작업을 처리를 함
072            for(int i=0; i<numberOfParams; i++) {              
073                 
074                // 각 인자를 이용한 복잡한 Task 실행함.
075                // 예제에서는 인자로 전달된 시간만큼 sleep
076                SystemClock.sleep(new Integer(strData[i]));
077                 
078                // background 작업에 걸린시간을 누산해 리턴함
079                totalTimeSpent += new Long(strData[i]);
080                 
081                // onProgressUpdate callback을 호출 해
082                // background작업의 실행경과를 UI에 표현함
083                publishProgress((int)(((i+1)/(float)numberOfParams)*100));
084            }          
085            return totalTimeSpent;
086        }
087         
088        // onInBackground(...)에서 publishProgress(...)를 사용하면
089        // 자동 호출되는 callback으로
090        // 이곳에서 ProgressBar를 증가 시키고, text 정보를 update하는 등의
091        // background 작업 진행 상황을 UI에 표현함.
092        // (예제에서는 UI스레드의 ProgressBar를 update 함)
093        @Override
094        protected void onProgressUpdate(Integer... progress) {
095            progressBar.setProgress(progress[0]);
096        }
097         
098        // onInBackground(...)가 완료되면 자동으로 실행되는 callback
099        // 이곳에서 onInBackground가 리턴한 정보를 UI위젯에 표시 하는 등의 작업을 수행함.
100        // (예제에서는 작업에 걸린 총 시간을 UI위젯 중 TextView에 표시함)
101        @Override
102        protected void onPostExecute(Long result) {
103            textResult.setText("Background 작업에 걸린 총 시간: "
104                            new Long(result).toString()
105                            "m초");   
106        }
107         
108        // AsyncTask.cancel(boolean) 메소드가 true 인자로
109        // 실행되면 호출되는 콜백.
110        // background 작업이 취소될때 꼭 해야될 작업은  여기에 구현.
111        @Override
112        protected void onCancelled() {
113            // TODO Auto-generated method stub
114            super.onCancelled();
115        }      
116    }
117}

접기

 

 

AsyncTask 클래스는 다음과 같이 중요한 callback들을 제공 함으로 상황에 맞게 오버라이딩 해야 한다.

  • protected void onPreExecute(): Background 작업이 시작되자마자 UI스레드에서 실행될 코드를 구현해야 함. (예. background 작업의 시작을 알리는 text표현, background 작업을 위한 ProgressBar popup등)
  • protected abstract Result doInBackground(Params… params): Background에서 수행할 작업을 구현해야 함. execute(…) 메소드에 입력된 인자들을 전달 받음.
  • void onProgressUpdate(Progress... values): publishProgress(…) 메소드 호출의 callback으로 UI스레드에서 보여지는 background 작업 진행 상황을 update하도록 구현함. (예. ProgressBar 증가 등)
  • void onPostExecute(Result result): doInBackground(…)가 리턴하는 값을 바탕으로 UI스레드에 background 작업 결과를 표현하도록 구현 함. (예. background작업을 계산한 복잡한 산술식에 대한 답을 UI 위젯에 표현함 등)
  • void onCancelled(): AsyncTask:cancel(Boolean) 메소드를 사용해 AsyncTask인스턴스의 background작업을 정지 또는 실행금지 시켰을 때 실행되는 callback. background작업의 실행정지에 따른 리소스복구/정리 등이 구현될 수 있다.

 

 

또, AsyncTask 클래스는 background 작업의 시작과 background 작업 중 진행정보의 UI스레드 표현을 위해 다음과 같은 메소드를 제공한다.

  • final AsyncTask<…> execute(Params… params): Background 작업을 시작한다. 꼭 UI스레드에서 호출하여야 함. 가변인자를 받아들임으로 임의의 개수의 인자를 전달할 수 있으며, 인자들은 doInBackground(…) 메소드로 전달된다.
  • final void publishProgress(Progress... values): Background 작업 수행 중 작업의 진행도를 UI 스레드에 전달 함. doInBackground(…)메소드 내부에서만 호출.

 

 

위의 메소드들은 AsyncTask 클래스를 이용해 구현된 background 작업 시 다음과 같은 형태로 사용된다.

 

 

위 의 그림에서 처럼AsyncTask인스턴스는 자기 자신을 pending, running, finished 이렇게 세 가지 상태(status)로 구분하는데 각각 AsyncTask:Status 클래스에 상수 PENDING, RUNNING, FINISHED로 표현 될 수 있다.

현재 AsyncTask인스턴스의 상태는 다음 메소드를 호출해서 얻을 수 있다.


public final AsyncTask.Status getStatus ()

return

AsyncTask인스턴스의 상태정보를 AsyncTask.Status 객체의 상수 값 PENDING, RUNNING, FINISHED 중에서 리턴.

 

 

또, AsyncTask클래스는 background 작업을 정지, 또는 시작금지 시키기 위해 다음 메소드를 제공한다. 이 메소드가 성공적으로 호출되면 onCacelled() callback이 호출되니 onCacelled()에 적절한 뒤처리를 해주어야 한다.


final boolean cancel (boolean mayInterruptIfRunning)

parameter

mayInterruptIfRunning: true값을 제공했을 때 background작업이 실행 중일 경우(running 상태) 작업을 중단 시키고, 준비 중(pending 상태) 일 경우 작업을 실행 금지 시킴. (execute() 명령 사용 불가. 사용하면 exception 발생)

return

true: background작업을 성공적으로 중지하거나 실행 금지 시킴

false: 벌써 작업이 완료된 상태(finished 상태) 일 경우 리턴

 

 

마지막으로 AsyncTask 사용해 background작업을 구현 시 꼭 지켜야 하는 사항들이다.

  • AsyncTask클래스는 항상 subclassing 하여 사용하여야 한다.
  • AsyncTask 인스턴스는 항상 UI 스레드에서 생성한다.
  • AsyncTask:execute(…) 메소드는 항상 UI 스레드에서 호출한다.
  • AsyncTask:execute(…) 메소드는 생성된 AsyncTask 인스턴스 별로 꼭 한번만 사용 가능하다. 같은 인스턴스가 또 execute(…)를 실행하면 exception이 발생하며, 이는 AsyncTask:cancel(…) 메소드에 의해 작업완료 되기 전 취소된 AsyncTask 인스턴스라도 마찬가지이다. 그럼으로 background 작업이 필요할 때마다 new 연산자를 이용해 해당 작업에 대한 AsyncTask 인스턴스를 새로 생성해야 한다.
  • AsyncTask의 callback 함수 onPreExecute(), doInBackground(…), onProgressUpdate(…), onPostExecute(…)는 직접 호출 하면 안 된다. (꼭 callback으로만 사용)

'Mobile > Android' 카테고리의 다른 글

BroadcastReceiver  (0) 2012.11.02
Push에 대한 것!  (0) 2012.10.30
TweenAnimation  (0) 2012.09.24
Context  (0) 2012.09.21
UI쓰레드와 Handler  (0) 2012.09.21