Феншуй, MatrixCursor+SimpleCursorAdapter+CursorLoader=>
Добавлено: 26 ноя 2014, 01:48
задача:
-нужно сделать бесконечный список подгружаемых картинок.
-использовать CursorLoader чтоб автоматически сетились данные в адаптер, и адаптер автоматически обновлял view(феншуй)
как работает:
-вводишь строку поиска, дергается onQueryTextSubmit, строка сохраняется в SharedPreferences, дергается
-свой обработчик скрола списка который в нужный момент вызывает
- loadInBackground заново (пере)использует MatrixCursor
- LoaderCallbacks вызывает adapter.swapCursor(data);
затык:
1.вызывается только один раз, даже если второй раз AbsListView.OnScrollListener дергает лоадер, лоадер срабатывает второй раз тоже , но onLoadFinished уже не отрабатывает
2. каждый раз когда вызывается, и записываются строка запроса, происходит обращения к локальной памяти, что не феншуй, как исправить?
Обработчик лоадера:
и лоадер
Пробовал MatrixCursor и каждый раз новый, и передавать в аргументе адаптера, и ключи(CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER) адаптера тоже пробовал, LoaderCallbacks вызывается только один раз при вводе новой строки.
-нужно сделать бесконечный список подгружаемых картинок.
-использовать CursorLoader чтоб автоматически сетились данные в адаптер, и адаптер автоматически обновлял view(феншуй)
как работает:
-вводишь строку поиска, дергается onQueryTextSubmit, строка сохраняется в SharedPreferences, дергается
Код: Выделить всё
Loader.ForceLoadContentObserver observer#.onChangeКод: Выделить всё
Loader.ForceLoadContentObserver observer#.onChange(true)- LoaderCallbacks вызывает adapter.swapCursor(data);
затык:
1.
Код: Выделить всё
LoaderManager.LoaderCallbacks<Cursor>#onLoadFinished(Loader<Cursor> loader, Cursor data) Код: Выделить всё
public Cursor loadInBackground()2. каждый раз когда вызывается
Код: Выделить всё
Loader.ForceLoadContentObserver observer#.onChange Обработчик лоадера:
Код: Выделить всё
package com.example.myapp.views;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v4.widget.SimpleCursorAdapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.widget.SearchView;
import com.example.myapp.Const;
import com.example.myapp.R;
import com.example.myapp.async.ImageCursorLoader;
import com.example.myapp.listeners.InfiniteScrollListener;
import com.example.myapp.model.ImageData;
import com.example.myapp.storage.DBFav;
/**
* Created by v on 16.11.2014.
*/
public class SearchFragment extends SherlockListFragment implements View.OnClickListener, LoaderManager.LoaderCallbacks<Cursor>, SearchView.OnQueryTextListener {
DBFav db;
SimpleCursorAdapter adapter;
SharedPreferences sp;
String query;
Loader.ForceLoadContentObserver observer;
Uri NOTIFICATION_URI = Uri.parse("content://v.k");
InfiniteScrollListener listNer = new InfiniteScrollListener() {
@Override
public void onLoadMore(int page, int totalItemsCount) {
observer.onChange(true);
}
};
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
ImageCursorLoader loader = null;
if (id == Const.LOADER_SEARCH_ID) {
loader = new ImageCursorLoader(getSherlockActivity(), args);
Log.d(getClass().getName(), "onCreateLoader: " + loader.hashCode());
observer = loader.new ForceLoadContentObserver();
}
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
Log.d(getClass().getName(), "onLoadFinished for loader " + loader.hashCode()
+ ", result = ");
if (adapter.getCursor() != null)
adapter.notifyDataSetChanged();
else {
adapter.swapCursor(data);
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
Log.d(getClass().getName(), "onLoaderReset for loader " + loader.hashCode());
adapter.swapCursor(null);
observer = null;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
sp = PreferenceManager.getDefaultSharedPreferences(getSherlockActivity());
if (adapter != null) {
setListAdapter(adapter);
getListView().setOnScrollListener(listNer);
return;
}
setHasOptionsMenu(true);
db = new DBFav(this.getActivity());
db.open();
query = sp.getString(Const.KEY_QUERY, null);
/* Context context, int layout, Cursor c, String[] from,
int[] to, int flags) {*/
adapter = new SimpleCursorAdapter(getSherlockActivity(),
R.layout.item, null, new String[]{
DBFav.COLUMN_IS_FAVOURITE,
DBFav.COLUMN_TITLE,
DBFav.COLUMN_IMG_ID
}, new int[]{R.id.cbBox, R.id.descr, R.id.image}, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
adapter.setViewBinder(new Main.SeekBarBinder());
setListAdapter(adapter);
getListView().setOnScrollListener(listNer);
if (query != null) onQueryTextSubmit(query);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.list_fragment, container, false);
return view;
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
SearchView searchView =
(SearchView) menu.findItem(R.id.search).getActionView();
searchView.setOnQueryTextListener(this);
}
@Override
public void onClick(View view) {
ImageData dat = (ImageData) view.getTag();
if (view instanceof CheckBox) {
CheckBox cb = (CheckBox) view;
if (cb.isChecked()) {
db.add(dat);
} else {
db.delRec(dat.getImageId());
}
dat.setFavourite(cb.isChecked());
} else {
((Main) getActivity()).showImage(dat, R.id.search_fragment);
}
}
@Override
public boolean onQueryTextSubmit(String query) {
/* adapter.getDataList().clear();
adapter.setServerListSize(0);*/
adapter.notifyDataSetChanged();
if (observer == null) {
Bundle req = new Bundle();
req.putString(Const.KEY_QUERY, query);
getLoaderManager().initLoader(Const.LOADER_SEARCH_ID, req, this).forceLoad();
} else {
SharedPreferences.Editor e = sp.edit();
e.putString(Const.KEY_QUERY, query);
e.commit();
observer.onChange(true);
}
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
return false;
}
}
Код: Выделить всё
package com.example.myapp.async;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.content.CursorLoader;
import android.util.Log;
import com.example.myapp.Const;
import com.example.myapp.model.ImageData;
import com.example.myapp.parse.ResponseDataWrapper;
import com.example.myapp.storage.DBFav;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
/**
* Created by v on 25.11.2014.
*/
public class ImageCursorLoader extends CursorLoader {
Navigator navigator;
ImageCacheService cacheService;
volatile String query;
MatrixCursor result;
ResponseDataWrapper data;
LinkedList<ImageData> tmpDataList = new LinkedList<>();
AtomicLong idCounter = new AtomicLong();
ImageData tmpImage;
List tmpData;
public ImageCursorLoader(Context context, Bundle args) {
super(context);
navigator = new Navigator();
resetQuery(args.getString(Const.KEY_QUERY));
cacheService = ImageCacheService.getInstance();
}
private MatrixCursor makeCursor() {
MatrixCursor cursor;
cursor = new MatrixCursor(DBFav.PROJECTION_ARR);
return cursor;
}
@Override
public Cursor loadInBackground() {
int counter = Const.CACHE_SIZE;
if (!resetIfNeed())
return result;
while (counter > 0) {
while (counter > 0 && tmpDataList.size() > 0) {
tmpImage = tmpDataList.removeFirst();
try {
tmpData = tmpImage.toList(idCounter.incrementAndGet());
} catch (Exception ex) {
ex.printStackTrace();
}
result.addRow(tmpData);
counter--;
}
if (counter > 0) {
data = navigator.next();
try {
tmpDataList.addAll(cacheService.processMini(data.getResponseData().getResponseData()));
} catch (Exception ex) {
return result;
}
}
}
return result;
}
private boolean resetIfNeed() {
if (query == null)
return false;
boolean res = true;
if (!query.equals(navigator.getQueryString())) {
navigator.setQueryString(query);
tmpDataList.clear();
}
if (result == null)
result = makeCursor();
return res;
}
private boolean checkAndReset() {
boolean res = true;
res &= isStarted() & !isAbandoned() & !isReset();
return res;
}
@Override
protected void onForceLoad() {
super.onForceLoad();
Log.d(getClass().getName(), hashCode() + " onForceLoad called");
}
@Override
public void onCanceled(android.database.Cursor cursor) {
super.onCanceled(cursor);
Log.d(getClass().getName(), hashCode() + " onCanceled called");
}
@Override
public void forceLoad() {
super.forceLoad();
Log.d(getClass().getName(), hashCode() + " forceLoad called");
}
@Override
protected void onStartLoading() {
super.onStartLoading();
Log.d(getClass().getName(), hashCode() + " onStartLoading called");
}
@Override
protected void onStopLoading() {
super.onStopLoading();
Log.d(getClass().getName(), hashCode() + " onStopLoading called");
}
@Override
protected void onAbandon() {
super.onAbandon();
Log.d(getClass().getName(), hashCode() + " onAbandon called");
}
@Override
protected void onReset() {
super.onReset();
Log.d(getClass().getName(), hashCode() + " onReset called");
}
private void resetQuery(String newQueryOrNot) {
if (query != null && query.equals(newQueryOrNot)) {
return;
} else {
query = newQueryOrNot;
}
}
@Override
public void onContentChanged() {
super.onContentChanged();
Log.d(getClass().getName(), hashCode() + " onContentChanged called");
Log.d(getClass().getName(), hashCode() + " setting new query");
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
resetQuery(sp.getString(Const.KEY_QUERY, "google search"));
}
@Override
public boolean cancelLoad() {
Log.d(getClass().getName(), hashCode() + " cancelLoad");
return super.cancelLoad();
}
@Override
public void stopLoading() {
Log.d(getClass().getName(), hashCode() + " stopLoading");
super.stopLoading();
}
}
Пробовал MatrixCursor и каждый раз новый, и передавать в аргументе адаптера, и ключи(CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER) адаптера тоже пробовал, LoaderCallbacks вызывается только один раз при вводе новой строки.