1.. Android Application ์ํ ์ ์ง ๊ธฐ๋ฒ
์๋๋ Activity ์ life Cycle ์ด๋ค. Android ๋ Process ์ ๊ด๋ฆฌ๋ฅผ Android Frame Work์ด ์ํํ๊ธฐ ๋๋ฌธ์ ๊ฐ๋ณApplication ์์๋ ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ๋ฑ์ ์ํ ๊ธ์์ค๋ฌ์ด ์์คํ ์ ์ข ๋ฃ๋ฅผ ๋๋นํ ํ์๊ฐ ์๋ค.
Activity ์ ์์ฑ์ ์ํ ์์์ Loading ๋ฐ Setting ์onCreate()์์ App ์ด ์ข ๋ฃ์์ ํ์ํprocess ์ฒ๋ฆฌ๋ฅผ onPause() ์์ ํ๋ค๋ ๊ฒ์ ํ๋ฆฐ ์ด์ผ๊ธฐ๋ ์๋์ง๋ง onCreate์ onPause ์ ์ฝ๋๊ฐ ์ง์ฃผ๋๋ ๊ฒ์ ๋ง๊ณ ํ์คํ Application์ ์ํ์ ์ง๋ฅผ ์ํด์๋ ์๋์ ๋ ๊ฐ์ง ์ํ๋ฅผ ์ด์ฉํ ํ์๊ฐ ์๋ค.
onsaveInstanceState : Activity๊ฐ ์ข ๋ฃ๋๋ ์์ ์ ๋ถ๋ ค์ง๋ค. ์์๋ก๋ onPause() ๋ค์์ ์คํ
onRestoreInstanceState : Activity ๊ฐ ๋ค์ ํ๋ฉด์ผ๋ก ์ฌ๋ผ์ค๋ ๊ฒฝ์ฐ ๋ถ๋ ค์ง๋ค. onCreate ๋ค์ ์คํ
์์ ๋ ์ํ์์๋ Instance ์ ์ ์ฅ์ ์ํด Parcelable ์ ์์๋ฐ๋ Bundle ๊ฐ์ฒด๋ฅผ ์ด์ฉํ๋ฉฐ
์ด์ ๋ํ ์ค๋ช ์ ๋ค์ชฝ์์ ํ๋๋ก ํ๋ค.
- Fragment
Android 3.0 ์ดํ์์๋ ํ๋ฉด์ ์ฆ Activity ์ด๊ณ ๋ชจ๋ logic ์ฒ๋ฆฌ๋ฅผ Activity ์์์ ์ํ์ ํ์๋ค๋ฉด Android 3.0 ์ด์์ ๋ฒ์ ์์๋ Activity ์์ ๋ณต์๊ฐ์ ๋ณ๋์ ์๋ช ์ฃผ๊ธฐ๋ฅผ ๊ฐ๋Fragment ๋ฅผ
ํฌํจํ์ฌ ๊ฐ๋ฐํ๋๋ก UI ๊ฐ๋ฐ ์ฌ์์ด ๋ฐ๋์๋ค. ๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
– Fragment๋ฅผ ์์๋ฐ๋ ํด๋์ค๋ฅผ ์์ฑํ๋ค.
– ์์ฑํ Fragment ๋ฅผ layout ํน์ java ์ฝ๋๋ฅผ ํตํด Activity ์ ๋ฑ๋กํ๋ค.
(1) Activity ์ Fragment ๋ฑ๋กํ๊ธฐ
- A) Fragment Class ์ ์
Fragment ๋ Activity ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ผ๋ฐ Fragment , ListFragment ๋ฑ ๋ค์ํ ์ข ๋ฅ์ Fragment ๊ฐ ์กด์ฌํ๋ฉฐ, ๊ธฐ๋ณธ์ ์ธ Fragment ์ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ callback Class ๋ค์ ๊ฐ๋๋ค.
@Override
public void onAttach(Activity activity) {
super.onAttach(activity); }
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); }
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return tv;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onDetach() {
super.onDetach();
}
- B) layout XML ์ ๋ฑ๋กํ์ฌ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
<fragment class=”edu.jaen.android.fragment.layout.FragmentLayout$TitlesFragment”
android:id=”@+id/titles”
android:layout_width=”match_parent”
android:layout_height=”match_parent” />
- B) Java ์์ ๋์ ์ผ๋ก ํฌํจ์ํค๋ ๋ฐฉ๋ฒ
DetailsFragment details = new DetailsFragment();
details.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(android.R.id.content,
details).addToBackStack(null).commit();
@Sample@ : 1. Fragment ํด๋ ์ฐธ์กฐ
- Action Bar
API11 ๋ถํฐ ๊ธฐ์กด์ title bar์ ๋ฉ๋ด, tab ๋ฑ์ ๊ธฐ๋ฅ์ ์ถ๊ฐํ์ฌ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ ํฌํจํ Action Bar Class ๊ฐ ์ ๊ณต๋๋ค .๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
– menu ํํ๋ฅผ layout ํน์ java ์ฝ๋๋ก ์์ฑ
– activity ์ onCreateOptionsMenu, onOptionsItemSelected ์์ ์์ฑํ ๋ฉ๋ด ํน์ TAB์ Activity ์ ์ถ๊ฐํ๋ค.
(1) action bar ์ ๋ฉ๋ด ๋ฑ๋ก
- A) xml ์ ๋ฉ๋ด๋ฅผ ์ ์
Menu -> item -> menu(sub) -> item(sub)๊ณผ ๊ฐ์ ํ์์ผ๋ก xml ์ ์ ์ํ ์ ์๋ค.
<menu xmlns:android=“http://schemas.android.com/apk/res/android”
android:actionViewClass=“android.widget.HorizontalScrollView”>
<item android:id=“@+id/action_sort”
android:icon=“@android:drawable/ic_menu_sort_by_size”
android:title=“@string/action_bar_sort”
android:showAsAction=“always”>
<menu>
<item android:id=“@+id/action_sort_size”
android:icon=“@android:drawable/ic_menu_sort_by_size”
android:title=“@string/action_bar_sort_size”
android:onClick=“onSort”/>
<item android:id=“@+id/action_sort_alpha”
android:icon=“@android:drawable/ic_menu_sort_alphabetically”
android:title=“@string/action_bar_sort_alpha”
android:onClick=“onSort”/>
</menu>
</item>
</menu>
- b) java ์์ ๋์ ์ผ๋ก ์ถ๊ฐ
menu.add(“Normal item1”);
menu.add(“Normal item2”);
menu.add(“Normal item3”);
MenuItem actionItem = menu.add(“Action Button”);
actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
actionItem.setIcon(android.R.drawable.ic_menu_share);
(2) Activity ์์์ ์ฒ๋ฆฌ
- A) Menu Event ์ฒ๋ฆฌ
onCreateoptionMenu ์ onOptionsItemSelected Event API11 ์ด์ ๋ฒ์ ๊ณผ ๋์ผํ์ง๋ง
actionItem.setShowAsAction๋ฉ์๋๋ฅผ ์คํํจ์ผ๋ก์จ ActionBar ๋ก ๋ฉ๋ด๋ฅผ ์ฌ๋ ค ๋ณด๋ผ ์ ์๋ค.
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// java์์ ๋์ ์ผ๋ก ๋ฑ๋ก
menu.add(“Normal item3”);
MenuItem actionItem = menu.add(“Action Button”);
actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
actionItem.setIcon(android.R.drawable.ic_menu_share);
// xml layout inflating
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.actions, menu);
return true;
}
@Override
public booleanonOptionsItemSelected(MenuItem item) {
// ์ ํ๋ ๋ฉ๋ด์ ๋ํ ๊ธฐ๋ฅ ์ฒ๋ฆฌ
return true;
}
- B) Tab ์ถ๊ฐ
ActionBar ์ addTab ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ ๋์ ์ผ๋ก tab์ ์ถ๊ฐ ํ ์ ์์ผ๋ฉฐ Fragment์์ ์ฐ๋์ ํตํด API 11 ์ด์ TabActivity ๊ธฐ๋ฅ์ ๋์ฒด ํ ์ ์๋ค.
final ActionBar bar = getActionBar();
final int tabCount = bar.getTabCount();
final String text = “Tab ” + tabCount;
bar.addTab(bar.newTab().setText(text).setTabListener(new TabListener(new TabContentFragment(text))));
@Sample@ : ActionBar ํด๋ ์ฐธ์กฐ
- Loader
์ฝ๋ ์ฆ์์ฆ์ ์ถ๋ ฅ๊ฐ๋ฅํ๋๋ก ๊ฐ๋จํ ๋ฉ์๋๋ค์ ์ง์ํ๋ค. Thread ์ ์ ์ฌํ ๊ฐ๋ ์ผ๋ก ์๋๋ก์ด๋์์ ์ง์ํ๋ Loding์ ์ํ ํด๋์ค
(1) LoadManager ๋ฑ์ Implement
– implements OnQueryTextListener, LoaderManager.LoaderCallbacks
(2) init method ํธ์ถ
– getLoaderManager().initLoader(id, Bundle arg, callback);
(3) call back method ์ ์
A)onCreateLoader
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = Contacts.CONTENT_URI;
}
String select = “((” + Contacts.DISPLAY_NAME + ” NOTNULL) AND (”
+ Contacts.HAS_PHONE_NUMBER + “=1) AND (”
+ Contacts.DISPLAY_NAME + ” != ” ))”;
return newCursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + ” COLLATE LOCALIZED ASC”);
}
B)onLoadFinished
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mAdapter.swapCursor(data);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
C)onLoadReset
public voidonLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
@Sample@ : 8.LoaderCursor
- Intent
Intent ๋ Android Framework ๊ณผ ํต์ ํ๊ธฐ ์ํ ํต์ ๊ฐ์ฒด๋ก Android ์์ Intent๋ก ๋ค๋ฅธ Activity๋ฅผ ํธ์ถํ๋ ๊ณผ์ ์ ์๋์ ๊ฐ์ด ์ผ์ด๋๋ค.
(Activity -> Intent ํธ์ถ ->Android Frame Work -> Target Activity)
Android ๊ฐ Target Action์ ํธ์ถํ๋ ๋ฐฉ๋ฒ์ ๋ช ์์ ํธ์ถ๋ฐฉ๋ฒ๊ณผ ์๋ฌต์ ํธ์ถ๋ฐฉ์์ด ์๋ค.
๋ช ์์ ํธ์ถ๋ฐฉ๋ฒ์ package ๋ช ์ ์ง์ ์ง์ ํ์ฌ ํธ์ถํ๋ ๋ฐฉ์์ด๊ณ , ์๋ฌต์ ํธ์ถ๋ฐฉ์์ category, action, data ์ ์กฐ๊ฑด์ ๊ฐ์ง๊ณ broad casting ๋ฐฉ์์ผ๋ก ํธ์ถํ๋ ๊ฒ์ด๋ค.
(1) ๋ช ์์ ํธ์ถ๋ฐฉ์
ComponentName n=new ComponentName(“edu.diana.audio”,”edu.diana.audio.AudioAct”);
i.setComponent(n);
startActivity(i);-
(2) ์๋ฌต์ ํธ์ถ๋ฐฉ์
i.addCategory(Intent.CATEGORY_DEFAULT);
i.setAction(Intent.ACTION_VIEW);
i.setData(Uri.parse(“poscocctvmobapp:”));
startActivity(i);
(3) Android-manifest ์ค์
<intent-filter>
<action android:name=“android.intent.action.VIEW”/>
<category android:name=“android.intent.category.DEFAULT”/>
<category android:name=“android.intent.category.BROWSABLE”/>
<data android:scheme=“poscocctvmobapp” />
</intent-filter>
(4) Intent ํธ์ถ์ Flag ๋ฅผ ํตํ TASK ๊ด๋ฆฌ
Task ๋ android process ๋ค์ ์คํ ์์๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ๋งํ๋ค. ์ฌ์ด ์๋ก H/W back ๋ฒํผ์ ๋๋ฅผ ๊ฒฝ์ฐ ์ด์ ์ ์ฌ์ฉํ๋ App ๋ค์ ํ๋ฉด์๋จ์ผ๋ก ํธ์ถํ๋ ๊ฒ๊ณผ ๊ฐ์ ํ์์ ๋ณผ ์ ์๋ค.
์ด๋ฌํ task ๋ Android ActivityManager ์์ ์ํํ๊ณ ์์ผ๋ฉฐ, Task ๋ Intent ํธ์ถ ์ Flag ๊ฐ๊ณผ
Android-Manifest ์์LuchMode ๋ฅผ ์ ์ํจ์ผ๋ก์จ ์ปจํธ๋กค ํ ์ ์๋ค .
- A) flag
flag ๋ฅผ ํตํด์ task ๊ด๋ฆฌ ๊ฐ๋ฅ, bit์ฐ์ฐ์ผ๋ก ๋ณต์์ flag ์ธํ ๊ฐ๋ฅ
-intent.FLAG_ACTIVITY_RECORDER_TO_FRONT : ๊ฐ์ ๋์ ์๋ก ์ฌ๋ฆฐ๋ค.
-intent.FLAG_ACTIVITY_CLEART_TOP : ํธ์ถ ๋์ ์์ ์๋ task ์ญ์ (ํธ์ถ ๋์๊น์ง ์ญ์ ํ๊ณ
๋์์ ๋ค์ ๋ง๋ ๋ค)
– intent.FLAG_ACTIVITY_CLEART_TOP|intent.FLAG_ACTIVBITY_SINGLE_TOP : (ํธ์ถ ๋์์ ์ญ์ ํ์ง
์๊ณ ์๋ฅผ ์ ์ฒด ์ญ์ )
-intent.FLAG_ACTIVITY_NEW_TASK : ์๋ก์ด ํ ์คํฌ ์์ฑ, service ๋ฐbroadcast_receiver ์์
Activity๋ฅผ ์คํํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ
- B) LunchMode ย ย ย
-standard : ๋์ผํ ํ๋ก์ธ์ค๊ฐ ์ค๋ณตํ์ฌ ์์ผ์ ์๋ค.
– singleTop : ๋์ผํ ํ๋ก์ธ์ค๋ฅผ ์ฐ์์ผ๋ก ๋๋ฒ ๋๋ฅด๋ ๊ฒฝ์ฐ ๋์ผํ ๊ฒ์ ์คํ์ ์์ง ์์
– singleTask : ํธ์ถ๋ Activity ๋ฅผ ์์์ ์ผ๋ก ์๋ก์ด task์์ฑ
– singleinstance : ๋ ๋ฆฝ์ ์ผ๋ก ํ๋์ activity ๋ง ์กด์ฌํจ (ex : ๋ฐ์ณ)
Cf) lunchMode – task๋ช : ํ ์คํฌ ๋ช ์ ์ง์ ํ์ง ์์ผ๋ฉด(Activity-Task afifinity) ๊ธฐ๋ณธ์ ์ผ๋ก Package ๋ช ์ ๋ฐ๋ผ๊ฐ๋ค. task ๋ช ์ด ๊ฐ์ ๊ฒฝ์ฐ
- ์์๊ณต์
(1) ํ์ผ ์์ฒด๋ฅผ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ
– ๊ธฐ๋ณธ์ ์ผ๋ก DB, FILE ๋ฑ์ Linux ๊ถํ ์ ์ฑ ์ ๋ฐ๋ผ ๋ค๋ฅธ ์ดํ๋ฆฌ์ผ์ด์ ์์ ์ฝ์ ์ ์๋ค . ย ย
– ๊ธฐ๋ณธ์ ์ผ๋ก Cache, File, DB ๋ ์์ ์ Context ์์ญ์ ์ ์๋๋ค.
– ๋ค๋ฅธ Context ์ ์๋ฃ๋ฅผ ๊ฐ์ง๊ณ ์ถ๋ค๋ฉด. createPackageContext๋ฅผ ์ฌ์ฉํด์ ๋ค๋ฅธ ์ปจํ์คํธ๋ฅผ
์์ฑํด์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ทผํ ์ ์๋ค (๋จ, ๊ถํ์ ์์ด์ผ ํ๋ค. )
– ๋จ, ํ์ผ๋ง๋ค๊ธฐ ๋จ๊ณ์์(createPackageContext) ๊ถํ์ ์ฃผ๋ฉด ๋ค๋ฅธ ์ดํ๋ฆฌ์ผ์ด์ ์์ ์ง์
Access ๊ฐ ๊ฐ๋ฅํ๋ค.
– ํน์ ํ ํ๋ก์ ํธ๋ฅผ ์ง์ ํ์ฌ ์๋ก ์ ๊ทผ๊ฐ๋ฅํ๋๋ก ํ๊ณ ์ถ๋ค…-> userID ๋ฅผ ๊ณต์ ํด์ผ ํ๋ค.
android.os.Process.myUid(), Android_manifiest : shared user id ๋ฅผ ๊ณต์ ํ๋๋ก ํ๋ฉด ๋จ.
(2) jar ๋ฅผ ํตํ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ณต์
– ์๋๋ก์ด๋๋ ํ๋ ์์์ด๊ธฐ ๋๋ฌธ์ ์ ํด์ง ํด๋๋ง ๋น๋์์ ๋ฌถ๋๋ค.
– ํ์ธ ๋ฐฉ๋ฒ์ ํด๋์ A ๋ชจ์์ด ์๋์ง๋ฅผ ํ์ธํ๋ค.
– ๋ณดํต์ ๊ฒฝ์ฐ libs ์๋ jar ํ์ผ์ ํฌํจ์ํค๊ณ path ๋ฅผ ๊ฑธ์ด์ค๋ค.
(3) apk ํ์ผ ๊ณต์
– ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธํ : ํ๋ก์ ํธ ์ ํ – propoerties – android – isLib ์ฒดํฌ
– ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ : ํ๋ก์ ํธ ์ ํ – propoerties – android – add
(4) DB ๊ณต์ – Content-Provider ์ฌ์ฉ
DB์์ฒด๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ด ์๋ contentProvider๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์๋ค.
Android์์ ์ ๊ณตํ๋ ์ฃผ์๋ก๊ณผ ๊ฐ์ ๊ฒ๋ค์ด ์ด๋ฌํ ํํ๋ก ์ฌ์ฉ์์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๊ณ
์๋ค. Content Provider ๋ ์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ก ๋์ํ๋ค.
Activity ( contentResolver์ฌ์ฉ)
->URI(target์ง์ ) ,update(),delete(),query(),insert() ๋ฉ์๋ ์ฌ์ฉ
-> ContentProvider ๋ ํด๋น ๋ฉ์๋์ ๋ํ ์ฒ๋ฆฌ
.
– Content-Provider์ ์ด๋ฆ์ ๊ณ ์ ํด์ผ ํ๋ค.
-SQLLiteOpenHelper์ ๊ฒฝ์ฐ Android Frame work ์์ ๊ด๋ฆฌํ์ง ์๋ ํด๋์ค์ด๋ค.
– ๊ทธ๋ ๊ธฐ ๋๋ฌธ์content-provider ๋ฅผ ์์๋ฐ์ ๊ตฌํ์ ํ๋ฉด Frame ์ ํตํด ์ ๊ทผ์ด ๊ฐ๋ฅํ๋ค.
-content-provider ์ ๋ฏธ๊ตฌํ ๋ฉ์๋๋ insert, update, delete-query
-content-provider๋ฅผ ํธ์ถํ๊ธฐ ์ํ ํด๋์ค๋ contentResolver ์ด๋ค.
-> context.getContentResolver ๋ฅผ ํตํด์ ๊ตฌํ๋ค.
-> insert(URI, ), update(URI, ), delete, quert ๋ฉ์๋ ์ง์…
- android ์์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ URI ๋ android.provider ์์ ์ฐพ๋๋ค.
– ํ๊ฒ Content-Provider ๋ Android-Manifest ๋ฑ๋ก ์ authority ๋ฅผ ๋ฑ๋กํด์ผ ํ๋ค.
-> URI : content://<์ ์ํauthority>/path(table๋ช )
<provider android:name=“MyContentProvider” android:authorities=“com.ict”
android:exported=“true”></provider>
-Content-Provider ์์ฑํ manifiest ์ export ์์ฑ์ true ๋ก ์ ์ํด ์ฃผ์ด์ผ ํ๋ค.
-Provider ๋ ๊ฐ Method ์์ path ๋ช ์ ์ด์ฉํ์ฌ ์๋น์ค๋ฅผ ๋ถ๊ธฐ์ฒ๋ฆฌ ํ ์ ์๋ค.
@SAMPLE@ : Content-Provider ํด๋ ์ฐธ์กฐ
- Broadcast Receiver
BroadcastReceiver๋ ๋ฒ ํฐ๋ฆฌ ์ํ, ์ถฉ์ , wifi์ ์, ๋ฌธ์ ๋ฑ ๊ฐ์ข Broadcast Event ์ ๋์ํ๊ธฐ
์ํ์ฌ ์ฌ์ฉํ๋ค. Broadcast Receiver๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค.
- ย A) Receiver ์์ฑ
– Receiver ์ธก์ Android-Manifest ์ ๋ฑ๋กํ๊ฑฐ๋ Java ์์์ ๋ฑ๋กํ๋ค.
– BroadcastReceiver ๋ฅผ ์์๋ฐ์ onReceive(Context context, Intent intent)
๋ฉ์๋๋ฅผ ์ค๋ฒ๋ผ์ด๋ฉ ํ๋ค.
- ย B) Broadcast ํธ์ถ
– Android-Manifest ์ Braodcast Messgage ์ ์ก ํผ๋ฏธ์ ์ ์ถ๊ฐํ๋ค .
<uses-permission android:name=“android.permission.BROADCAST_STICKY”>
– context method ์ธ sendOrderedBroadcast,sendStickyBroadcast๋ฑ์ ์ฌ์ฉํ์ฌ ๊ฐ๋จํ
ํธ์ถ ๊ฐ๋ฅํ๋ค.
(1) Broadcast Receiver์์ฑ ๋ฐฉ๋ฒ
- A) android-manifest.xml ์ ๋ฑ๋ก
์๋์ ๊ฐ์ดAndroid-Manifest์ ๋ฑ๋กํ๋ ๊ฒฝ์ฐ Android Framework์์ ๋ฐ์ํ๋ ๋ชจ๋
๋ฉ์์ง์ ๋ํด์ ๋ฐ์ํ๋ค.
<receiver
android:name=“edu.jaen.android.receiver.OneShotAlarm1”
android:process=“:remote”>
<intent-filter android:priority=“1”>
<action android:name=“com.jaen.REGISTER” />
</intent-filter>
</receiver>
- B) Activity ์์ Regist
Java ์์ ๋ด๋ถ์ ์ผ๋ก ๋ฑ๋กํ๋ ๊ฒฝ์ฐ Android Framework์ด ์๊ณ ์์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ์๋์
๊ฐ์ด BraodcastReceiver ๋ฅผ ๋ฑ๋กํ๊ธฐ ์ ์๋ ๋์ํ์ง ์๋๋ค. (๋ก์ปฌํ๊ฒ ์ฌ์ฉํ๊ณ ์ถ์ ๊ฒฝ์ฐ)
Context c=getApplicationContext();
IntentFilter f=new IntentFilter(“com.jaen.REGISTER”); //action
f.setPriority(500); // ์ฐ์ ์์ ๋ถ์ฌ
c.registerReceiver(a2, f); //receiver ๋ฑ๋ก
- C) BroadCastting ์์ฒญ ๋ฐฉ๋ฒ
์ฌ์ฉ์๊ฐ Braodcast ๋ฉ์์ง๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ ํฌ๊ฒ 3๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ํธ์ถ์ด ๊ฐ๋ฅํ๋ค.
– sendBroadCast() : ๋์ผํ action ์ ๊ฐ๊ณ ์๋ Broadcast ๊ฐ ์ฌ๋ฌ ๊ฐ ์์ ๊ฒฝ์ฐ Random
– sendOrderedBroadcast(): ์ฌ๋ฌ ๊ฐ๊ฐ ์์ ๊ฒฝ์ฐ ์ฐ์ ์์์ ์ํด ์์ฐจ์ ์ผ๋ก ์คํ
– sendStickyBroadcast() : ํธ์ถ ์์ ์ Receiver๊ฐ ์์ด๋ ์ ๊ท ๋ฑ๋ก์ ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ค๊ฐ ์คํ
- D) Intent Flag ๋ฅผ ์ด์ฉํ Broadcast ์ ์ด
intent ์์ ํธ์ถ ์ flag ๋ฅผ ์ฌ์ฉํ์ฌ ์ ์ด๋ฅผ ํ ์ ์๋ค.
-FLAG_RECEIVER_REGISTED_ONLY : Android_Manifiest ์ ์ ์๋์ด ์๋ receiver๋ ๋ฌด์ํ๋ค.
-FLAG_RECEIVER_REPLACE_PENDING : ๋์ผํ intent ๊ฐ ์ฐ์์ ์ผ๋ก ์ ๋ฌ๋ ๊ฒฝ์ฐ ์ฒ์๊ณผ
๋ง์ง๋ง ๊ฒ๋ง ์ธ์ํจ
-FLAG_INCLUDE_STOPPED_PACKAGE : (Package๊ฐ Stopped)์ ์ง๋์ด ์๋ PROCESS ๋
์คํ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ์ด๋ฐ ๊ฒฝ์ฐ ์ฌ์ฉํ๋ค.
@SAMPLE@ : BroadCastReceiver ํด๋ ์ฐธ์กฐ
- Widget – Service
Widget์ ๊ธฐ๋ณธ์ ์ผ๋ก HomeApplication ๊ณผ์ ํต์ ์ ํตํด์ ๋์ํ๋ค. Android ์์๋ ์ด๋ฌํ ๋ณต์กํ ํต์ ๊ณผ์ ์ ๊ฐ๋จํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋๋กappWidgetProvider ๋ฅผ ์ ๊ณตํ๋ค.,
์๋๋ ๊ธฐ๋ณธ์ ์ธ Widget ์ ๋์ ๊ณผ์ ์ด๋ค.
Service -> RemoteView -> AppWidgetProvider-> Home Program
(1) Android-Manuifest.xml ์ ์
์๋์ ๊ฐ์ Manifest ์ ์ ์๋ฅผ ํ๊ฒ ๋๋ฉด Android Home ์์ Widget ์ค์น ๋ฉ๋ด์ ๋ฑ๋ก์ด ๋จ
Meta-data ์ ๋ณด๋ฉด Home์์ Widget ์ UI ๋ฅผ ์ ์ํ๋ xml ์ด ์ ์ ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
<receiver
android:enabled=“true”
android:label=“์ค๋ง์ผ! ์ด๋ฒคํธ“
android:name=“edu.jaen.android.wiget.event.WidgetReceiver”>
<intent-filter >
<action android:name=“android.appwidget.action.APPWIDGET_UPDATE”/>
</intent-filter>
<meta-data
android:name=“android.appwidget.provider”
android:resource=“@xml/smileinfo”/>
</receiver>
(2) [resource].xml ์ ์
Widget ์ ํฌ๊ธฐResizable ์ฌ๋ถ๋ฅผ ์ ์ํ๊ณ Widget์์ ์ฌ์ฉํ layout ๋ฑ์ ์ ์ํ ์ ์๋ค.
<?xml version=“1.0”encoding=“utf-8”?>
<appwidget-provider xmlns:android=“http://schemas.android.com/apk/res/android”
android:minWidth=“40dip”
android:minHeight=“110dip”
android:resizeMode=“vertical|horizontal”
android:updatePeriodMillis=“0”
android:initialLayout=“@layout/smile”>
</appwidget-provider>
(3) layout ์ ์
Layout ์ ๊ธฐ์กด์Activity ๋ Fragment ์ Layout ์ ์ ์ํ๋ ๊ฒ๊ณผ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋ค.
<?xml version=“1.0”encoding=“utf-8”?>
<RelativeLayout xmlns:android=“http://schemas.android.com/apk/res/android”
android:id=“@+id/mainlayout”
android:layout_width=“wrap_content”
android:layout_height=“fill_parent”
android:orientation=“vertical”>
<ImageView
android:id=“@+id/smileImage”
android:layout_width=“wrap_content”
android:layout_height=“wrap_content”
android:src=“@drawable/smile”/>
<TextView
android:id=“@+id/smileText”
android:layout_width=“fill_parent”
android:layout_height=“wrap_content”
android:layout_alignRight=“@+id/smileImage”
android:layout_below=“@id/smileImage”
android:gravity=“center”
ย ย ย android:text=“Smile”
android:textColor=“#ffff00”
android:textSize=“15sp”/>
</RelativeLayout>
(4)AppWidgetProvider ์์ ํด๋์ค์์ฑ
3๋ฒ ๊น์ง์ ๊ณผ์ ์ ํตํด์ Widget์ Home ํ๋ฉด์ ์ถ๋ ฅํ์๋ค๋ฉด ์ด์ ์ ๋์ ์ผ๋ก ์ด๋ฒคํธ ์ฒ๋ฆฌ๋ ๋ฐ์ดํฐ ๊ฐฑ์ ์ ์ํ์ฌ AppWidgetProvider ์ Service ๋ฅผ ์ด์ฉํ์ฌ์ผ ํ๋ค.
AppWidgetProvider ๋Home ๊ณผ Service ์ฌ์ด์ ํต์ ์ ๋์์ฃผ๋ฉฐ ํต์ ์ ์ํด์๋ RemoteView๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ๊ตํํ๋ค.
public class WidgetReceiver extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds)
{
}
static void appWidgetUpdate(Context context, int appWidgetId, int imgId,
CharSequence text) {
}
@Override
public void onEnabled(Context context) {
super.onEnabled(context);
}
@Override
public void onDisabled(Context context) {
super.onDisabled(context);
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
}
}
(5)RemoteView ์์ฑ
- A) RemoteView๋ฅผ ์์ฑ
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.smile);
views.setImageViewResource(R.id.smileImage, imgId);
views.setTextViewText(R.id.smileText, text);
- B) AppWidgetManger ์์ฑ
AppWidgetManager wm = AppWidgetManager.getInstance(context);
C)Service๋ฅผ ์คํํ Intent ์์ฑ
Intent intentImage = new Intent(context, ImageService.class);
intentImage.putExtra(“wId”, appWidgetId);
D)๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ดIntent๋ฅผ ์คํํ ์ ์๋๋ก PendinIntent ์์ฑ
PendingIntent pendingImage = PendingIntent.getService(context,appWidgetId, intentImage, 0);
E)RemoteView ์ onClickPendingIntent Listener ๋ฅผ ์ถ๊ฐ
views.setOnClickPendingIntent(R.id.smileImage, pendingImage);
F)AppWidgetManager์ updateAppWidget() ๋ฉ์๋๋ฅผ ํตํด HOST๋ก View Update
wm.updateAppWidget(appWidgetId, views);
@Sample@ : 6. AppWigetEvent ํด๋๋ฅผ ์ฐธ์กฐํ๋ค.
- ์ํ์ ์ง ๊ธฐ๋ฒ๊ณผ Parcelable
์ํ ์ ์ง ๊ธฐ๋ฒ์ผ๋ก๋ Preference ,Data Base, File , network ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ Android ์ System Memory ๋ฅผ ์ฌ์ฉํ๋ ๊ธฐ๋ฒ์ด ์๋ค.
๋, Activity ์์ ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ํด onSaveInstanceState, onRestoreInstanceState ์ํ๋ฅผ ์ด์ฉํ ์ ์๋ค.
์ฌ๊ธฐ์๋ Android์System Memory๋ฅผ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ณต๊ตฌํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์ด์ผ๊ธฐ ํ๊ณ ์ ํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก Activity์ Android FrameWork์ ๊ธฐ๋ณธ์ ์ผ๋ก ํต์ ์ ๊ธฐ๋ฐ์ผ๋ก ํ๊ณ ์๊ธฐ ๋๋ฌธ์ Seralized ๋ ๊ฐ์ฒด๋ง์ด ์ ์ก๊ฐ๋ฅํ๋ฉฐ ํน๋ณํ Android ์์๋ Parcelable ์ด๋ผ๋ ๊ฐ๋ ์ ์ฌ์ฉํ๊ณ ์๋ค.
(1) Parcelable ์ด๋?
– ๊ธฐ๋ณธ์ ์ผ๋ก ์๋๋ก์ด๋๋ Activity ๊ฐ์ Intent ํต์ ์ ์ฌ์ฉํ๋ค.
– ํต์ ์์ ๊ฐ์ฒด๋ฅผ ์ ์กํ๊ธฐ ์ํด์๋ Serialized ๊ฐ ๋์ด ์์ด์ผ ํ๋ค.
– Serialized์ ๋จ์ ์ ์๋๊ฐ ๋๋ฆฌ๋ค๋ ๊ฒ์ธ๋ฐ ์ด๊ฒ์ ๋จ์ ์ ๋ณด์ํ ๊ฒ์ด Parcelable ์ด๋ค.
-Android ์์๋ ์ด๋ฌํ Parcelabel ์ ๊ฐ๋ ์ ์ฌ์ฉํ์ฌ Bundle ์ด๋ผ๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค
(2) onCreate, onSaveInstance ์์์ Bundle ํ์ ํ๋ผ๋ฉํฐ
- A) save call back ์์ Bundle ์ Parcelable ๊ฐ์ฒด๋ฅผ ์ ์ฅํ ์ ์๋ค.
ย ์ ์ฅ๋ ๊ฐ์ฒด๋ Android FrameWork ์ System Memory ๊ณต๊ฐ์ ์ ์ฅ๋๋ค.
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);
bundle.putParcelableArrayList(“list”, pList);
}.
- B) Bundle ๊ฐ์ฒด์์ Parcelable ๊ฐ์ฒด๋ฅผ ๊บผ๋ด์ด ๋ฐ์ดํฐ๋ฅผ ๋ณต๊ตฌํ๋ค.
ย ์ ์ฅ๋ ๊ฐ์ฒด๋ Android FrameWork ์ System Memory ๊ณต๊ฐ์ ์ ์ฅ๋๋ค.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pList = bundle.getParcelableArrayList(“list”);
}
(2) ๊ธฐ์กด์ Android ์ ์ ์๋ Pacelable ๊ฐ์ฒด๋ฅผ ์ด์ฉ
– Bundle ์ ๊ธฐ๋ณธ์ ์ผ๋ก Parcelable ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฅ ์ฌ์ฉํ๋ฉด ๋๋คโฆ
ArrayList<HashMap<String, String>> selectedChildList = null;
ArrayList<Bundle> currentList = null;
Bundle bundle = null;
HashMap<String, String> item = null;
Object[] keyArray = null;
if(mChildList != null && mChildList.size() > 0)
{
selectedChildList = mChildList.get(groupPosition); if(selectedChildList != null && selectedChildList.size() > 0)
{
currentList = new ArrayList<Bundle>();
for(int i = 0; i < selectedChildList.size(); i++) {
item = selectedChildList.get(i);
bundle = new Bundle();
keyArray = (Object [])item.keySet().toArray();
for(int j = 0; j < keyArray.length; j++)
{
bundle.putString(String.valueOf(keyArray[j]), item.get(keyArray[j]));
}
currentList.add(bundle);
}
}
(3) Parcelable ๊ฐ์ฒด๋ฅผ ์์ฑํ์ฌ ์ฌ์ฉํ๊ธฐ
– ๊ธฐ๋ณธ์ ์ผ๋ก Parcelable ์ Implements ๋ฐ์ ์์ฑํ๋ฉฐ ๋ช ๊ฐ์ง ํ์์ ์ธ Method ๋ฅผ Overide ํ์ฌ ๊ตฌํํ์ฌ์ผ ํ๋ค.
– writeToParcel: ํต์ ์ Android FrameWork์์ ํธ์ถ๋๋ ๋ฉ์๋๋ก Seraliazable ํ๋๋ก ์ง์ ์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ set ํด์ฃผ์ด์ผ ํ๋ค. (์ด๋ ์์๊ฐ ๋งค์ฐ ์ค์, CREATE ์ ์ผ์นํด์ผ ํจ)
– CREATEOR : ๋ฆฌํดํ๊ณ ์ ํ๋ ๊ฐ์ฒด ํ์ ์ผ๋ก ๋ณต์ํ๋ ๋ฉ์๋ ๋ํ Overide ํ์ฌ ๊ตฌํ ํ์
public class Point implements Parcelable{
float x;
float y;
boolean isDraw;
public Point(float f, float g, boolean isDraw) {
this.x = f;
this.y = g;
this.isDraw = isDraw;
}
@Override
public int describeContents() {
// TODO Auto-generated method stub
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// TODO Auto-generated method stub
dest.writeFloat(x);
dest.writeFloat(y);
dest.writeBooleanArray(new boolean[]{isDraw});
}
public static Creator<Point> CREATOR = newCreator<Point>() {
@Override
public Point createFromParcel(Parcel source) {
// TODO Auto-generated method stub
float x = source.readFloat();
float y = source.readFloat();
boolean[] ba = new boolean[1];
source.readBooleanArray(ba);
return new Point(x,y,ba[0]);
}
@Override
public Point[] newArray(int size) {
// TODO Auto-generated method stub
return new Point[size];
}
};
}
@Sample@ : CustomView ํด๋ ์ฐธ์กฐ
- binding ๊ณผ Service ๋ฅผ Custom Provider
– ์ด๋ฏธ ServiceBind ๊ธฐ๋ฅ์ ์ด์ฉํ์ฌ Service ์ Activity ๊ฐ์ Interactive ํ ํต์ ์ด ๊ฐ๋ฅํ๋ค.
์ํ์ฝ๋๋ ์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ก ๋์ํ๋ค. .
Activity -> Resolver-> (Bind) -> Service (onCreate() -> onBind()-> onUnBind()) ->onDestory());
Service ์ชฝ์์ Bind() ๊ฐ ๋๋ฉด Resolver ์ธก์๋ onServiceConnected() Callback ์ด ํธ์ถ๋๋ฉฐ Bind
๋ณ์๋ฅผ ๋ฆฌํดํ๋ค. ์ด Bind ๋ณ์๋ฅผ Interface๋ก Castinfํ์ฌ Service ์ธก๊ณผ ๋ฉ์๋ ๊ธฐ๋ฐ์ ํต์ ์ด ๊ฐ๋ฅํ๋ค. ์ด๋, ์ฃผ๊ณ ๋ฐ์ ์ ์๋ ๊ฐ์ฒด๋ ๋น์ฐํ ํต์ ๊ธฐ๋ฐ์ด๊ธฐ ๋๋ฌธ์ Parcelable ๊ฐ์ฒด๋ง ๊ฐ๋ฅ
(1) Activity ->Resolver
์ํ์ฝ๋ ์์ Activity ์ ๊ตฌํ๋๋ ๋ด์ฉ์ ๋ณ ๊ฒ ์๋ค. Resolver ์ ๊ตฌํ๋ ๋ช ๊ฐ์ง ๋ฉ์๋๋ค์ ํธ์ถํ ๋ฟ์ด๋ค .
myResolver = new MyResolver(this);
Button btn01 = (Button)this.findViewById(R.id.btn_01);
btn01.setOnClickListener(newOnClickListener() {
@Override
public void onClick(View v) {
myResolver.insert();
}
});
(1) Resolver ->Service
์ํ์ฝ๋์์ Resolver ๋ ์ด๋ค ์ธํฐํ์ด์ค๋ ํด๋์ค๋ ์์ ๋ฐ์ง ์๋๋ค. Resolver์์ ํ๋ ์ญํ ์ 3๊ฐ์ง๋ก ์์ฝ๋๋ค. Service Binding, ServiceConnection ๊ฐ์ฒด๋ฅผ ํตํBinding ๊ฐ์ฒด ์์ฑ, Binding ๊ฐ์ฒด๋ฅผ ์ด์ฉํService method ํธ์ถ 3๊ฐ์ง๋ก ์์ฝ๋๋ค.
- A) Service ๋ฐ์ธ๋ฉ
Intent i = new Intent();
ComponentName cn = new ComponentName(“com.example.a10.bindtestmyservice”,”com.example.a10.bindtestmyservice.MainService”);
i.setComponent(cn);
//๋ฐ์ธ๋ฉ
context.bindService(i, conn, Context.BIND_AUTO_CREATE);
- B) AIDL ์์ฑ
๋ค๋ฅธ ํจํค์ง ๊ฐ์ Method ๋ฐฉ์์ผ๋ก Direct ํธ์ถ์ ๊ต์ฅํ ๋ณต์กํ ์ผ์ด๋ค. ๊ทธ๋์ Android Frame Work ์์๋ AIDL ์ ์ง์ํ๋ค .
– AIDL ํ์ฅ์์ ํ์ผ์src/package ์๋ ์์ฑํ๋ค.
– gen ํด๋ ์๋ java ํ์ผ์ด ์๋ ์์ฑ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค .
– Service ๋ฅผ ์ ๊ณต๋ฐ๊ณ ์ ํ๋ ์ชฝ์์๋ ๋์ผํ๊ฒ AIDL ํ์ผ์ ์์ฑํด์ผ ํ๋ค.
– ๋จ, Service ๋ฅผ ์ ๊ณตํ๋ ์ชฝ๊ณผ ๋์ผํ Package ๋ช ์ ์ฌ์ฉํด์ผ ํ๋ค๋ ์ ์ ์ ์
– ์๋๋ AIDL ํ์ผ์ ์์ ์ด๋ค.
package com.example.a10.bindtestmyservice;
interface AidlProvider
{
void insert();
void update();
void delete();
void query();
}
- C) ServiceConnection์์ฑ
ServiceConnection ํด๋์ค๋ ๋ ๊ฐ์ Overiding method ๋ฅผ ์ง์ํ๋๋ฐ onServerConnected()
์์๋ Bind ํด๋์ค๋ฅผ return ๋ฐ์ ์ ์๋ค.
์ฐ๋ฆฌ๊ฐ ์ ์ํ update, query, delete, insert 4๊ฐ์ method ๋ฅผ ํ์ฉํ๊ธฐ ์ํด์ (B)์์ ์์ฑํ AIDL ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ค.
AidlProvider provider = AidlProvider.Stub.asInterface(Binder bind)
์ด๋ ๊ฒ ์์ฑ๋ provider ๋ bind.insert();bind.update();bind.delete();bind.query();
๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค .
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(context, “-ServiceDisconncted”, 10).show();
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(context, “-ServiceConneted”, 10).show();
bind = AidlProvider.Stub.asInterface(service);
}
};
@Sample@ : AIDL ํด๋ ์ฐธ์กฐ
- USER-PERMISSION
(1) ์์ ์ด ์์ฑํ Applcation ์ Permission ์ง์
<permission
android:description=”@string/permdesc_required”
android:label=”๊ถํ์ด ์๊ตฌ๋ฉ๋๋ค.”
android:name=”edu.jaen.permission”
android:protectionLevel=”signature”
/>
(2) Permission ํ๋
<uses-permission android:name=”edu.jaen.permission”/>
@Sample@ : B2.PermissionClient, B2.PermissionProject
- ๊ธฐํ
(1) ํ์ ๋ฒ์ OS ํ๊ฒฝ์์ ์์๋ฒ์ ๊ธฐ๋ฅ ์ฌ์ฉํ๊ธฐ
– android-support_v4 : ํ์ ๋ฒ์ ์์ ์์ OS ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์๋๋ก External ํํ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๊ณต๋๋ค. ํด๋น Lib ๋APK ์ ํฌํจ๋์ด ํ์ OS ์์๋ ๋์ ํ ์ ์๋๋ก ํ๋ค.
(2) ApplicationManager
(3) SQLLite
Wow, wonderful blog layout! How long have you
been blogging for? you make blogging look easy. The overall look of your web site is excellent, let alone
the content!