在后台执行某些操作然后更新UI很难在Android中正确实现.它设计得很糟糕.典型的例子是AsyncTask,它从Web获取内容并显示结果.这有两个问题:
AsyncTask引用了Activity(因为它需要更新其UI).屏幕方向更改后,重新启动活动.但是AsyncTask仍然引用旧的被破坏的Activity,因此无法更新新Activity的UI.
这可能导致OutOfMemoryException.想象一下,你有一个包含大量位图的Activity,并启动一些AsyncTask.您按BACK(活动已完成)但AsyncTask仍在运行,并且因为它引用了Activity,所以带有位图的Activity仍在内存中.重复此操作(开始活动和返回),你的力量迟早会关闭.
这可以解决,但它太复杂了.在一个Activity中,我有3个不同的AsyncTasks,每个都可以同时在多个实例中运行.正确实现这一点令人沮丧.代码变得非常难以理解和调试.
Honeycomb Loaders可以解决这个问题吗?有没有办法在pre-Honeycomb Android版本中使用它们?
基于android开发人员示例,我有一个使用ActionBar选项卡滑动选项卡的活动.
每个选项卡显示一个片段,每个片段(实际上,SherlockFragment)通过自定义AsyncTaskLoader加载不同类型的远程api请求.
问题是,如果您点击一个标签移动2个标签/页面,而您要离开的标签的片段(旧片段)正在加载结果,则该结果将传递到您移动到的标签的片段(新片段).在我的情况下,这会导致ClassCastException,因为预期的结果是不兼容的类型.
在代码中,情况的要点是:
装载机:
public class FooLoader extends AsyncTaskLoader<Foo>
public class BarLoader extends AsyncTaskLoader<Bar>
Run Code Online (Sandbox Code Playgroud)
片段:
public class FooFragment extends Fragment implements LoaderManager.LoaderCallbacks<Foo> {
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
}
public Loader<Foo> onCreateLoader(int id, Bundle args) { return new FooLoader(); }
...
}
public class BarFragment extends Fragment implements LoaderManager.LoaderCallbacks<Bar> {
...
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getLoaderManager().initLoader(0, null, this);
}
public Loader<Bar> onCreateLoader(int id, Bundle args) { return new …Run Code Online (Sandbox Code Playgroud) android android-fragments android-viewpager android-loadermanager android-loader
我目前正在大量修改/重写一个Android应用程序,我看到一个非常偶然的崩溃沿着以下几行:一个CursorAdapter方法被调用,它调用AbstractWindowedCursor#checkPosition(),和:
02-20 15:03:18.180 E/AndroidRuntime(17143): android.database.StaleDataException: Attempting to access a closed CursorWindow.Most probable cause: cursor is deactivated prior to calling this method.
02-20 15:03:18.180 E/AndroidRuntime(17143): at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:139)
02-20 15:03:18.180 E/AndroidRuntime(17143): at android.database.AbstractWindowedCursor.getLong(AbstractWindowedCursor.java:74)
02-20 15:03:18.180 E/AndroidRuntime(17143): at android.database.CursorWrapper.getLong(CursorWrapper.java:106)
02-20 15:03:18.180 E/AndroidRuntime(17143): at android.widget.CursorAdapter.getItemId(CursorAdapter.java:220)
Run Code Online (Sandbox Code Playgroud)
麻烦的是,我们没有关闭任何Cursors.我们所有的Cursors都来自CursorLoaders而且又是由a产生的ContentProvider.我们要传递Cursor到每个相应的CursorAdapter从LoaderCallbacks,我们正在注册Cursor中的通知ContentProvider,我们通知了ContentResolver从各insert(...),delete(...)和update(...)......总之我找不到任何理由为什么Cursor会在使用中关闭一段时间.
那么:a 的其他原因是 …
android staledataexception android-contentprovider android-loadermanager android-loader
我对装载机有一个奇怪的问题.目前我不确定这是否是我的代码中的错误或我误解了加载器.
该应用程序
问题出现在对话中(想象类似于Whatsapp的东西).我使用的加载器是基于AsyncTaskLoader示例实现的.我正在使用支持库.
这非常有效,但有以下例外.
问题
当我打开另一个片段(并将事务添加到backstack)然后使用Back-Key返回conversationFragment时,onLoadFinished再次使用之前的两个结果调用.此调用发生在片段有机会再次启动加载器之前...
我之前获得的"旧"结果的传递导致重复的消息.
题
堆栈跟踪的电话
MyFragment.onLoadFinished(Loader, Result) line: 369
MyFragment.onLoadFinished(Loader, Object) line: 1
LoaderManagerImpl$LoaderInfo.callOnLoadFinished(Loader, Object) line: 427
LoaderManagerImpl$LoaderInfo.reportStart() line: 307
LoaderManagerImpl.doReportStart() line: 768
MyFragment(Fragment).performStart() line: 1511
FragmentManagerImpl.moveToState(Fragment, int, int, int, boolean) line: 957
FragmentManagerImpl.moveToState(int, int, int, boolean) line: 1104
BackStackRecord.popFromBackStack(boolean) line: 764
...
Run Code Online (Sandbox Code Playgroud)
更新1 此处提到的加载器由对话片段启动:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
Bundle args = getArguments();
m_profileId = args.getString(ArgumentConstants.ARG_USERID);
m_adapter = new MessageAdapter(this); …Run Code Online (Sandbox Code Playgroud) 加载器优于异步任务有什么优势吗?此外,如何使用Android froyo兼容手机的加载器.
编辑:
这里的主要问题是我没有使用本机DB(SqlLite).在开发服务器上使用DB.显然,我不能再使用CursorLoader了.AsyncTaskLoader没有任何例子.如果有,请做链接.
将所需数据加载到本地数据库然后使用它进行查询是否更好CursorLoader?
android android-asynctask android-cursorloader android-loader
在我最近的一个SO问题中,有人建议我使用Loader我的解决方案.所以在这里我试图了解如何实现一个简单的AsyncTaskLoader
这是我想出的:
public class Scraper extends AsyncTaskLoader<List<Event>> {
List<Event> lstEvents;
public Scraper(Context context) {
super(context);
}
public List<Event> loadInBackground() {
//This is where I will do some work and return the data
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我所知道的.我阅读了文档,AyncTaskLoader但我从来没有遇到任何如此神秘和混乱的东西.有一百万种方法,所有这些方法都是相互矛盾的,看着它们是不可能的,它们被调用的顺序,甚至它们是否应该被覆盖和调用.这项任务的生命周期是一个该死的噩梦.
我正在寻找的只是简单地抓取一些数据并将其返回.我还想将它存储在一个类变量中,以便我在下一次立即返回它而不必再次刮掉所有数据.
我没有打开游标,流或类似的东西,只是一个简单的变量lstEvents(可能很大).我不想泄漏内存和浪费资源,所以如果有人可以解释我需要关闭/无效的地方和时间以使这项任务有效,我会很高兴.
我应该在哪里将数据存储到类变量中?Shoudl我在我的loadInBackground方法结束时这样做或者我应该在deliverResult方法中这样做吗?
在这个简单的场景中,是否有我真正需要检查任务是否被取消或是否被重置的地方,或者我是否应该简单地不覆盖这些方法并让它AsyncTaskLoader处理它.
如果有人知道,一些脚手架代码会有所帮助.万分感谢.
我正面临着Loader的问题.
我有一个Activity,它显示从本地DB检索的记录列表.活动开始时,记录将通过LoaderManager.initLoader()方法自动加载.
还可以通过ActionBarSherlock中的刷新按钮手动刷新列表.但是,在完成另一个向DB添加记录的活动之后,不会调用onLoadFinished.
我正在使用SimpleCursorLoader,这里是活动的代码片段:
@Override
public void onStart() {
...
getSupportLoaderManager().initLoader(0, null, this);
}
@Override
public void onPause() {
...
getSupportLoaderManager().destroyLoader(0);
}
public void refreshRecords() {
getSupportLoaderManager().restartLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, final Bundle args) {
Loader<Cursor> l = new SimpleCursorLoader(this) {
@Override
public Cursor loadInBackground() {
return recordDAO.getCursor();
}
};
l.forceLoad();
return l;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
// updateUI
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
Run Code Online (Sandbox Code Playgroud)
问题是,在完成其他活动之后,会onLoaderCreate …
给定一个使用加载器从数据库加载(大量)数据的片段.
问题:
我有一个寻呼机适配器,当用户离开拿着它的标签时会破坏该片段,并在用户返回该标签时重新创建它.由于这种重新创建,每次都会创建一个新的加载器,并且每次都会加载数据.
题 :
为了避免每次创建片段时重新创建加载器,是否可以在片段getActivity.getSupportLoaderManager.initLoader(loaderId, null, false)的onActivityCreated方法中使用?
我试过它,测试它,似乎工作正常.但我不相信这是对的.
我在一个活动中使用了一个加载器.我能够启动加载器并调用onLoadFinished.当我更新数据并onContentChanged在加载器中调用时,我看到loadInBackground并且deliverResult都被调用.这是小道似乎停止的地方.我没有收到任何回调onLoadFinished.
如果我重新创建活动(也就是方向更改或重新启动),那么它将以相同的方式运行.
我正在使用support-v4加载器和加载器管理器.
我SharedPreferenceLoader基于CommonsWare的加载器:
public class SharedPreferencesLoader extends AsyncTaskLoader<SharedPreferences>
implements SharedPreferences.OnSharedPreferenceChangeListener {
private SharedPreferences prefs = null;
private static final String TAG = SharedPreferencesLoader.class.getSimpleName();
public SharedPreferencesLoader(Context context) {
super(context);
}
@Override
public SharedPreferences loadInBackground() {
Log.v(TAG, "wol: load in background");
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
prefs.registerOnSharedPreferenceChangeListener(this);
return (prefs);
}
@Override
protected void onStartLoading() {
if (prefs != null) {
deliverResult(prefs);
}
if (takeContentChanged() || prefs == null) {
forceLoad();
} …Run Code Online (Sandbox Code Playgroud) android android-loader android-support-library commonsware-cwac
我正在使用第一种方法开发基于Google IO演示架构的应用程序.基本上我有一个Service,ContentProvider由SQLiteDB 支持,我也使用Loaders.
当我的数据库发生更改时,我需要一种更新UI的方法.例如,用户可能想要将项目添加到他的购物篮中.将项目ID插入到篮子表后,我想更新UI.我应该使用什么方法?ContentObserver到目前为止,我看到的信息很少.这是要走的路吗?
android android-contentprovider android-loader android-sqlite