올해는 머신러닝이다.
[펌]안드로이드 Loader 활용하기 본문
출처 : http://ismydream.tistory.com/136
안드로이드 Loader 활용하기
Loader
- 안드로이드 3.0 에서 소개된 Loader 를 사용하면 액티비티와 프래그먼트에서의 비동기 데이터 로딩을 쉽게 처리할 수 있습니다.
특징
- 모든 액티비티와 프래그먼트에서 사용할 수 있습니다.
- 어플리케이션 UI를 Blocking 하지 않도록 비동기 데이터 로딩을 제공합니다.
- 데이터를 모니터 하기 때문에 데이터가 변경되었을때 변경사항을 확인할 수 있습니다.
API
LoaderManager
- LoaderManager는 액티비티, 프래그먼트 와 1:1 의 관계를 갖습니다. 액티비티 하나당 하나의 LoaderManger 가 존재하는 셈이죠
그리고 하나의 LoaderManager 는 여러개의 Loader 를 관리하게 됩니다.
LoaderManager.LoaderCallbacks
- Loader 를 컨트롤하기 위해 제공되는 콜백 메소드입니다. 콜백 메소드를 통해서 Loader 를 생성하고 변경할 수 있습니다.
Loader
- 비동기 데이터 로딩을 수행하는 추상 클래스입니다.
AsyncTaskLoader
- AsyncTask 를 제공하는 추상 로더입니다.
CursorLoader
- AsyncTaskLoader 의 하위 클래스로서 ContentrResolver 에 쿼리를 하여 Cursor 를 리턴 받도록 합니다.
- AsyncTaskLoader 를 사용하기 때문에 처리하는 작업이 어플리케이션 UI 를 블락킹하지 않습니다.
Loader 적용하기
Loader 시작하기
- Loader 를 초기화하기 위해서 아래코드를 Activity 의 onCreate(), Fragment 의 onActivityCreated() 콜백함수내에 추가한다.
getLoaderManager().initLoader(
0, // Loader 를 구분하기 위한 ID 값
null, // 추가 인자
this // Loader 로 부터 콜백을 받기 위해서 LoaderManager.LoaderCallbacks 를 구현한 객체를 넘겨준다.
);
※ initLoader 메소드는 두가지의 결과를 갖게되는데
- initLoader 에 넘겨준 ID 값을 갖는 Loader 가 이미 존재하는 경우 이미 존재하는 LOader 를 재사용하게 됩니다.
- 존재하지 않는 경우에는 LoaderManager.LoaderCallbacks 인터페이스에 있는 onCreateLoader() 콜백함수를 호출하게 됩니다.
Loader 재시작하기
initLoader 메소드에서 ID 가 이미 존재하는 경우에는 기존 Loader 를 재사용 한다고 했는데 재사용 하더라도 데이터를 초기화하고 싶을 때가 있습니다. 그런 경우에 Loader 를 재사용하며 데이터는 초기화하고 싶을때 재시작하게 됩니다.
// 검색시 검색어가 변경되었을 경우 호출
public boolean onQueryTextChanged( String newText){
mCurFilter = !TextUtils.isEmpty( newText) ? newText : null;
getLoaderManager().restartLoader( 0, null, this);
return true;
}
LoaderManager 콜백 사용하기
LoaderManager.LoaderCallbacks
- onCreateLoader()
initLoader 에 넘겨준 ID 를 갖는 Loader 를 생성하여 넘겨준다. 직접 생성하여야 한다.
- onLoaderFinished()
Loader 가 로딩을 끝내을 때 호출한다.
- onLoaderReset()
Loader 가 리셋 됬을 때 호출한다.
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 new CursorLoader(
getActivity(),
baseUri, // 가져올 컨텐트의 uri
CONTACTS_SUMMARY_PROJECTION, // 가져올 컬럼의 정보, null 일 경우 모든 컬럼을 리턴한다.
select, // 가져올 데이터를 필터링 하는 정보 SQL 의 WHERE 절과 유사하다., 모든 데이터를 가져올 경우 null 을 설정한다.
null, // selectionArgs
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC" // 정렬 순서 sortOrder
);
}
onLoadFilnished 예제
- 로딩이 끝난후 adapter 에 Cursor를 설정하는 예제
SimpleCursorAdapter mAdapter;
public void onLoadFinished( Loader<Cursor> loader, Cursor data){
mAdapter.swapCursor( data);
}
onLoaderReset 예제
- Loader 가 리셋 되었을 때 호출된다. 그러므로 기존 데이터를 해제해야 한다.
SimpleCursorAdapter mAdapter;
public void onLoaderReset( Loader<Cursor> loader){
mAdapter.swapCursor( null);
}
LoaderManager.LoaderCallbacks 를 구현한 Fragment 예제입니다.
public static class CursorLoaderListFragment extends ListFragment
implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
// If non-null, this is the current filter the user has provided.
String mCurFilter;
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Give some text to display if there is no data. In a real
// application this would come from a resource.
setEmptyText("No phone numbers");
// We have a menu item to show in action bar.
setHasOptionsMenu(true);
// Create an empty adapter we will use to display the loaded data.
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_2, null,
new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
setListAdapter(mAdapter);
// LoaderManger 를 초기화합니다. ID 가 존재하는 경우는 존재하는 Loader 를 재사용합니다.
// Fragment 는 onActivityCreated 메소드내에서 초기화를 진행합니다.
getLoaderManager().initLoader(0, null, this);
}
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Place an action bar item for searching.
MenuItem item = menu.add("Search");
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SearchView sv = new SearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
public boolean onQueryTextChange(String newText) {
// ActionBar 에서 검색시 검색어가 변경되었을 경우에 기존 로더를 재사용하기 위해 Loader의 데이터를 초기화해 줍니다.
mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
getLoaderManager().restartLoader(0, null, this);
return true;
}
@Override public boolean onQueryTextSubmit(String query) {
// Don't care about this.
return true;
}
@Override public void onListItemClick(ListView l, View v, int position, long id) {
// Insert desired behavior here.
Log.i("FragmentComplexList", "Item clicked: " + id);
}
// CursorLoader 에서 가져올 컬럼 정의
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
// Loader 를 생성하는 콜백 메소드. Loader 를 생성해서 넘겨주면 LoaderManager 에서 알아서 실행하게 됩니다.
@Override public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// First, pick the base URI to use depending on whether we are
// currently filtering.
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = Contacts.CONTENT_URI;
}
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ Contacts.DISPLAY_NAME + " != '' ))";
// CursorLoader 를 생성해서 넘겨줍니다.
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
// Loader 작업이 끝난후 결과 데이터를 처리하는 콜백 메소드
@Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
}
// Loader 가 리셋되었을때 기존 데이터를 해제하는 콜백 메소드
@Override public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
}
'Android > Tip&Tech' 카테고리의 다른 글
안드로이드 추천 팁 링크 (0) | 2014.11.07 |
---|---|
[펌]LoaderManager 동작이해 (0) | 2014.10.21 |
자바 표준 스타일 정의 (0) | 2014.09.30 |
[링크]아날로그 시계 만드는 소스 (0) | 2014.08.26 |
kitkat(4.4)에서 맞닥뜨린 이슈 및 해결 (0) | 2014.08.14 |