因为,一直存在一些问题AsyncTask.所以,现在,我正在考虑转向Loader或Headless Fragments.
我的应用程序是一个社交媒体应用程序,人们评论,发布,喜欢和做更多的事情.每个活动从服务器获取图像,我必须缓存它们.要处理运行时配置更改,哪个更适合此应用程序.装载机或无头碎片.
我将处理每个陷阱,例如从服务器加载数据并且活动进入onStop()或onPause()状态.救命!
android android-asynctask android-fragments android-cursorloader android-loader
我正在尝试使用Commonsware中使用Loader的适配器实现DataListFragment.此Loader直接使用SQLiteDatabase,不需要使用ContentProviders.
关于Loaders的android参考说明:"当Loaders处于活动状态时,他们应该监视数据源,并在内容发生变化时提供新的结果."
在我的SQLiteCursor实现(下面)中,这不会发生.OnLoadFinished()被召唤一次就是这样.据推测,可以Loader.onContentChanged()在底层数据库发生更改的情况下插入调用,但通常数据库代码类不了解加载器,所以我不确定实现它的最佳方法.
有没有人有任何关于使Loader"数据感知"的建议,或者我应该将数据库内容包装为ContentProvider并使用CursorLoader代替?
import com.commonsware.cwac.loaderex.SQLiteCursorLoader;
public class DataListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>{
protected DataListAdapter mAdapter; // This is the Adapter being used to display the list's data.
public SQLiteDatabase mSqlDb;
private static final int LOADER_ID = 1;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
int rowlayoutID = getArguments().getInt("rowLayoutID");
// Create an empty adapter we will use to display the loaded data.
// We pass 0 to flags, since the Loader will watch for data changes …Run Code Online (Sandbox Code Playgroud) 我创建了一个Activity实现LoaderManager.LoaderCallbacks<Cursor>接口的简单方法 .该OnCreateLoader()很简单:
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args)
{
Log.d(TAG, "On create loader");
Uri queryUri = ContentUris.withAppendedId(SmartPresentationMessage.Person.CONTENT_URI, 1);
CursorLoader cursorLoader = new CursorLoader(this, queryUri, null, null, null, null);
return cursorLoader;
}
Run Code Online (Sandbox Code Playgroud)
当我getLoaderManager().initLoader(0, null, this)在Activity创建时调用时调用此方法.
我的问题是在我的ContentProvider,有以下query()方法:
@Override
public Cursor query(Uri uri, String[] projection, String where,
String[] whereArgs, String sortOrder)
{
int match = sUriMatcher.match(uri);
Cursor queryCursor;
SQLiteDatabase mdb = mOpenHelper.getReadableDatabase();
switch (match)
{
case PERSON:
long …Run Code Online (Sandbox Code Playgroud) 我在a CursorAdapter中使用a ListFragment来加载和显示注释列表.
public class CommentsFragment extends ListFragment implements LoaderCallbacks<Cursor> {
protected Activity mActivity;
protected CursorAdapter mAdapter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mActivity = getActivity();
mAdapter = new CommentsCursorAdapter(mActivity, null, 0);
setListAdapter(mAdapter);
mActivity.getContentResolver().registerContentObserver(CustomContract.Comments.CONTENT_URI, false, new CommentsObserver());
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle extras) {
Uri uri = CustomContract.Comments.CONTENT_URI;
return new CursorLoader(mActivity, uri, null, null, null, null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
mAdapter.swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) …Run Code Online (Sandbox Code Playgroud) android android-contentprovider contentobserver android-cursorloader android-cursoradapter
在我们的项目中,我们经常处理列表,并在过去使用它并使用以下“模式”:
ListView 位于 Fragment 中,在 onActivityCreated 中初始化,我们首先启动 CursorLoaders,然后在 onFinish 中将 Cusor 交换到 ListAdapter。然后,我们使用 filterQueryProvider 实现了搜索功能,该功能仅通过 contentResolver.query(...) 返回游标。如果我在选择列表中的某些内容时进行了一些方向更改,则在许多情况下(不定期)会出现以下错误:
android.database.StaleDataException: Attempted to access a cursor after it has been closed.
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1967)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1992)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3378)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.access$700(ActivityThread.java:127)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1162)
12-05 10:36:59.531: E/ACRA(12079): at android.os.Handler.dispatchMessage(Handler.java:99)
12-05 10:36:59.531: E/ACRA(12079): at android.os.Looper.loop(Looper.java:137)
12-05 10:36:59.531: E/ACRA(12079): at android.app.ActivityThread.main(ActivityThread.java:4448)
12-05 10:36:59.531: E/ACRA(12079): at java.lang.reflect.Method.invokeNative(Native Method)
12-05 10:36:59.531: E/ACRA(12079): at java.lang.reflect.Method.invoke(Method.java:511)
12-05 …Run Code Online (Sandbox Code Playgroud) 我尝试将我的 java 项目转换为 kotlin,但有一个问题让我感到困惑。
项目结构:
App:用于声明全局变量应用
MainActivityAppCompatActivity:
Provider:ContentProvider的
SectionsPagerAdapter:FragmentPagerAdapter
fragment0:
fragment1:片段器具LoaderManager.LoaderCallbacks
当我尝试将 fragment1 转换为 kotlin 时,它会抛出 FC。
片段1 java代码:
class fragment1 : Fragment(), LoaderManager.LoaderCallbacks<Cursor> {
private var mMainView: View? = null
private var adapter: SimpleCursorAdapter? = null
private var cursor: Cursor? = null
private var date: Date? = null
private var kadaihao: Array<String?>? = null
private val uri: Uri? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val inflater = activity.layoutInflater
mMainView = inflater.inflate(R.layout.fragment1, …Run Code Online (Sandbox Code Playgroud) 我使用a ContentProvider来查询数据库并返回一个Cursor用于CursorLoader:
ItemsActivity:
public class ItemsActivity extends SherlockActivity implements LoaderCallbacks<Cursor> {
@Override
public void onCreate(Bundle savedInstance) {
....
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
...
}
@Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
return new CursorLoader(getApplicationContext(), itemsListUri, ...);
}
...
}
Run Code Online (Sandbox Code Playgroud)
ItemsContentProvider:
public Cursor query(Uri uri, String[] projection, String selection, ...) {
SqliteQueryBuilder builder = new SqliteQueryBuilder();
builder.setTables(ItemsTable.NAME);
return builder.query(db, projection, selection, ...);
}
Run Code Online (Sandbox Code Playgroud)
活动有一个ListView,我使用CursorAdapter(通过更新LoaderCallbacks)来表示光标内的数据.
这工作正常,直到我需要查找大型数据集中的项目(例如,超过30,000行).观察日志我发现查找超出了内存限制,并且从结果游标中删除了一些行.
我的问题:在使用这样的游标时,处理非常大的数据集的最佳方法是什么?
我目前的解决方案是将SQLite查询ContentProvider拆分为具有偏移和限制的查询序列,然后使用MergeCursor …
目前我正在使用getContentResolver().query()/ managedQuery()来获取光标以从图库应用程序中检索图像.因为我正在使用的API部分弃用,所以我想将CursorLoader与LoaderManager一起使用.
/**
* Creates a cursor to access the content defined by the image uri for API
* version 11 and newer.
*
* @return The created cursor.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private Cursor createCursorHoneycomb() {
String[] projection = {
MediaStore.Images.Media.DATA
};
Cursor cursor = getContentResolver().query(imageUri, projection, null, null, null);
return cursor;
}
/**
* Creates a cursor to access the content defined by the image uri from API
* version 8 to 10.
*
* @return The created cursor.
*/ …Run Code Online (Sandbox Code Playgroud) android android-cursor android-loadermanager android-cursorloader android-cursoradapter
在我的活动中,我有一个代表医生的列表视图.每行都有医生的名字和一个复选框.我已经实现了一个回调接口,这样当选择医生时,所有其他医生都会从列表视图中删除,只剩下选定的医生.
它似乎有效,因为一旦我选择了医生,所有其他人都被移除了.当我取消检查医生时,每个人都被加回.但是,如果我现在选择一位不同的医生,原来的医生会停下来而其他所有医生都会被移除.
为了更好地解释这个问题,让我们说当我开始活动时,我在列表视图中有两位医生,Joel和Sam.我想我想选择Joel,所以我这样做,而且Sam从列表中删除了.然后,我意识到我错了,所以我取消选择乔尔,我现在看到列表中的乔尔和萨姆.最后,我选择了Sam.但是,Sam被从列表中删除,只有Joel再次出现.
以下是适配器类的一些代码片段:
@Override
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
final long id = cursor.getLong(cursor.getColumnIndex(DoctorEntry._ID));
String firstName = cursor.getString(cursor.getColumnIndex(DoctorEntry.COLUMN_FIRSTNAME));
viewHolder.nameView.setText(firstName);
viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if(mCallbacks != null){
if(isChecked){
mCallbacks.onDoctorChecked(id);
} else{
mCallbacks.onDoctorUnchecked();
}
}
}
});
}
public void onRegisterCallbacks(DoctorAdapterCallbacks activity){
mCallbacks = activity;
}
public static interface DoctorAdapterCallbacks{
void onDoctorChecked(long id);
void onDoctorUnchecked();
}
Run Code Online (Sandbox Code Playgroud)
在我的活动中,我有以下实现:
@Override
public void onDoctorChecked(long id) { …Run Code Online (Sandbox Code Playgroud) java android callback android-cursorloader android-cursoradapter
我正在使用带有 的游标加载器,RecyclerView其他一切正常,除了每次从 RecyclerView 中删除一个项目时,最后一个项目闪烁,就像这样
我的删除代码是
public void deleteData(long id){
Uri uri = ContentUris.withAppendedId(URI, id);
getContentResolver().delete(uri, null, null);
}
Run Code Online (Sandbox Code Playgroud)
刷卡代码:
deleteData(viewHolder.getItemId());
Run Code Online (Sandbox Code Playgroud)
请注意,我有一个使用相同的另一个活动RecyclerAdapter,ContentProvider甚至大多数的实现和方法途径和布局代码,都是一样的,但一个完美的作品没有任何闪烁,所以这对我来说是很奇怪的情况。
是否有可能导致此问题的特定原因?我已经尝试禁用动画
recyclerView.getItemAnimator().setChangeDuration(0);
Run Code Online (Sandbox Code Playgroud)
或者
((DefaultItemAnimator) recyclerViewObject.getItemAnimator()).setSupportsChangeAnimations(false);
Run Code Online (Sandbox Code Playgroud)
但这些都没有奏效,更不用说我确实希望动画正常工作。
编辑:断点上传:
在创建:
"main@4668" prio=5 tid=0x2 nid=NA runnable java.lang.Thread.State: RUNNABLE at com.jackz314.todo.HistoryActivity.onCreateLoader(HistoryActivity.java:803) at android.support.v4.app。 LoaderManagerImpl.createLoader(LoaderManager.java:539) at android.support.v4.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:548) at android.support.v4.app.LoaderManagerImpl.initLoader(LoaderManager.java:603) at com .jackz314.todo.HistoryActivity.displayAllNotes(HistoryActivity.java:394) 在 com.jackz314.todo.HistoryActivity.deleteExpiredNotes(HistoryActivity.java:767) 在 com.jackz314.todo.HistoryActivity.onCreate(HistoryActivity.java:129)
在 android.app.Activity.performCreate(Activity.java:6975) 在 android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) 在 android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) 在 android.app。 ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(ActivityThread.java:-1) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
在 android.os.Handler.dispatchMessage(Handler.java:105) 在 android.os.Looper.loop(Looper.java:164) 在 android.app.ActivityThread.main(ActivityThread.java:6541) 在 …
android android-contentresolver android-contentprovider android-cursorloader android-recyclerview