어제 드디어 2달간 도전했던 서울시 공공앱 공모전에 응모를 하고 무엇을 다시 시작해 볼까하다가 잠시 다른 차기APP를 만들 것에 대한 아이디어를 정리하는 동안은 지금까지 읽은 책과 인터넷자료를 정리해서 우리 회사 후배들에게 하게 될 강의를 일단 이곳에 올려보며 정리를 해볼까하는 생각을 하며 가능하면 하루에 한 컨셉은 이곳에 올려볼까하는 다짐을 해본다.

그 첫 발걸음으로는 안드로이드의 특징과 장단점이라는 부분이다. 현재 구글의 안드로이드는 애플의 iOS와 함께 모바일 플랫폼을 지배하는 양대산맥이며 삼성이 있는 우리나라에서는 사실 애플앱개발자보다는 안드로이드 개발자를 지향하는 사람이 훨씬 많은 게 사실이다. 그런데 세계적으로는 전에 어떤 자료에 보니 프로그램언어의 비율중 안드로이드는 9%대였고 objective -c는 의외로 8%였다. 좀더 다양한 언어들이 서로의 장점을 가지고 발전해 가기를 바래보며 안드로이드도 애플 iOS도 더 좋은,편리한 플랫폼으로 발전해가기를 빌어본다.

이렇게 안드로이드는 'Open Software,Open Device,Open Ecosystem'을 추구한다. 이러한 개방성 과 무료라는 점 그리고 애플의 플랫폼과 비슷하게 업데이트 유통 결제등 개발자가 골치아파하는 문제를 플랫폼이 알아서 해준다는 점이 이렇게 성공할 수 있는 요소가 된 것이 아닐까?

1강_안드로이드설명과 설치환경구축.pptx

 

 

액션바 taps+swipe에서 잠시 언급했던 fragment에 대해 이번엔 정리해 보도록 하겠습니다.

안드로이드 플랫폼 3.0 버전인 허니컴Honeycomb부터 큰 화면의 태블릿을 위해 도입된 대표적인 컴포넌트가 프래그먼트(Fragment)와 액션바(ActionBar)입니다.그 중 액션바는 이전 게시판에서 이야기했으니 오늘은 프래그먼트에 대해서입니다.

 프래그먼트 개요

만약 스마트 폰 앱을 개발할 때 세로모드(Portrait)에서는 단순하게 화면을 구성하지만 가로모드(Landscape) 화면 구성을 좀더 다양한 화면으로 구성 하고 싶다면 어떻게 할지 고민할 수 있습니다. 또는 해상도나 디바이스의 스크린크기, 디바이스 종류에 따라서 보여지는 것들을 다르게 구성하고 싶어할 수도 있습니다.

안드로이드에서는 이러한 요구사항을 만족시켜줄 수 있는 것을 fragment라는 개념으로 추가하게 되었습니다.

안드로이드 3.0이전 버전에서는 한 화면에 보이는 모든 것을 관장하는 것이 Activity라는 개념이였는데 이러한 Activity는 하나의 화면에 여러개 사용할 수 없게 설계가 되어있습니다.

그러나 하나의 액티비티로 상호작용하는 것은 큰 화면의 기기에서 비효율적이며 자원 낭비가 심하고 또한 일부 화면을 위한 자원을 재사용할 수 없고, 다양한 내용을 표시하려면 구성이 매우 복잡했습니다.

그래서 하나의 화면에 Activity와 비슷한 개념을 가지면서도 여러가지 화면을 넣을 수 있는 방법으로 fragment가 등장하게 되었습니다. 

 프래그먼트 특징

1) 프래그먼트는 액티비티 조각 혹은 서브액티비티(subactivity)

2) 하나의 액티비티에서 다수의 프래그먼트를 결합하여 다중 패널multi-pane UI를 생성할 수 있음

3) 여러 액티비티에서 하나의 프래그먼트를 재활용 가능

4) 프래그먼트 자신만의 생명주기 가짐

5) 입력 이벤트를 받아들이며, 액티비티가 실행하는 동안 동적으로 추가 혹은 삭제 가능

