블로그 이미지
엡뽀
피난(?) 오신걸 환영합니다.

calendar

1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Notice

2012. 12. 20. 13:17 Programing/Android

2. 리스트 View

이번엔 리스트 View를 만들어 볼껀데요. 별다른거 없이. STATE BAR, ACTION BAR, LISTVIEW, NAVIGATION BAR로 화면 구성을 하도록 하겠습니다. 


- ListViewActivity -


최종 프로젝트의 목적은 하나의 Activity 에 두개의 View를 만들어서 네비게이션 바를 통해 화면 전환이 일어나도록 하는 것이지만, 우선은 새로운 Activity를 만들어서 MainActivity에서 ACTION BAR -> ORDER ACTION 버튼으로 화면 전환이 일어나도록 하겠습니다. 반대로 ListActivity 에서는 홈버튼을 누르면 MainActivity로 되돌아가는(하지만 사실상 ActivityStack에 의하여 back키 한번만 눌러도 되죠 ㅎㅎ)식으로 구성하겠습니다. 


또한 기본 ListView를 그대로 사용하는 것보다 오픈소스를 이용하여 아래로 스크롤시 아이템이 추가 되는 리스트를 사용하여 화면 구성을 하도록 하겠습니다. 


▶ android-pulltorefresh 오픈소스.

 URL : https://github.com/johannilsson/android-pulltorefresh

(또 다시 오픈 소스를 프로젝트에 추가를 해야하는군요... 그렇습니다, 또 다시 복사 붙여넣기!!!)



파일 다운로드 및 압축 풀기.




다운로드를 풀게 되면, pulltorefresh폴더와 pulltorefreshexample 폴더가 나오게 되는데 이중 pulltorefresh 폴더 내용물들을 복사하여 프로젝트에 붙여넣기 하시면 됩니다. 



res\drawable



res\drawable-hdpi (전체 붙여넣기)



res\drawable-ldpi (전체 붙여넣기)



res\drawable-mdpi (전체 붙여넣기)



res\layout (전체 붙여넣기)



res\values

strings.xml 파일은 프로젝트에 존재하니깐 이번에도 내용 복사로 하겠습니다.



res\values\strings.xml

    <string name="pull_to_refresh_pull_label">Pull to refresh...</string>
    <string name="pull_to_refresh_release_label">Release to refresh...</string>
    <string name="pull_to_refresh_refreshing_label">Loading...</string>
    <string name="pull_to_refresh_tap_label">Tap to refresh...</string>



src\com\markupartist\android\widget 

(소스 파일은 기존에 추가 하였던 com.markupartist.android.widget 패키지에 넣으시면 됩니다.)


이것으로 android-pulltorefresh 오픈 소스를 사용할 준비가 다 되었구요. 새로운 Activity와 레이아웃 파일을 만들어 보도록 하겠습니다. 


- activity_list.xml -

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.markupartist.android.widget.ActionBar
        android:id="@+id/actionbar"
        style="@style/ActionBar" />

    <com.markupartist.android.widget.PullToRefreshListView
        android:id="@+id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="1" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="48dip"
        android:background="#a0ff0000"
        android:gravity="center"
        android:text="@string/navigation"
        android:textColor="#000000"
        android:textSize="22sp" />

</LinearLayout>

레이아웃 파일에서 리니어레이아웃을 최상위로 잡고, actionbar, listview, textview를 추가하였습니다.
여기서 하나 짚고 넘어가야하는 부분이, com.markupartist.android.widget.PullToRefreshListView 뷰의 id 설정 부분을 보시면 

android:id = "@+id/android:list" 

로 되어있는데요. 이는 activity를 만들때 ListActivity 클래스를 상속받아 만들기 위해서 지켜야하는 약속(?) 같은 것입니다. ListActivity 클래스는 Listview를 꼭 포함해야하며, Listview의 id가 android:list 값을 가져야합니다. (Android Developers 참조

하지만 사실상 Activity로 만든 다음에 findViewByID 메소드를 이용해서 list 객체를 얻어와도 상관없지만, 오픈소스의 예제를 충실히 따르기 위해서 id값을 저렇게 설정 하도록 하겠습니다. 



- ListViewActivity.java -

public class ListViewActivity extends ListActivity {
	//리스트 아이템.
	private String[] mStrings = {
            "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam",
            "Abondance", "Ackawi", "Acorn", "Adelost", "Affidelice au Chablis",
            "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler"};
	private LinkedList<String> mListItems;    //adapter 데이터 객체.
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_list);
		
                 //action bar 객체 얻기. 
		final ActionBar actionBar = (ActionBar) findViewById(R.id.actionbar);
        actionBar.setTitle("ListView");  //action bar 타이틀 설정.
        
        //action bar에 홈 action 설정. 
        actionBar.setHomeAction(new IntentAction(this, MainActivity.createIntent(this), R.drawable.ic_title_home_default));
        actionBar.setDisplayHomeAsUpEnabled(true); //action bar에 홈 버튼 보이기
        
         //OnRefreshListener 리스너 설정.
        ((PullToRefreshListView) getListView()).setOnRefreshListener(new OnRefreshListener() {
            public void onRefresh() {
                // Do work to refresh the list here.
                new GetDataTask().execute(); //Task 실행.
            }
        });
        
        mListItems = new LinkedList<String>(); //adapter 데이터 객체 생성
        mListItems.addAll(Arrays.asList(mStrings)); //데이터 설정
        
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mListItems); //adapter 생성. 

        setListAdapter(adapter); //리스트에 어뎁터 설정.
        
	}
	
	//데이터 추가 Task
	private class GetDataTask extends AsyncTask<Void, Void, String[]> {

        protected String[] doInBackground(Void... params) {
            // Simulates a background job.
            try {
                Thread.sleep(2000); //2초동안 프로세스 중지.
            } catch (InterruptedException e) {
                ;
            }
            return mStrings; //onPostExecute 함수에 넘겨줄 데이터 리턴.
        }

        protected void onPostExecute(String[] result) {
            mListItems.addFirst("Added after refresh..."); //"Added after refresh..." 데이터 추가
            // Call onRefreshComplete when the list has been refreshed.
            ((PullToRefreshListView) getListView()).onRefreshComplete(); //변경 완료.

            super.onPostExecute(result);
        }
    }

}



