Loader
Android 2013. 10. 29. 13:26Android 3.0에서 도입 된 로더에 의해, 활동이나 조각에서 데이터를 비동기 적으로로드가 쉽게되었습니다. 로더에는 다음과 같은 특징이 있습니다.
- 모든
Activity
와Fragment
에서 사용할 수 있습니다. - 비동기 데이터로드를 제공합니다.
- 그 데이터 소스를 모니터링하고 내용이 변경 될 때 새로운 결과를 전달합니다.
- 설정 변경이 있은 후에 다시 생성되면 자동으로 로더 커서에 다시 연결합니다. 따라서 다시 데이터를 요청해야합니다.
로더 API 요약
응용 프로그램 로더의 사용을 채택 할 것 같은 클래스와 인터페이스는 다양합니다. 다음 표는 그 요약입니다.
클래스 / 인터페이스 | 설명 |
---|---|
LoaderManager | 하나 이상의 Loader 인스턴스를 관리하기위한 Activity 와 Fragment 관련 추상 클래스입니다. 그러면 This 응용 프로그램이 Activity 와 Fragment 의 라이프 사이클과 연동하여 장시간 작업을 관리 할 수 있습니다. 이와 더불어 CursorLoader 을 사용하는 것이 가장 일반적이지만 응용 프로그램이 그 다음 데이터 유형을로드하기 위해 자신의 로더를 작성하는 것은 자유입니다. 활동 및 조각마다 하나의 LoaderManager 밖에 존재하지 않습니다. 하지만 LoaderManager 여러 로더를 가질 수 있습니다.
|
LoaderManager.LoaderCallbacks | 클라이언트가 LoaderManager 와 양방향으로 상호 작용하는 콜백 인터페이스입니다. 예를 들어, onCreateLoader () 콜백 메서드를 사용하여 새 로더를 만듭니다. |
Loader | 비동기 데이터로드를 실행하는 추상 클래스입니다. 이것이 로더의 기본 클래스입니다. CursorLoader 의 사용이 일반적이지만, 독자적인 서브 클래스를 구현할 수 있습니다. 로더가 활성화 동안 해당 데이터 소스는 모니터링 된 콘텐츠에 변화가 있으면 새로운 결과를 전달합니다. |
AsyncTaskLoader | 처리하기위한 AsyncTask 를 제공하는 추상 로더입니다. |
CursorLoader | AsyncTaskLoader 의 서브 클래스에서, ContentResolver 에 문의하여 Cursor 를 돌려줍니다. 이것은 커서의 문의에 대해 표준적인 방법으로 Loader 프로토콜을 구현 한 클래스에서 응용 프로그램의 UI를 차단하지 않도록 백그라운드 스레드에서 커서를 작동시키기 위해 AsyncTaskLoader 를 기반으로 구축되어 있습니다. 조각과 활동의 API에서 관리 된 쿼리를 실행하는 것이 아니라,ContentProvider 에서 데이터를 비동기 적으로로드하도록하기 위해이 로더를 사용하는 것이 가장 좋은 방법입니다. |
위 표에있는 클래스와 인터페이스는 응용 프로그램 로더를 구현하는 데 사용하게 될 필수적인 구성 요소입니다. 만드는 로더 각각이 모두 필요하지 않지만 로더를 초기화하고 CursorLoader
등 Loader
클래스를 구현하기 위해서는, LoaderManager
의 참조가 항상 필요합니다. 응용 프로그램에서 이러한 클래스와 인터페이스를 사용하는 방법을 다음 절에서 설명합니다.
응용 프로그램 로더 사용
이 섹션에서는 Android 애플리케이션에서 로더의 사용 방법을 설명합니다. 로더를 사용하는 응용 프로그램은 일반적으로 다음이 포함되어 있습니다.
Activity
또는Fragment
.LoaderManager
의 인스턴스입니다.ContentProvider
데이터를로드하기위한CursorLoader
. 또는 다른 데이터 소스가 제공하는 데이터를로드하기 위해 자신의Loader
및AsyncTaskLoader
의 서브 클래스를 구현 할 수 있습니다.LoaderManager.LoaderCallbacks
대한 구현. 여기가 새로운 로더를 만들고 기존의 로더에 대한 참조를 관리하는 장소가된다.SimpleCursorAdapter
등 로더의 데이터를 표시하는 것을 의미합니다.CursorLoader
를 사용할 때ContentProvider
등의 데이터 소스.
로더의 시작
LoaderManager
는 하나 이상의 Loader
인스턴스를 Activity
와 Fragment
에서 관리합니다. 활동 및 단편마다 하나의 LoaderManager
밖에 존재하지 않습니다.
일반적으로 활동의 onCreate ()
메서드 또는 조각 onActivityCreated ()
메서드에서 Loader
를 초기화합니다. 다음과 같이하여 작업을 수행합니다.
/ / Prepare the loader. Either re-connect with an existing one,
/ / or start a new one.
getLoaderManager (). initLoader (0, null, this);
initLoader ()
메서드는 다음 매개 변수를받습니다.
- 로더를 식별하는 고유 ID이 예제에서는 ID는 0.
- 로더의 구축시에 공급하는 선택적 인수 (이 예제에서는
null
). LoaderManager.LoaderCallbacks
구현에서LoaderManager
이것을 호출하여 로더 이벤트를 전한다. 이 예에서는 로컬 클래스가LoaderManager.LoaderCallbacks
인터페이스를 구현하므로 전달 참조는 자신의this
된다.
initLoader ()
를 호출하여 로더의 초기화 및 활성화가 이루어집니다. 다음 두 가지 결과가 발생할 수 있습니다.
- 지정된 ID의 로더가 이미 존재하는 경우에는 마지막으로 만들어진 로더가 재사용된다.
- 지정된 ID의 로더가 존재 하지 않는 경우
initLoader ()
이LoaderManager.LoaderCallbacks
방법의onCreateLoader ()
트리거가된다. 여기가 새로운 로더를 인스턴스화하고 반환 코드를 구현하는 장소가된다. onCreateLoader 섹션을 참조하십시오.
어느 경우에서도 구현 된 LoaderManager.LoaderCallbacks
는 로더와 연관되어 로더의 상태가 변경 될 때 호출되는 것입니다. 이 호출하려고 할 때 호출자가 시작된 상태에 있고, 요청 된 로더가 이미 존재 해, 그 데이터를 생성 한 경우 시스템이 즉시 onLoadFinished ()
를 호출하기 때문에 ( initLoader ()
의 사이)이 발생하게 준비해 둘 필요가 있습니다. 이 콜백에 대해 자세하게 해설하고있다 onLoadFinished 를 참조하십시오.
initLoader ()
메소드는 생성 된 Loader
를 반환하지만 그것에 대한 참조를 가지고 있지 않은 점에 주목하십시오. LoaderManager
는 로더의 생존 상태를 자동으로 관리합니다. LoaderManager
는 필요할 때 선적 시작하고 중지 로더의 상태와 관련 콘텐츠를 보유하고 있습니다. 이것이 의미하는 것처럼 로더와 직접 통신하는 것은 거의 없습니다 (하지만 로더의 동작을 조정하려면 로더의 메서드를 사용할 수 있으므로, 그 예는 LoaderThrottle 샘플을 참조 하십시오). 이벤트가 발생할 때 선적 처리를 끼우는 목적으로 공통적으로 사용되는 것이 LoaderManager.LoaderCallbacks
방법입니다. 이 항목에 대한 자세한 설명은 LoaderManager 콜백 사용 을 참조하십시오.
로더 재개
initLoader ()
를 사용하면 위에서 설명한대로 지정된 ID를 가진 기존의 로더가있는 경우 그것을 사용합니다. 없으면 만듭니다. 오래된 데이터를 버리거나 다시하고 싶은 것도 있고합니다.
오래된 데이터를 버릴에는 restartLoader ()
를 사용합니다. 예를 들어이 SearchView.OnQueryTextListener
의 구현을 통해 사용자가 쿼리를 변경하면 로더가 재개됩니다. 로더는 개정 된 검색 필터를 사용하여 새 질문을 할 수 있도록 다시 시작해야합니다.
public boolean onQueryTextChanged (String newText) {
/ / Called when the action bar search text has changed. Update
/ / the search filter, and restart the loader to do a new query
/ / with this filter.
mCurFilter =! TextUtils.isEmpty (newText )? newText : null;
getLoaderManager (). restartLoader (0, null, this);
return true;
}
LoaderManager 콜백 사용
LoaderManager.LoaderCallbacks
클라이언트가 LoaderManager
와 상호 작용 수 있도록하는 콜백 인터페이스입니다.
로다, 특히 CursorLoader
은 정지해도 그 데이터를 보유하고있는 것으로 예상되고 있습니다. 그러면 응용 프로그램, 활동 및 조각 onStop ()
와 onStart ()
메소드 사이에서 그 데이터를 지켜주고 있기 때문에 사용자가 응용 프로그램에 돌려 보낼 때 데이터를 다시로드를 기다릴 필요가 없습니다. 새로운 로더를 만들 타이밍을 알고 싶을 때나, 로더의 데이터 사용을 중지하고 타이밍을 응용 프로그램에 알리기 위해 LoaderManager.LoaderCallbacks
방법을 사용합니다.
LoaderManager.LoaderCallbacks
에는 다음 메서드가 포함되어 있습니다.
onCreateLoader ()
- 주어진 ID에 대한 새로운Loader
를 인스턴스화 해 돌려 준다.
onLoadFinished ()
- 이전에 만든 로더가로드를 완료했을 때 호출된다.
onLoaderReset ()
- 이전에 만든 로더가 재설정되고 그로 인하여 그 데이터를 사용할 수 없게되었을 때 호출된다.
이러한 방법의 자세한 내용은 다음 섹션에서 설명합니다.
onCreateLoader
로더에 대한 액세스를 시도 할 때 (예를 들어 initLoader ()
를 사용하여) 지정된 ID로 기존 로더의 존재 여부를 확인합니다. 도하지 않으면 그 액세스가LoaderManager.LoaderCallbacks
방법의 onCreateLoader ()
트리거입니다. 여기가 새로운 로더를 작성하는 곳입니다. 일반적으로 이것이 CursorLoader
이지만, 독자적으로 Loader
의 서브 클래스를 구현할 수 있습니다.
이 예제에서는 onCreateLoader ()
콜백 메서드가 CursorLoader
을 만들고 있습니다. 생성자를 사용하여 CursorLoader
를 작성해야 거기에는 ContentProvider
에서 쿼리를 실행하는 데 필요한 모든 정보 집합이 필요합니다. 구체적으로는 다음이 필요합니다.
- uri - 검색 할 컨텐츠 URI.
- projection - 반환 열 목록.
null
을 전달하면 모두 반환되지만 비효율적이다. - selection - SQL의 WHERE 절 (WHERE 자신은 제외)으로 포맷 된 반환 행 필터의 선언.
null
를 전달 제공 한 URI에 대해 모든 행이 반환된다. - selectionArgs - selection에?이 있으면 그들이 나타나는 순서대로 selectionArgs 가 제공하는 값으로 그들을 대체합니다. 값은 String 배열로 바인딩된다.
- sortOrder - SQL의 ORDER BY 절 (ORDER BY는 제외)로 포맷 된 행의 순서 성.
null
을 전달하면 기본 정렬 순서로 정렬되지 않습니다.
다음은 그 예입니다.
// If non-null, this is the current filter the user has provided.
String mCurFilter;
...
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 + " != '' ))";
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
onLoadFinished
이 메서드는 이전에 만들어진 로더가로드를 완료 할 때 호출됩니다. 이 메소드는,이 로더에 의해 제공된 마지막 데이터를 해제하기 전에 호출되도록 보장되어 있습니다. 이때 사용하는 기존 데이터는 모두 삭제해야하지만 (즉시 풀어 놓는 것이니까) 그 로더가 그 데이터를 보관하고 그 후에도 그것을 관리하기 때문에 자신의 데이터를 공개해야 는 없습니다.
로더는 응용 프로그램이 데이터를 더 이상 사용하지 않으면 안다고 데이터를 삭제합니다. 예를 들어, 데이터가 CursorLoader
가 제공하는 커서의 경우 스스로 그 close ()
를 호출해서는 없습니다. 커서가 CursorAdapter
에 놓여있는 경우 swapCursor ()
메서드를 사용하여 이전 Cursor
가 폐쇄되지 않도록해야합니다. 다음은 그 예입니다.
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...
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);
}
onLoaderReset
이 메서드는 이전에 만들어진 로더가 재설정 될 때마다 호출되며, 그로 인하여 그 데이터를 사용할 수 없게됩니다. 이 콜백 메서드는 데이터가 해방 되려고하는시기를 알 수 있으며, 그로 인하여 데이터 참조를 제거 할 수 있습니다.
이 구현은 다음과 같이 swapCursor ()
에 null
값을 전달하여 호출합니다.
// This is the Adapter being used to display the list's data.
SimpleCursorAdapter mAdapter;
...
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);
}
실례
예를 들어, 연락처에 콘텐츠 공급자의 결과가 들어간 ListView
보기 Fragment
의 완전한 구현이 여기에 있습니다. 이것은 프로 바이더에서 쿼리를 관리하는 CursorLoader
을 사용하고 있습니다.
응용 프로그램이이 예제와 사용자의 연락처에 액세스하려면 매니페스트에 READ_CONTACTS
의 권한을 추가해야합니다.
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);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
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) {
// Called when the action bar search text has changed. Update
// the search filter, and restart the loader to do a new query
// with this filter.
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);
}
// These are the Contacts rows that we will retrieve.
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,
};
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 + " != '' ))";
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
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);
}
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' 카테고리의 다른 글
안드로이드 ADT 번들 마지막 버전 다운로드 (0) | 2016.02.01 |
---|---|
갤럭시탭 10.1 커스터롬 관련 링크 (0) | 2014.04.09 |
안드로이드 바코드 스캐너 ZXing 빌드 방법 (2) | 2013.11.04 |