互換性パッケージを使用してプロジェクトにAsyncTaskLoaderを実装したいので、Android Docs)のローダーのマニュアルに従いました。
問題は、ローダーが何もしないことです。loadInBackground()
が呼び出されることはないようです。
私のコードの何が問題になっているのか考えていますか? (ExpandableListFragment
はFragment
を拡張しますが、重要なメソッドをオーバーライドしません)
ありがとうございました :-)
/ **編集:
私は(遅く、私はモロンです)AsyncTaskLoaderが抽象クラスであることに気付いたので、サブクラス化する必要があります... m(__)m誰かが私の後ろに来た場合に備えて、質問を残します。 ..
public class AgendaListFragment extends ExpandableListFragment implements
LoaderManager.LoaderCallbacks<JSONArray> {
private TreeMap<Integer, ArrayList<Evento>> mItems = new TreeMap<Integer, ArrayList<Evento>>();
private AgendaListAdapter mAdapter;
private ProgressBar mProgressBar;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_agenda, container);
mProgressBar = (ProgressBar) root.findViewById(R.id.loading);
return root;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new AgendaListAdapter(getActivity());
setListAdapter(mAdapter);
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<JSONArray> onCreateLoader(int arg0, Bundle arg1) {
mProgressBar.setVisibility(View.VISIBLE);
return new AsyncTaskLoader<JSONArray>(getActivity()) {
@Override
public JSONArray loadInBackground() {
return getDataFromService(AgendaServices.LISTADO_MES);
}
};
}
@Override
public void onLoadFinished(Loader<JSONArray> loader, JSONArray data) {
// Some stuff to turn JSONArray into TreeMap
mProgressBar.setVisibility(View.GONE);
mAdapter.setItems(mItems);
}
@Override
public void onLoaderReset(Loader<JSONArray> arg0) {
mAdapter.setItems(null);
mProgressBar.setVisibility(View.VISIBLE);
}
}
互換性パッケージの最善の解決策は、AsyncTaskLoader.onStartLoadingメソッドをオーバーライドすることだと思います。
例えば.
@Override
protected void onStartLoading() {
if(dataIsReady) {
deliverResult(data);
} else {
forceLoad();
}
}
これは正確に修正されていますが、機能するはずです。互換性ライブラリが壊れていると確信しています。これを試して:
getLoaderManager().initLoader(0, null, this).forceLoad();
Cheok Yan Cheng 絶対に正しい:
TakeContentChangedのチェックも重要なステップのようです。
次のようにメソッドを作成する場合:
protected void onStartLoading() {
forceLoad();
}
子アクティビティが発生してから親アクティビティに戻ると、onStartLoading
(したがってloadInBackground
)が再度呼び出されることに気付くでしょう。
あなたは何ができますか?コンストラクター内で内部変数(mContentChanged
)をtrueに設定します。次に、onStartLoading
内のこの変数を確認します。それが本当の場合にのみ、実際にロードを開始します。
package example.util;
import Android.content.Context;
import Android.support.v4.content.AsyncTaskLoader;
public abstract class ATLoader<D> extends AsyncTaskLoader<D> {
public ATLoader(Context context) {
super(context);
// run only once
onContentChanged();
}
@Override
protected void onStartLoading() {
// That's how we start every AsyncTaskLoader...
// - code snippet from Android.content.CursorLoader (method onStartLoading)
if (takeContentChanged()) {
forceLoad();
}
}
}
https://code.google.com/p/Android/issues/detail?id=14944 でのディスカッションを見ると、takeContentChanged
をチェックすることも重要なステップのようです。
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
AndroidフレームワークからCursorLoader
のソースコードを取得し、作業を容易にするためにCustomTaskLoader<T>
クラスを作成しました。
基本的に、次の2つの関数を実装します。
public abstract T runTaskInBackground(CancellationSignal signal);
public abstract void cleanUp(T oldResult);
アクティビティとフラグメントでの使用法を参照してください。たとえば、次のようになります(私のコードはCancellationSignal
を無視します。これは、私のリストではTODO
ですが、自由に使用できます)。
return new CustomTaskLoader<Cursor>(getActivity().getApplicationContext())
{
@Override
public Cursor runTaskInBackground(CancellationSignal signal)
{
return SiteSession.getAllPostsCursor(PostListAdapter.POST_COLUMNS);
}
@Override
public void cleanUp(Cursor oldCursor)
{
if (!oldCursor.isClosed())
oldCursor.close();
}
}
CursorLoaderからAsyncTaskLoaderに移行した後、同じ問題が発生しました。
ドキュメントによると :Loader<D>
のサブクラスは、通常、少なくともonStartLoading()、onStopLoading()、onForceLoad()、およびonReset()。
AsyncTaskLoaderはローダーを拡張しますが、実装しませんonStartLoading()、onStopLoading()、onReset()。自分で実装する必要があります!
@ davidshen84は良い解決策を提案しました。 takeContentChangedのチェックのみを追加しました。
@Override
protected void onStartLoading() {
try {
if (data != null) {
deliverResult(data);
}
if (takeContentChanged() || data == null) {
forceLoad();
}
Log.d(TAG, "onStartLoading() ");
} catch (Exception e) {
Log.d(TAG, e.getMessage());
}
}
ForceLoad()の使用は問題ありません(悪い習慣ではありません)。どのドキュメントを参照してください 言う :
通常、これはローダーの起動時にのみ呼び出す必要があります。つまり、isStarted()はtrueを返します。