2011년 8월 31일 수요일

Android 3.0 Fragments Example


Fragment을 적용한 Sample App을 만들어보기로 하겠습니다.

App의 형태는 아래와 같습니다.
  1. 좌측은 메뉴 형태로 각 사이트로 이동할 수 있는 버튼이 4개 있습니다.
  2. 버튼을 클릭하면 우측 Webview가 해당 사이트로 이동합니다.
  3. 처음 시작은 m.nate.com 에서 시작됩니다.



위 화면을 구성하기 위해서는 외곽을 구성하는 하나의 Activity와 두 개의 Fragment을 작성해야 합니다.



Step 1: AndroidMainfest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.daddycat.fragment"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="12" />

<application
android:icon="@drawable/icon"
android:label="@string/app_name">
<activity
android:name=".FirstFragmentsLayoutActivity"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>
<supports-screens
android:largeScreens="true"
android:normalScreens="true"
android:anyDensity="true" />
<uses-permission android:name="android.permission.INTERNET" />
</manifest>

Step 2:  Activity을 구성하는 default_fragment_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<fragment
android:id="@+id/menu"
class="com.daddycat.fragment.FirstFragmentsLayoutActivity$menuFragment"
android:layout_width="400px"
android:layout_height="fill_parent" />


<FrameLayout
android:id="@+id/details"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="?android:attr/detailsElementBackground" />
</LinearLayout>

Step 3: Menu Fragment Layout, menu_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#bbbbbb">


<Button
android:id="@+id/naver"
android:layout_width="150px"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="네이버"
android:tag="m.naver.com" />


<Button
android:id="@+id/daum"
android:layout_width="150px"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="다음"
android:tag="m.daum.net" />


<Button
android:id="@+id/google"
android:layout_width="150px"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="구글"
android:tag="m.google.com" />


<Button
android:id="@+id/yahoo"
android:layout_width="150px"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="야후"
android:tag="w.yahoo.co.kr" />

</LinearLayout>

Step 4: Detail Fragment Layout, detail_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<WebView
android:id="@+id/mainWebkit"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="none" />

</LinearLayout>

Step 5: Activity & Fragments, FirstFragmentsLayoutActivity.java
package com.daddycat.fragment;

import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.webkit.CookieSyncManager;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;

public class FirstFragmentsLayoutActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.default_fragment_layout);

}

public static class menuFragment extends Fragment {
boolean mDualPane;
private Button naver;
private Button daum;
private Button google;
private Button yahoo;

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

naver = (Button) getActivity().findViewById(R.id.naver);
daum = (Button) getActivity().findViewById(R.id.daum);
google = (Button) getActivity().findViewById(R.id.google);
yahoo = (Button) getActivity().findViewById(R.id.yahoo);

naver.setOnClickListener(new MenuOnClickListener());
daum.setOnClickListener(new MenuOnClickListener());
google.setOnClickListener(new MenuOnClickListener());
yahoo.setOnClickListener(new MenuOnClickListener());

View detailsFrame = getActivity().findViewById(R.id.details);
mDualPane = detailsFrame != null
&& detailsFrame.getVisibility() == View.VISIBLE;
showDetailFragment("m.nate.com");
}

private void showDetailFragment(String index) {
if (mDualPane) {
DetailsFragment details = (DetailsFragment) getFragmentManager()
.findFragmentById(R.id.details);
details = DetailsFragment.newInstance(index);
FragmentTransaction ft = getFragmentManager()
.beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.menu_fragment, null);
}

private class MenuOnClickListener implements OnClickListener {

@Override
public void onClick(View v) {

showDetailFragment(v.getTag().toString());
}

}
}

public static class DetailsFragment extends Fragment {

public static DetailsFragment newInstance(String index) {
DetailsFragment f = new DetailsFragment();

Bundle args = new Bundle();
args.putString("index", index);
f.setArguments(args);

return f;
}

public String getShownIndex() {
return getArguments().getString("index", "m.nate.com");
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.detail_fragment, null);
}

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

WebView browser = (WebView) getActivity().findViewById(
R.id.mainWebkit);
browser.setWebViewClient(new MainWebViewClient());
WebSettings ws = browser.getSettings();
ws.setJavaScriptEnabled(true);
ws.setDefaultZoom(WebSettings.ZoomDensity.FAR);
browser.requestFocusFromTouch();
boolean ScrollBarEnabled = getActivity().getIntent()
.getBooleanExtra("ScrollBarEnabled", true);
if (!ScrollBarEnabled) {
browser.setVerticalScrollBarEnabled(false);
browser.setHorizontalScrollBarEnabled(false);
}
browser.loadUrl("http://" + getShownIndex());
}

private class MainWebViewClient extends WebViewClient {

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {

view.loadUrl(url);
return true;
}

@Override
public void onPageFinished(WebView view, String url) {
CookieSyncManager.getInstance().sync();

}
}
}
}

Android 3.0 Fragment

Fragment 소개

Application 개발자는 Android 3.0에 새롭게 추가된 Fragment를 이용하여 Application의 UI를
아이패드 처럼 FrameLayout으로 나눌 수 있게 되었습니다.