6) activity 안에서만 존재할 수 있고 단독으로 존재할 수 없다.

7) activity 안에서 다른 view와 함께 존재 가능

8) back stack을 사용가능

9) 반드시 default 생성자 존재

 프래그먼트 디자인 철학

애플리케이션을 태블릿과 핸드셋에 모두 지원하도록 설계하고자 한다면 화면의 사이즈에 따라 최적의 UX을 맛볼 수 있도록 프래그먼트를 다양한 레이아웃 구성에 재사용할 수 있습니다.

작은 화면사이즈 기기에는 하나의 액티비티에 하나의 프래그먼트를 사용하는 1-패널 UI를 제공하고, 태블릿과 같은 큰 화면사이즈 기기에서는 2개의 프래그먼트를 하나의 액티비티에 조합하여 2-패널UI를 제공하면 됩니다. 

 프래그먼트 생명주기

● 활성resumed 상태 : 실행 중인 액티비티에서 프래그먼트가 보이는 상태

● 중지paused 상태 : 다른 액티비티가 포그라운드 상태이며 포커스를 가지고 있지만 프래그먼트가 거주하는 액티비티가 여전히 보이는 상태

● 정지stopped 상태 : 프래그먼트가 보이지 않는다. 호스트 액티비티가 정지되거나 프래그먼트가 액티비티에서 제거되고 백스택에 추가되어 있는 상태 정지된 프래그먼트는 여전히 살아 있어 모든 상태와 멤버 정보가 시스템에 보관되어 있으나 사용자에게 더 이상 보이지 않고 액티비티가 종료되면 프래그먼트도 같이 종료됨

아래 소스에서 사용한 메소드는 onActivityCreated,onResume,onPause, onCreateView정도여서 http://blog.saltfactory.net/190 의 설명을 인용하도록 하겠습니다.

● onAttach()

onAttach() 콜백 메소드는 fargment가 activity에 추가되고 나면 호출된다. 이때 Activity가 파라미터로 전달되게 된다. Fragment는 Activity가 아니다. 다시말해서 Activity는 Context를 상속받아서 Context가 가지고 있는 많이 있지만 Fragment는 android.app 의 Object 클래스를 상속받아서 만들어진 클래스이다. 그래서 Fragment에서는 Context의 기능을 바로 사용할 수 없다. 뿐만 아니라 Fragment는  Activity 안에서만 존재하기 때문에 Activity를 onAttach() 콜백으로 받아올 수 있다.

 public void onAttach(Activity activity) {
      super.onAttach(activity);
 }



onCreate()

프래그먼트가 생성될 때 호출된다. 프래그먼트가 중지 혹은 정지된 후 재개될 때 보유하기 원하는 프래그먼트의 필수 컴포넌트을 초기화한다.

Fragment의 onCreate() 메소드는 Activity의 onCreate() 메소드와 비슷하지만 Bundle을 받아오기 때문에 bundle에 대한 속성을 사용할 수 있다.

 	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}


onCreateView()

Fragment의 onCreateView()는 Fragment에 실제 사용할 뷰를 만드는 작업을 하는 메소드이다. LayoutInflater를 인자로 받아서 layout으로 설정한 XML을 연결하거나 bundle에 의한 작업을 하는 메소드이다. 

	public View onCreateView(LayoutInflater inflater, ViewGroup container,
	                Bundle savedInstanceState)
	{
	        view = inflater.inflate(R.layout.table, container, false);
	        return view;
	}


onActivityCreated()

onActivityCreate() 메소드는 Activity에서 Fragment를 모두 생성하고 난 다음에 (Activity의 onCreate()가 마치고 난 다음)에 생성되는 메소드이다. 이 메소드가 호출될 때에서는 Activity의 모든 View가 만들어지고 난 다음이기 때문에 View를 변경하는 등의 작업을 할 수 있다.그러나, fragment에서 생성된 view의 size를 알려고 하니 이 메소드에서는 getWidth가 0으로 나와 따로 메소

    public void onActivityCreated(Bundle savedInstanceState) {
    	//Log.d(TAG,"onActivityCreated");
	    super.onActivityCreated(savedInstanceState);
    }


