标签: android-loader

Honeycomb Loaders可以解决AsyncTask + UI更新的问题吗?

在后台执行某些操作然后更新UI很难在Android中正确实现.它设计得很糟糕.典型的例子是AsyncTask,它从Web获取内容并显示结果.这有两个问题:

  1. AsyncTask引用了Activity(因为它需要更新其UI).屏幕方向更改后,重新启动活动.但是AsyncTask仍然引用旧的被破坏的Activity,因此无法更新新Activity的UI.

  2. 这可能导致OutOfMemoryException.想象一下,你有一个包含大量位图的Activity,并启动一些AsyncTask.您按BACK(活动已完成)但AsyncTask仍在运行,并且因为它引用了Activity,所以带有位图的Activity仍在内存中.重复此操作(开始活动和返回),你的力量迟早会关闭.

这可以解决,但它太复杂了.在一个Activity中,我有3个不同的AsyncTasks,每个都可以同时在多个实例中运行.正确实现这一点令人沮丧.代码变得非常难以理解和调试.

Honeycomb Loaders可以解决这个问题吗?有没有办法在pre-Honeycomb Android版本中使用它们?

android android-3.0-honeycomb android-loader

13
推荐指数
1
解决办法
2583
查看次数

Loader将结果传递给错误的片段

基于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

13
推荐指数
2
解决办法
2964
查看次数

什么可能导致StaleDataException而不是过早地调用cursor.close()?

我目前正在大量修改/重写一个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到每个相应的CursorAdapterLoaderCallbacks,我们正在注册Cursor中的通知ContentProvider,我们通知ContentResolver从各insert(...),delete(...)update(...)......总之我找不到任何理由为什么Cursor会在使用中关闭一段时间.

那么:a 的其他原因是 …

android staledataexception android-contentprovider android-loadermanager android-loader

12
推荐指数
1
解决办法
1012
查看次数

为什么在片段恢复后再次调用onLoadFinished?

我对装载机有一个奇怪的问题.目前我不确定这是否是我的代码中的错误或我误解了加载器.

该应用程序

问题出现在对话中(想象类似于Whatsapp的东西).我使用的加载器是基于AsyncTaskLoader示例实现的.我正在使用支持库.

  • 在OnCreate中,我启动一个加载器来检索缓存的消息.
  • 当CachedMessageLoader完成时,它启动RefreshLoader以检索(在线)最新消息.
  • 每个加载器类型作为不同的ID(例如,离线:1在线:2)

这非常有效,但有以下例外.

问题

当我打开另一个片段(并将事务添加到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 android-loadermanager android-loader

12
推荐指数
1
解决办法
6236
查看次数

在Android中使用Asynctask的加载器有什么优势?

加载器优于异步任务有什么优势吗?此外,如何使用Android froyo兼容手机的加载器.

编辑:

这里的主要问题是我没有使用本机DB(SqlLite).在开发服务器上使用DB.显然,我不能再使用CursorLoader了.AsyncTaskLoader没有任何例子.如果有,请做链接.

将所需数据加载到本地数据库然后使用它进行查询是否更好CursorLoader

android android-asynctask android-cursorloader android-loader

11
推荐指数
1
解决办法
6074
查看次数

如何实现简单的AsyncTaskLoader?

在我最近的一个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处理它.

如果有人知道,一些脚手架代码会有所帮助.万分感谢.

java android android-asynctask android-loader

9
推荐指数
1
解决办法
2613
查看次数

Android - onLoadFinished没有调用

我正面临着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 …

android android-loadermanager android-loader

9
推荐指数
1
解决办法
1万
查看次数

Android Fragment - 使用activity的loadermanager而不是Fragment.好吗?

给定一个使用加载器从数据库加载(大量)数据的片段.

问题:

我有一个寻呼机适配器,当用户离开拿着它的标签时会破坏该片段,并在用户返回该标签时重新创建它.由于这种重新创建,每次都会创建一个新的加载器,并且每次都会加载数据.

题 :

为了避免每次创建片段时重新创建加载器,是否可以在片段getActivity.getSupportLoaderManager.initLoader(loaderId, null, false)onActivityCreated方法中使用?

我试过它,测试它,似乎工作正常.但我不相信这是对的.

android fragment android-loadermanager android-loader

7
推荐指数
1
解决办法
3363
查看次数

Loader:onLoadFinished只调用一次

我在一个活动中使用了一个加载器.我能够启动加载器并调用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

7
推荐指数
1
解决办法
694
查看次数

数据库更改发生后更新UI的方法

我正在使用第一种方法开发基于Google IO演示架构的应用程序.基本上我有一个Service,ContentProviderSQLiteDB 支持,我也使用Loaders.

当我的数据库发生更改时,我需要一种更新UI的方法.例如,用户可能想要将项目添加到他的购物篮中.将项目ID插入到篮子表后,我想更新UI.我应该使用什么方法?ContentObserver到目前为止,我看到的信息很少.这是要走的路吗?

android android-contentprovider android-loader android-sqlite

7
推荐指数
1
解决办法
5190
查看次数