Fragment는 별도의 UI와 생명주기를 갖는 독립된 Application Component 이며, 특정 Device 혹은 Screen 해상도에 따라여러 개의 Fragment를 조합하거나 재배치 하는 방식으로 원하는 UI를 손쉽게 구성할 수 있습니다.

이전에도 ActivityGroup을 이용하여 복수의 Activity를 하나의 Activity에 담을 수 있었지만, 기본적으로 Activity는 독립적으로 동작하도록 설계되었기 때문에 ActivityGroup을 적절하게 활용하는 것은 쉬운 일이 아니었습니다.

지금까지 화면이 회전 되거나 설정 값이 변경됨에 현재 Activity가 Destroy 되고 이어 새로운 Activity가 생성되는 경우 두 Activity 인스턴스간에 데이터를 유지하기 위해서는 Activity.onRetainNonConfigurationInstance() 메서드를 활용해야 했습니다.  하지만 Fragment API를 활용하여, 특정 Fragment인스턴스에 적절한 플래그만 설정해주면 가능하게 되었습니다.

DialogFragment 클래스가 제공되어 Activity 라이프 사이클에 잘 부합되도록 다이얼로그 박스를 표시하는게 훨씬 수월해진다.

ListFragment클래스가 제공됩니다.  기존 ListActivity와 유사하지만, Fragmen 특성 상, 임의의 Activity에 손쉽게 포함될 수 있기 때문에 테이터 목록과 동시에 여러가지 추가 정보를 표시하기 적합합니다.

현재 실행중인 Activity에 포함되어 있는 모든 Fragment 인스턴스 정보는 해당 Activity의 'saved instance state’로 자동으로 저장되며, Activity가 잠시 종료되었다가 재 시작될때 자동으로 복원됩니다.

Fragment Lifecycle

Activity의 생명주기 메서드와 매우 유사한 형태를 띄고 있으며, 뷰 생성과 관련된 몇몇 메서드가 더 추가되어 있습니다.

onAttach(Activity)
Fragment가 Activity 레이아웃에 포함되는 순간 호출됩니다. Activity 레이아웃에 Fragment를 정적으로 배치했다면 Activity가 시작될 때 같이 호출되며, 동적으로 레이아웃에 추가할 땐 Fragment를 레이아웃에 추가하는 순간 호출됩니다.

onCreate(Bundle)
Activity의 onCreate() 콜백 메서드와 유사하게 Fragment가 최초로 생성될 때 호출됩니다.

onCreateView(LayoutInflater, ViewGroup, Bundle)
Fragment의 UI를 구성하는 뷰(View)를 반환합니다. UI를 가지지 않는 Fragment일 경우 null을 반환할 수도 있습니다.

onStart()
Fragment가 화면에 표시될 때 호출됩니다. 하지만, 아직 사용자와 상호작용은 할 수 없는 상태입니다.

onResume()
Fragment가 사용자와 상호작용을 할 수 있게 되었을 때 호출됩니다. 즉, Fragment가 완전히 화면에 표시되어 제 역할을 수행할 수 있게 된 상태입니다.

onPause()
Activity의 onPause()와 유사하게 Fragment가 사용자와 상호작용을 할 수 없게 될 때 호출됩니다. Fragment가 아직 화면에 표시되고 있는 상태이나, 다른 요소에 의해 Fragment가 가려져 상호작용을 하지 못하는 상태입니다.

onStop()
Fragment가 화면에서 보이지 않게 될 때 호출됩니다. Activity가 화면에서 보이지 않게 될 때 onStop() 메서드가 호출되는 것과 유사합니다.

onDestroyView()
Fragment가 화면에서 사라진 후, 뷰의 현재 상태가 저장된 후 호출됩니다. 여기에서 저장된 뷰의 상태는 Activity와 유사하게 Bundle 형태로 저장되며, 저장된 뷰의 상태는 onCreate() 및 onCreateView()에서 다시 불러들일 수 있습니다.

onDestroy()
Fragment가 더 이상 사용되지 않을 때 호출됩니다.

onDetach()
Fragment가 Activity 레이아웃에서 제거될 때 호출됩니다.

기존 Activity을 Fragment로 변경한다면.
  1. 화면 유형을 적절하게 잘 나누어 "fragmentlayout"를 구성한다.
  2. 두개로 분할된 화면이라면 전체 외각을 구성하는 하나의 Activity와 2개의 Fragment 로 구성된다.
  3. 기존에는 Actrivity을 상속 받았지만 Fragment를 상속 받아야 한다.
  4. Fragment는 “onCreate”대신 "oncreateView”로 변경해줘야 함. Layout 지정은 "inflater.inflate(R.layout.menu_fragment, null)" 이렇게
  5. onActivityCreated을 사용해서 이벤트 리스너나 view을 핸들링한다.
  6. Fragment는 Activity가 아니기 때문에 “findViewById”는 “getActivity().findViewById”로 변경
  7. FrameLayout는 "getFragmentManager().findFragmentById”로 찾는다.

블록체인 개요 및 오픈소스 동향

블록체인(block chain) 블록체인은 공공 거래장부이며 가상 화폐로 거래할때 발생할때 발생할 수 있는 해킹을 막는 기술. 분산 데이터베이스의 한 형태로, 지속적으로 성장하는 데이터 기록 리스트로서 분산 노드의 운영자에 의한 임의 조작이 불가...