onStart()

이 메소드가 호출되면 화면의 모든 UI가 만들어진 지고 호출이 된다.

    public void onStart(){
    	super.onStart();
    }


onResume()

이 메소드가 호출되고 난 다음에 사용자와 Fragment와 상호작용이 가능하다. 다시 말해서 이 곳에서 사용자가 버튼을 누르거나 하는 이벤트를 받을 수 있게 된다.

	public void onResume() {
		super.onResume();

		⁄⁄mStatus.setText("현재 상태 : 서비스 시작");
		cellwidth = new int[5];
		desity = this.getResources().getDisplayMetrics().density;
		appendHeader();
		appendRowBlank();
		datainfo = selectData();
		appendRow(datainfo);	
		ViewTreeObserver vto = headerView[0].getViewTreeObserver();
		vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
		  @SuppressWarnings("deprecation")
		@Override
		  public void onGlobalLayout() {
		    ⁄⁄Log.d(TAG, "Height = " + headerView[0].getWidth() + " Width = " + tv[0][0].getWidth());
		    ViewTreeObserver obs = headerView[0].getViewTreeObserver();
		    resizeRow();
		    obs.removeGlobalOnLayoutListener(this);
		  }
		});		
		
	}	


onPause()

이 메소드는 Fragment가 다시 돌아갈 때 (Back) 처음으로 불려지는 콜백 메소드이다. 

    
   @Override
    public void onPause() {
        super.onPause();
    }


onSaveInstanceState()

이 메소드에서는 Activity와 동일하게 Fragment가 사라질때 현재의 상태를 저장하고 나중에 Fragment가 돌아오면 다시 저장한 내용을 사용할 수 있게해주는 메소드이다.

    
    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        super.onSaveInstanceState(savedInstanceState);
        savedInstanceState.putInt("text", "savedText");
    }


● onStop()

Fragment의 onStop() 메소드는 Activity의 onStop()메소드와 비슷하다. 이 콜백 메소드가 호출되면 Fragment가 더이상 보이지 않는 상태이고 더이상 Activity에서 Fragment에게 오퍼레이션을 할 수 없게 된다.

    
    @Override
    public void onStop() {
        super.onStop();
    }


onDestroyView()

Fragment의 View가 모두 소멸될 때 호출되는 콜백 메소드이다. 이때 View에 관련된 모든 자원들이 사라지게 된다.

    
    @Override
    public void onDestroyView() {
        super.onDestroyView();
    }


onDestroy()

Fragment를 더이상 사용하지 않을 때 호출되는 콜백 메소드이다.  하지만 Activity와의 연결은 아직 끊어진 상태는 아니다.

    @Override
    public void onDestroy() {
        super.onDestroy();
    }


onDetach()

Fragment가 더이상 Activity와 관계가 없을 때 두 사이의 연결을 끊으며 Fragment에 관련된 모든 자원들이 사라지게 된다.

   @Override
    public void onDetach() {
       super.onDetach();
       activity = null;
    }

 전체소스

PublicWifi_0409.zip

참고사이트

http://developer.android.com/guide/components/fragments.html

http://blog.saltfactory.net/190

swipe기능이 뭔지 어색할지 모르지만 스마트폰 사용자라면 지금도 많이 사용하고 있는 기능입니다. 특히 안 가르쳐줘도 아이들은 정말 잘 사용하는 기능이죠. 손가락으로 클릭후 오른쪽/왼쪽으로 움직하면 화면이 변경되는 기능입니다.

Android 3.0 부터 제공되는 Swipe Views와 Tabs + Swipe를 편리하게 생성하고 사용할 수 있습니다. 

프로젝트 생성시 다른 프로젝트와 조금 다르게 설정만 해주면 됩니다.

그럼 작성도 안 했는데 많은 소스의 내용이 생깁니다. 왠지 뿌듯하지만 작동로직을 제대로 이해하지 못하면 남이 짠 소스이니 구현에 힘이 들 수 있습니다.