ListViewActivity 코드에선 두가지 정도만 짚고 넘어가면 될 것 같습니다. 홈 action과 listview. 


1. action bar의 홈 action 

홈 action을 설정하는 코드를 보게 되면, 

actionBar.setHomeAction(new IntentAction(this, MainActivity.createIntent(this), R.drawable.ic_title_home_default));

로 되어있는데요. IntentAction 이라는 객체는 Context, intent, int를 매개변수로 받는 생성자를 가지고있습니다. 여기서 intent를 넘겨줄때 MainActivity의 static 메소드를 호출하여, 인텐트를 넘겨주고있습니다.

- MainActivity.java -

    public static Intent createIntent(Context context) {
        Intent i = new Intent(context, MainActivity.class);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        return i;
    }


자 그럼 여기서, 홈 acion, 즉 홈키를 누르면 뒤로 가야하는데, 왜 인텐트를 생성해서 넘겨주느냐? 하는 문제점이있는데요. 여기에서 제가 짚고 넘어가고 싶었던 인텐트의  속성(?)이 키워드입니다.

만약 소스코드에서 intent에 addFilags 를 하지않았다고 가정하게되면, ActivityStack이 아래와 같이 될것입니다. 

(출처 : 휴휴휴님 블로그)

즉, 뒤로 가기와 같은 효과가 아니라 새로운 Activity가 하나더 생성되게 되는거죠. 이러한 문제점을 intent의 flag로 해결할 수 있습니다. 


아래는 intent에 FLAG_ACTIVITY_CLEAR_TOP이라는 FLAG를 사용한 ActivityStack입니다. 



FLAG_ACTIVITY_CLEAR_TOP 플레그는 실행하고자 하는 Acitivity가 존재할 경우, 해당 Activity 위에있는 모든 activity를 종료시켜 줍니다. 따라서 홈으로 돌아가는 듯한 효과를 받게 되는 거죠. 이 FLAG 외에도 여러가지 FLAG가 존재 하는데요. 휴휴휴님의 블로그에서 자세히 소개 되고있습니다. (안드로이드 알아두면 요긴한 FLAG_ACTIVITY 네가지 :: http://huewu.blog.me/110087045138?Redirect=Log&from=postView )


2. android-pulltorefresh

오픈소스의 listview  "setOnRefreshListener"라는 메소드를 통해서 유저가 새로고침을 하게 될 경우 해야할 작업을 실행 할 수 있도록 해줍니다. 하지만 여기서 OnRefreshListener 리스너는 실행완료까지 자동으로 해주는 것은 아닙니다. 실제 작업이 완료된 이후에. listview의 onRefreshComplete() 메소드를 호출해주어야하죠.

이 소스코드에선 setOnRefreshListener 메소드를 통해 GetDataTask 를 실행하는 OnRefreshListener 를 구현한 임시 객체를 넘겨주고, 사용자가 새로고침(스크롤이 맨위로 올라가있는 상황에서 아래로 내렸을때) GetDataTask를 실행합니다.

GetDataTask 클래스는 AsyncTask 클래스를 상속받은 객체이며, doInBackground 메소드에선 하는 일없이, 2초간 쓰레드를 멈추후 작업을 종료합니다. 작업이 종료되면 onPostExecute 메소드가 호출되게 되는데 이때 adapter에서 사용하는 객체의 맨 처음 부분에 "Added after refresh..."라는 데이터만 추가한뒤에 listview의 onRefreshComplete() 메소드를 호출합니다.


여기까지가 두번째 Acitivity를 생성하여 호출하는 작업입니다. 마지막으로 Activity를 추가하였으니, 매니페스트 파일을 수정하여줍니다. 


- AndroidManifest.xml -

    <activity
            android:name=".ListViewActivity"
            android:label="@string/title_activity_list" >
    </activity>


(위 부분을 application 태그 안에다 추가 해주시면 됩니다. )


여기까지가, 기본뷰를 만들고, Activity를 추가하여 listview를 만드는 과정이었습니다. 여기까지 된 전체 소스를 올려드리도록 하겠으며, 다음 포스팅에선 두개의 Activity로 되어있는 구성을 하나의 Activity로 구성하면서, Tabbar로 두개의 화면을 보여줄수 있도록 수정하는 작업을 하도록 하겠습니다. 


현재 까지 작업된 전체 소스 파일.

AndroidUI.zip







posted by 엡뽀