Android 设备旋转导致的ViewPager和LoaderManager错误
我使用一个有3个片段的ViewPager。另外,使用LoaderManager加载每个片段数据。我实现了自己的加载器,但是如果我旋转设备并且实际选择了加载器选项卡,则分页器和加载器的组合将以NullPointerException运行。这是我的日志 java.lang.NullPointerException android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:960) android.support.v4.app.FragmentManagerImpl.performPendingDeferredStart(FragmentManager.java:768) FragmentManagerImpl.startPendingDeferredFragments(FragmentManager.java:1104) android.support.v4.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:410) android.support.v4.content.Loader.deliverResult(Loader.java:103) com.android.droidbridge.loader.FridgeLoader.deliverResult(FridgeLoader.java:144) com.android.droidbridge.loader.FridgeLoader.deliverResult(FridgeLoader.java:1) android.support.v4.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:221) android.support.v4.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:61) android.support.v4.content.ModernAsyncTask.finish(ModernAsyncTask.java:461) android.support.v4.content.ModernAsyncTask.access$500(ModernAsyncTask.java:47) android.support.v4.content.ModernAsyncTask$InternalHandler.handleMessage(ModernAsyncTask.java:474) 以下是我的完整加载程序代码:Android 设备旋转导致的ViewPager和LoaderManager错误,android,android-viewpager,android-loadermanager,Android,Android Viewpager,Android Loadermanager,我使用一个有3个片段的ViewPager。另外,使用LoaderManager加载每个片段数据。我实现了自己的加载器,但是如果我旋转设备并且实际选择了加载器选项卡,则分页器和加载器的组合将以NullPointerException运行。这是我的日志 java.lang.NullPointerException android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:960) android.suppo
package com.android.droidfridge.loader;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeSet;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import android.util.Log;
import com.android.droidfridge.adapters.FridgeEntryItem;
import com.android.droidfridge.adapters.Item;
import com.android.droidfridge.adapters.SectionItem;
import com.android.droidfridge.database.DatabaseHelper;
import com.android.droidfridge.database.Items;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.QueryBuilder;
public class FridgeLoader extends AsyncTaskLoader<List<Item>>
{
private final static String TAG = "FridgeLoader";
private DatabaseHelper db = null;
private List<Item> item;
private ItemComparator option;
private boolean ascending;
public FridgeLoader( Context context, DatabaseHelper db, ItemComparator option, boolean ascending )
{
super( context );
this.db = db;
this.option = option;
this.ascending = ascending;
}
@Override
public List<Item> loadInBackground()
{
Log.i( TAG, "Started loadInBackground." );
ArrayList<Item> result = new ArrayList<Item>();
TreeSet<String> sections = new TreeSet<String>();
try
{
// search for all items
Dao<Items, Integer> dao = db.getItemsDao();
QueryBuilder<Items, Integer> builder = dao.queryBuilder();
builder.where().gt( Items.ACTUAL_AMOUNT_COLUMN, 0 );
List<Items> data = dao.query( builder.prepare() );
// sort items list
data = sortData( data );
// create list view items
for( Items item : data )
{
// add Category
if( !sections.contains( item.getCategory().getName() ) )
{
sections.add( item.getCategory().getName() );
result.add( new SectionItem( item.getCategory() ) );
}
// add Item
result.add( new FridgeEntryItem( item ) );
}
}
catch( SQLException e )
{
Log.e( TAG, "loadInBackground: " + e.getMessage() );
}
return result;
}
private List<Items> sortData( List<Items> data )
{
//...
return sortedResult;
}
@Override
public void deliverResult( List<Item> data )
{
if( isReset() )
{
if( data != null )
{
onReleaseResources( data );
}
}
List<Item> oldData = data;
item = data;
if( isStarted() )
{
super.deliverResult( data );
}
if( oldData != null )
{
onReleaseResources( oldData );
}
}
@Override
protected void onStartLoading()
{
Log.d( TAG, "onStartLoading()" );
if( item != null )
{
deliverResult( item );
}
if( takeContentChanged() || item == null )
{
forceLoad();
}
}
@Override
protected void onStopLoading()
{
Log.d( TAG, "onStopLoading()" );
cancelLoad();
}
@Override
public void onCanceled( List<Item> data )
{
Log.d( TAG, "onCanceled()" );
super.onCanceled( data );
onReleaseResources( data );
}
@Override
protected void onReset()
{
Log.d( TAG, "onReset()" );
super.onReset();
onStopLoading();
if( item != null )
{
onReleaseResources( item );
item = null;
}
}
private void onReleaseResources( List<Item> data )
{
}
}
package com.android.droidbridge.loader;
导入java.sql.SQLException;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.HashMap;
导入java.util.LinkedList;
导入java.util.List;
导入java.util.TreeSet;
导入android.content.Context;
导入android.support.v4.content.AsyncTaskLoader;
导入android.util.Log;
导入com.android.droidbridge.adapters.FridgeEntryItem;
导入com.android.droidbridge.adapters.Item;
导入com.android.droidbridge.adapters.SectionItem;
导入com.android.droidbridge.database.DatabaseHelper;
导入com.android.droidbridge.database.Items;
导入com.j256.ormlite.dao.dao;
导入com.j256.ormlite.stmt.QueryBuilder;
公共类FridgeLoader扩展了AsyncTaskLoader
{
私有最终静态字符串标记=“FridgeLoader”;
私有DatabaseHelper db=null;
私人清单项目;
私人项目比较选项;
私有布尔递增;
公共FridgeLoader(上下文上下文、DatabaseHelper db、ItemComparator选项、布尔升序)
{
超级(上下文);
这个.db=db;
this.option=选项;
这个上升=上升;
}
@凌驾
公共列表加载背景()
{
Log.i(标签“startedloadinbackground.”);
ArrayList结果=新建ArrayList();
树集节=新树集();
尝试
{
//搜索所有项目
Dao=db.getItemsDao();
QueryBuilder builder=dao.QueryBuilder();
builder.where().gt(Items.ACTUAL\u AMOUNT\u列,0);
List data=dao.query(builder.prepare());
//排序项目列表
数据=排序数据(数据);
//创建列表视图项
用于(项目:数据)
{
//添加类别
如果(!sections.contains(item.getCategory().getName()))
{
添加(item.getCategory().getName());
添加(新的SectionItem(item.getCategory());
}
//添加项
结果.添加(新FridgeEntryItem(项目));
}
}
捕获(SQLE异常)
{
Log.e(标记“loadInBackground:+e.getMessage());
}
返回结果;
}
私有列表排序数据(列表数据)
{
//...
返回分类结果;
}
@凌驾
公共无效交付结果(列表数据)
{
if(isReset())
{
如果(数据!=null)
{
发布资源(数据);
}
}
列出旧数据=数据;
项目=数据;
如果(isStarted())
{
super.deliverResult(数据);
}
如果(旧数据!=null)
{
onReleaseResources(旧数据);
}
}
@凌驾
开始加载时受保护的void()
{
Log.d(标记“onStartLoading()”);
如果(项!=null)
{
交付结果(项目);
}
if(takeContentChanged()|| item==null)
{
力载荷();
}
}
@凌驾
受保护的无效onStopLoading()
{
Log.d(标记“onStopLoading()”);
取消加载();
}
@凌驾
已取消公共作废(列表数据)
{
Log.d(标记“onCanceled()”);
super.onCanceled(数据);
发布资源(数据);
}
@凌驾
受保护的void onReset()
{
Log.d(标记“onReset()”);
super.onReset();
onStopLoading();
如果(项!=null)
{
释放资源(项目);
item=null;
}
}
私有void onReleaseResources(列表数据)
{
}
}
我找到了解决问题的方法。它位于一个片段事务中。重要的一点是:
setRetainInstance( true );
这一行是从我的片段使用这个加载程序从上面。它在他的构造函数中。你能添加
com.android.droidbridge.loader.FridgeLoader.deliverResult的代码吗?
请?我编辑了我的问题并添加了加载程序代码。现在我对这个问题有了更多的了解。这在viewPager中不是问题,在FragmentManager中更是如此。因为ViewPager通过内部标记策略重用片段。这意味着setRetainInstance(true)是开销。我不清楚为什么会有这个例外。谢谢!这解决了我的问题,节省了我很多时间。对我来说很好!