이제부터 자동생성 소스 중 변경부분을 위주로 설명하도록 하겠습니다.

 

 변경전 소스

		@Override
		public Fragment getItem(int position) {
			⁄⁄ getItem is called to instantiate the fragment for the given page.
			⁄⁄ Return a DummySectionFragment (defined as a static inner class
			⁄⁄ below) with the page number as its lone argument.
			Fragment fragment = new DummySectionFragment();
			Bundle args = new Bundle();
			args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
			fragment.setArguments(args);
			return fragment;
		}

 변경후 소스

		@Override
		public Fragment getItem(int position) {
			Fragment fragment = null;
			
			⁄⁄ getItem is called to instantiate the fragment for the given page.
			⁄⁄ Return a DummySectionFragment (defined as a static inner class
			⁄⁄ below) with the page number as its lone argument.
			switch (position) {
			case 0:			
				fragment = new TabOne();
				break;
			case 1:			
				fragment = new TabTwo();
				break;
			}
			return fragment;
		}

메인activity는 이렇게 만 변경하고 물론 tab이 기본이 3개인데 2개 바꾸는 기본적인 변경의 내용은 그냥 생략했습니다. 보면 직관적으로 알 수 있기 때문에 전체 소스를 참고하시면 될 듯 합니다.

public class TabOne extends Fragment implements MapView.OpenAPIKeyAuthenticationResultListener, 
MapView.MapViewEventListener,
MapView.CurrentLocationEventListener,
MapView.POIItemEventListener {

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
		super.onActivityCreated(savedInstanceState);

	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
	                Bundle savedInstanceState)
	{
	        view = inflater.inflate(R.layout.map, container, false);
	        linearLayout = (LinearLayout)view.findViewById(R.id.maplayout);
	}	

}

public class TabTwo extends Fragment {

	@Override
	public void onActivityCreated(Bundle savedInstanceState) {
	    super.onActivityCreated(savedInstanceState);
	}

	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
	                Bundle savedInstanceState)
	{
	        view = inflater.inflate(R.layout.table, container, false);
	        return view;
	}
}

이렇게 2개의 fragment를 생성해주면 됩니다. 프래그먼트에 대해서는 다음에 한번 이론적으로 접근해보고 지금은 이렇게 activity와 같은 식으로 추가해주면 아래와 같은 기능을 가진 앱이 만들어집니다.

그래도 이 기능은 기본 소스를 만들어주어서 참 편하게 구현할 수 있는 기능입니다.

 

 

 

PublicWifi_0409.zip

아직 생각한 모든 기능을 구현한 것은 아니지만 이 주제는 다 구현했으니 전체 소스도 첨부합니다.

액션바에 아래와 같이 검색창을 넣을 수 있는데 이를 위해서는 3가지 작업이 필요하다.

1) menu xml에 SearchView item추가

    <item
        android:id="@+id⁄action_search"
 
        android:showAsAction="ifRoom"
        android:actionViewClass="android.widget.SearchView"
        android:title="@string⁄search"
       android:icon="@drawable⁄search"        
    ><⁄item>

2) onCreateOptionsMenu 에 search view 항목추가 및 Listener 설정

@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.activity_lost, menu); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) { searchItem = menu.findItem(R.id.action_search); searchView = (SearchView) searchItem.getActionView(); searchView.setQueryHint("물품명 또는 분류"); searchView.setOnQueryTextListener(queryTextListener); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); if(null!=searchManager ) { searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName())); } searchView.setIconifiedByDefault(true); } return true; }

 

개발참고사이트 : http://developer.android.com/reference/android/widget/SearchView.html 

 setQueryHint(CharSequence)

 쿼리 필드가 비어있을 때 나타나는 문장 설정

 setOnQueryTextListener(SearchView.OnQueryTextListener listener)

 쿼리 변경시 사용자 액션의 listener 설정

setSearchableInfo(SearchableInfo searchable)  SearchableInfo 설정
 setIconifiedByDefault(boolean iconified)  검색창의 기본상태 설정
true : 필드가 보임
false : 아이콘으로 보임

