我正在创建一个显示zipcodes列表的应用程序(在ListView中),当我点击它时,它会显示使用OpenWeather API的详细天气报告。 zipcodes列表存储在SQLite数据库中并从中检索数据,我使用的是AsyncTaskLoader。数据显示正确。问题是在配置更改期间,正在调用loadinBackground()方法,这不应该发生。
public class DataLoader extends AsyncTaskLoader<List<RowItem>>
{
Context activityContext;
private String TAG="DataLoader";
public DataLoader(Context context)
{
super(context);
this.activityContext = context;
}
@Override
public List<RowItem> loadInBackground()
{
Log.v(TAG, "loadinBackground() IN");
List<RowItem> rowItems = new ArrayList<RowItem>();
DbReaderHelper mDbHelper = new DbReaderHelper(activityContext);
SQLiteDatabase db = mDbHelper.getReadableDatabase();
String[] columns = {DbReaderHelper.COLUMN_CITYNAME,DbReaderHelper.COLUMN_ZIPCODE};
Cursor cur = db.query(DbReaderHelper.TABLE_NAME, columns,null,null,null,null,null);
cur.moveToFirst();
while(!cur.isAfterLast())
{
String city = cur.getString(cur.getColumnIndex(DbReaderHelper.COLUMN_CITYNAME));
String zipcode = cur.getString(cur.getColumnIndex(DbReaderHelper.COLUMN_ZIPCODE));
rowItems.add(new RowItem(city,Integer.parseInt(zipcode)));
cur.moveToNext();
}
cur.close(); // release all the resources
db.close();
mDbHelper.close();
Log.v(TAG, "loadinBackground() OUT");
return rowItems;
}
}
这是Loader Callbacks的实现
public class ListFragment extends Fragment implements LoaderManager.LoaderCallbacks<List<RowItem>>
{
private TextView emptyListTV;
private EditText zipcodeET;
private CustomAdapter customAdapter;
private List<RowItem> rowItems;
private ListView listView;
private final String TAG = "ListFragment";
private boolean fromRemoveItemFromListView = false; // TODO check this again
private final int LOADER_ID = 0x0;
public ListFragment()
{
// empty constructor
}
@Override
public void onCreate(Bundle savedInstanceState)
{
Log.v(TAG,"onCreate() IN");
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
Log.v(TAG,"onCreate() OUT");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_list, container, false);
initializeLayoutViews(view);
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
getLoaderManager().initLoader(LOADER_ID,null,this).forceLoad();
}
@Override
public Loader<List<RowItem>> onCreateLoader(int id, Bundle args)
{
Toast.makeText(getActivity(),"onCreateLoader()",Toast.LENGTH_SHORT).show();
return new DataLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<List<RowItem>> loader, List<RowItem> rowItems)
{
Toast.makeText(getActivity(),"onLoadFinished",Toast.LENGTH_SHORT).show();
customAdapter.setData(rowItems);
customAdapter.notifyDataSetChanged();
setMessageIfListEmpty();
}
@Override
public void onLoaderReset(Loader<List<RowItem>> loader)
{
Toast.makeText(getActivity(),"onLoaderReset()",Toast.LENGTH_SHORT).show();
customAdapter.setData(new ArrayList<RowItem>());
customAdapter.notifyDataSetChanged();
}
}
以下是方向更改时的日志
01-31 22:07:12.532 15019-15019/com.siddhant.myweatherapp D/AbsListView﹕ onDetachedFromWindow
01-31 22:07:12.583 15019-15019/com.siddhant.myweatherapp I/PersonaManager﹕ getPersonaService() name persona_policy
01-31 22:07:12.583 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ onCreate() IN
01-31 22:07:12.653 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ onStart() IN
01-31 22:07:12.733 15019-15019/com.siddhant.myweatherapp D/AbsListView﹕ Get MotionRecognitionManager
01-31 22:07:12.743 15019-15019/com.siddhant.myweatherapp V/ListFragment﹕ onLoadFinished() IN
01-31 22:07:12.743 15019-15019/com.siddhant.myweatherapp V/ListFragment﹕ onLoadFinished() OUT
01-31 22:07:12.743 15019-15019/com.siddhant.myweatherapp V/ListFragment﹕ onLoadFinished() IN
01-31 22:07:12.743 15019-15019/com.siddhant.myweatherapp V/ListFragment﹕ onLoadFinished() OUT
01-31 22:07:12.743 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ onStart() OUT
01-31 22:07:12.753 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ OnResume() IN
01-31 22:07:12.753 15019-15522/com.siddhant.myweatherapp V/DataLoader﹕ loadinBackground() IN
01-31 22:07:12.753 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ onResume() OUT
01-31 22:07:12.803 15019-15019/com.siddhant.myweatherapp E/ViewRootImpl﹕ sendUserActionEvent() mView == null
01-31 22:07:12.813 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ onCreateOptionsMenu() IN
01-31 22:07:12.813 15019-15019/com.siddhant.myweatherapp V/MainActivity﹕ onCreateOptionsMenu() OUT
01-31 22:07:12.953 15019-15522/com.siddhant.myweatherapp V/DataLoader﹕ loadinBackground() OUT
01-31 22:07:12.963 15019-15019/com.siddhant.myweatherapp V/ListFragment﹕ onLoadFinished() IN
01-31 22:07:12.963 15019-15019/com.siddhant.myweatherapp V/ListFragment﹕ onLoadFinished() OUT
谢谢,
答案 0 :(得分:0)
您正在forceLoad()
返回的加载器上调用initLoader()
。这将导致加载程序重新加载数据,即使它之前已经检索过该数据。您不需要调用此方法,只需调用initLoader()
。
答案 1 :(得分:0)
forceLoad()
不会自动调用,但启动数据加载是必需的。
但是forceLoad()
应该在onStartLoading()
内完成,而不要在initLoader()
上调用
从API级别28(Android Pie)开始不推荐使用AsyncTaskLoaders。
答案 2 :(得分:0)
与AsyncTask会在您调用myAsyncTask.execute()
时自动运行后台任务不同,AsyncTaskLoader不会在您调用getSupportLoaderManager().initLoader(MY_LOADER_ID, null, this)
时自动运行后台线程;要强制它运行后台线程,您需要通过两种方式在Loader对象上显式调用forceLoad():
首先:使用带有getSupportLoaderManager().initLoader(MY_LOADER_ID, null, this).forceLoad();
的LoaderManager初始化/激活加载程序时,按方法链进行操作
第二:在自定义加载程序类onStartLoading()
回调中,该回调由getSupportLoaderManager().initLoader(...)
自动触发
@Override
protected void onStartLoading() {
super.onStartLoading();
forceLoad(); // call loadInBackground()
}
显然,对于配置更改,这两个方法都将调用loadInBackground()
方法,因为onCreate()方法将在屏幕旋转时被触发,随后是getSupportLoaderManager().initLoader(...)
,并且forceLoad()
将被相应地调用,但是隐式可以使用第二种方法通过使用loadInBackground()
方法来不必要地停止调用deliverResult()
,该方法将先前加载的结果传递给已注册的侦听器的onLoadFinished()
方法,从而允许我们跳过{{1 }}。
因此,您需要在代码中进行哪些更改:
loadInBackground()
这是装载机
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
值得一提的是,Loaders自Android P(API 28)起已被弃用。