3) 리스너에 처리로직 구현

	private OnQueryTextListener queryTextListener = new OnQueryTextListener() {
		@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
		@Override
		public boolean onQueryTextSubmit(String query) {
			⁄⁄ TODO Auto-generated method stub
			⁄⁄searchItem.collapseActionView();
			⁄⁄Log.d(TAG,"onQueryTextSubmit");
			Cursor mCount= db.rawQuery("select count(*) from datainfo where GetName like '%" + query+"%' or cate like '%"+ query+"%'", null);
			mCount.moveToFirst();
			count= mCount.getInt(0);
			mCount.close();
			if(count <=0){
				Toast.makeText(LostActivity.con, "검색된 데이타가 없습니다.", Toast.LENGTH_LONG).show();
				return false;
			}
			datainfo = new DataInfo[count];
			Cursor result = db.rawQuery("SELECT * from datainfo where GetName like '%" + query+"%' or cate like '%"+ query+"%' order by GetDate desc", null);
			result.moveToFirst();	
			int i =0;
			while (i<count){
				datainfo[i] = new DataInfo();
				datainfo[i].SetLostId(result.getString(1));
				datainfo[i].SetLostName(result.getString(2));
				datainfo[i].SetLostURL(result.getString(3));
				datainfo[i].SetLostDate(result.getString(5));
				datainfo[i].SetLostTitle(result.getString(4));
				datainfo[i].SetTakePlace(result.getString(6));
				datainfo[i].SetTakeContact(result.getString(7));
				datainfo[i].SetLostPos(result.getString(9));
				datainfo[i].SetLostPlace(result.getString(10));
				datainfo[i].SetLostThing(result.getString(11));
				datainfo[i].SetLostStatus(result.getString(12));
				datainfo[i].SetLostImageUrl(result.getString(14));
				i++;
				result.moveToNext();
			}
			result.close();	
			appendRow(datainfo);
			resizeRow(count);
			⁄⁄Log.d(TAG,"onQueryTextSubmit"+count);
			imm= (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
			imm.hideSoftInputFromWindow(searchView.getWindowToken(), 0);
			searchView.setQuery("", false);
			searchView.setIconified(true);
			⁄⁄Toast.makeText(LostActivity.con, "onQueryTextSubmit:["+count+"]", Toast.LENGTH_LONG).show();
			return false;
		}
		@Override
		public boolean onQueryTextChange(String newText) {
			// TODO Auto-generated method stub
			return false;
		}
	};

 

 

Lost_completed.zip

 

 

 

안드로이드 3.0, 허니컴(Honeycomb)에서는 태블릿 단말에 최적화된 컴포넌트들이 많이 추가되었는데, 프래그먼트(Fragment)와 함께 허니컴에서 추가된 대표적인 UI 컴포넌트 중 하나가 바로 액션바(Action bar)입니다.

기존 안드로이드 APP의 TitleBar가 단순한 제목의 표시나 간단한 정보만을 표시했다면 액션바는 아래와 같은 다양한 기능을 제공하며 4.0부터는 메뉴버튼까지 대체합니다.

 

 액션바의 주요기능

1) 타이틀바의 기능인 제목 표시 및 간단한 정보 표현

2) 사용자의 현재 위치 식별

3) 각종메뉴-탐색메뉴,액션항목을 통한 단축메뉴-제공

4) Navigation 지원

 

 액션바의 주요목적

1) APP의 이름,정보 와 사용자 위치 식별하기 위한 전용공간 제공

2) 다른 APP사의 일관된 네비게이션과 뷰의 세분화 제공

3) 검색,생성 공유와 같은 주요 액션에 대한 용이한 젭근 및 예측 가능 접근

 

 액션바의 주요UI

 

1. 앱 아이콘

: 애플리케이션 아이콘은 애플리케이션에 아이덴티티를 부여합니다. 원할 경우 다른 로고나 브랜드로 교체할 수도 있습니다. 중요: 만약 애플리케이션이 현재 최상위 화면을 표시하고 있지 않다면, 사용자가 상위 계층으로 이동할 수 있도록 애플리케이션 왼쪽에 상위 기호(Up caret)를 표시해야 합니다.

2. view control

: 만약 애플리케이션이 여러가지 뷰에서 데이터를 표시하고 있다면, 액션 바의 이 부분은 사용자가 뷰 간을 전활할 수 있도록 해줍니다. 뷰 전환 컨트롤에는 드롭다운 메뉴나 탭 컨트롤 등이 있습니다. 만약 애플리케이션이 여러가지 뷰를 지원하지 않는다면, 이 영역을 애플리케이션 타이틀이나 더 긴 브랜드 정보 등을 표시하는데 사용할 수도 있습니다.

 3. Action button

: 액션 섹션에서 애플리케이션의 중요한 액션들을 표시합니다. 액션 바에 들어갈 공간이 없는 액션들은 자동으로 액션 오버플로우 속으로 이동합니다.

4. Action overflow

: 덜 자주 사용하는 액션은 액션 오버플로우에 배치합니다.

 

 액션바의 사용시 주의사항

ActionBar, 액션바를 사용하기 위해서는 targetSdkVersion에 11 이상을 지정하셔야 합니다.

1
<uses-sdk android:targetSdkVersion="11" />



minSdkVersion은 하위 버전에 대한 호환을 고려하지 않을경우, 11이상으로 해두시면 됩니다.

이렇게 targetSdkVersion을 API 11이상으로 설정하시면, 자동적으로 액션바가 사용이 됩니다.

 

 Split action bar

안드로이드 4.0부터 split action bar라고 불리는 추가적인 모드를 사용할 수 있다. 분할 액션바를 사용하면 화면 하단에 별도의 bar가 보이며, 좁은 화면에서 액티비티가 실행되더라도 모든 액션 항목을 보여준다. 액션바를분할하여 액션 항목을 분리하는 것은 상단에 내비게이션과 타이틀 요소를 남겨둔 채로 좁은 화면에서 합리적인 공간을 사용하여 모든 액션 항목을 표시한다. 그리고 다양한 기기의 화면 크기와 화면 회전에 고려한 APP을 만들 때 중요한 UI입니다.

분할 액션바를 활성화하려면 uiOptions="splitActionBarWhenNarrow"를 매니페스트 파일의 <activity> 혹은 <application> 엘리먼트에 추가하면 됩니다.

 

1. 메인 액션바

2. 상단바

3. 하단바

사용자가 빠르게 애플리케이션에서 제공하는 뷰 간을 전환할 수 있도록, 상단 바에 탭이나 스피너를 배치하고 액션과 액션 오버 플로우를 표시하려면 하단 바를 배치하는 방법이 유용한 UI가 될 수 있습니다.

 

아직 split action bar는 사용을 해보지 못해서 이론적인 부분만 추가해 두었습니다.

나의 첫 서울시 공공앱을 이제 마켓으로 올릴 수 있을 정도로

완성된 듯 하다.

 

 

1. 사용에 관련된 주요기능

1) GPS가 켜있는 상태에서는 현재 위치 기준으로 가까운 주차장부터 찾아서 정렬

2) 서울시 공영주차장 19개의 주차장의 현재 잔여주차대수를 일괄으로 볼 수 있음

3) 주차장을 클릭하면 위치를 지도로 위치 확인 가능

4) 자세한 내용은 전화번호로 전화하여 문의 가능

2. 아쉬운 점

1) 좀더 많은 데이타(주차요금 등..)이 없음이 좀 아쉽다.

2) 보다 많은 주차장의 정보를 볼 수 있으면 좋으련만 19개의 주차장만 데이타를 제공한다.

3. 사용된 기술적 요소

1) html  request

- 서울시 공공API사용시 와 다음 로컬 API사용시 사용

- 아래는 서울시 공공API사용시 예제

 			  try{
				  URL url = new URL(urls[0]);
				  HttpURLConnection conn = (HttpURLConnection)url.openConnection();
				  if(conn != null){
					  conn.setConnectTimeout(10000);
					  conn.setUseCaches(false);
			        
					  if(conn.getResponseCode() == HttpURLConnection.HTTP_OK){
						  BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));      
						  for(;;){
							  String line = br.readLine();
							  if(line == null) break;
							  html.append(line+"\n");     
						  }     
						  br.close();
					  }
					  else{
			     
					  }
					  conn.disconnect();
				  }   
			  }
			  catch(Exception ex)
			  {
				  Log.e(TAG,"DownloadHtml ex=["+ex+"]"); 
				  return null;
			  } 

2) AsynTask기능

- 안드로이드 3.0(허니콤)부터는 network을 사용시에는 asyntask를 사용하여 처리가 늦어질 때를 대비하여 화면반응속도를 따로 처리하게 하여 사용자에게 앱이 죽은 듯 보여짐을 방지하고자 한다.

3) xml parser

- 서울공공API와 다음로컬 API시 xml로 받아서 분석하는 로직

		//API 요청 및 반환
		URLConnection conn = url.openConnection();
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		DocumentBuilder builder = factory.newDocumentBuilder();
		Document doc = builder.parse(conn.getInputStream());
		
		//channel노드를 객체화 하기
		Node node = doc.getElementsByTagName("channel").item(0);
		for (int i=0 ;i< node.getChildNodes().getLength();i++) {
			Node channelNode = node.getChildNodes().item(i);
			String nodeName = channelNode.getNodeName();
			
			//item 노드들일 경우
			if ("item".equals(nodeName)) 
			{
				//item노드의 자식노드를 검색
				for (int j=0 ;j< channelNode.getChildNodes().getLength();j++) 
				{
					Node itemNode = channelNode.getChildNodes().item(j);
					//title노드 일 경우 출력
					if("lng".equals(itemNode.getNodeName())){
						xy[0]= itemNode.getTextContent();
						
					}else if("lat".equals(itemNode.getNodeName())){
						xy[1]= itemNode.getTextContent();
						
					}	
				}
			}

4) SQLite

- 각 주차장의 데이타를 DB에 저장하는 데 사용함

5) tableview

- scrolling하는 기능의 추가와 헤더와 contents부분의 column사이즈를 맞추는 문제와 click event부여하는 문제 어느 것 하나 쉽지만은 않았음

6) 서울시 공공API 사용

- 서울시는 여러 공공의 데이타(http://data.seoul.go.kr/)를 시민들이 사용하기 편리하도록 공개하고 있음 이 앱은 이 데이타를 기반으로 만들어진 앱임

 7) 다음 API사용

- 다음의 로컬 API와 지도 API사용

		mapView = new MapView(this);
		
		mapView.setDaumMapApiKey("bcc6844e5b1aea2eda0dd7b52860dc30e3b97950");
		mapView.setOpenAPIKeyAuthenticationResultListener(this);
		mapView.setMapViewEventListener(this);
		mapView.setCurrentLocationEventListener(this);
		mapView.setPOIItemEventListener(this);

		mapView.setMapType(MapView.MapType.Standard);
		Log.d(TAG,"[1]dlng:["+ dlng + "],["+dlat +"]");
		// Move and Zoom to
		
		mapView.setMapCenterPointAndZoomLevel(MapPoint.mapPointWithGeoCoord(dlat, dlng),1, true);
		
		MapPOIItem poiItem1 = new MapPOIItem();
		poiItem1.setItemName(sname);
		
		poiItem1.setMapPoint(MapPoint.mapPointWithGeoCoord(dlat, dlng));
		poiItem1.setMarkerType(MapPOIItem.MarkerType.BluePin);
		poiItem1.setShowAnimationType(MapPOIItem.ShowAnimationType.NoAnimation);
		poiItem1.setShowCalloutBalloonOnTouch(true);
		poiItem1.setTag(153);	
		mapView.addPOIItem(poiItem1);
		mapView.fitMapViewAreaToShowAllPOIItems();
		linearLayout.addView(mapView);	

8) Action Bar에  refresh 메뉴 추가

9) intent

- 상세조회시 페이지를 다른 class로 하여 intent를 사용하여 call했으며 전화를 calling시에도 사용

10) 현위치 도출

- GPS를 이용하여 최근저장 위치를 처음에는 불러주고

나중에 이동시마다 10분간격으로 현위치를 저장하고 이에 따른 거리를 계산하도록 함

 

SeoulParking_20130320 (2).zip

+ Recent posts