【问题标题】:loadinBackground() called during configuration Change在配置更改期间调用的 loadinBackground()
【发布时间】:2015-03-31 08:30:02
【问题描述】:

我正在制作一个显示邮政编码列表(在 ListView 中)的应用程序,当我单击它时,它会使用 OpenWeather API 向我显示详细的天气报告。邮政编码列表存储在 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

谢谢,

【问题讨论】:

    标签: android loader asynctaskloader


    【解决方案1】:

    您在 initLoader() 返回的加载程序上调用 forceLoad()。这将导致加载程序重新加载数据,即使它之前已经检索过该数据。您应该不需要调用此方法,只需调用initLoader()

    【讨论】:

    • 感谢您的响应。当我不添加 forceLoad() 时,根本不会调用我的加载程序回调。你能告诉我为什么会这样吗?
    【解决方案2】:

    forceLoad() 不会自动调用,但需要启动数据加载。

    但是forceLoad() 应该在onStartLoading() 内完成,而不是在initLoader() 上调用

    从 API 级别 28(Android Pie) 起,AsyncTaskLoaders 已被弃用。

    【讨论】:

      【解决方案3】:

      AsyncTask 在调用myAsyncTask.execute() 时自动运行后台任务不同,AsyncTaskLoader 在调用getSupportLoaderManager().initLoader(MY_LOADER_ID, null, this) 时不会自动运行后台线程;要强制它运行后台线程,您需要通过两种方式显式调用 Loader 对象上的 forceLoad():

      首先:使用 getSupportLoaderManager().initLoader(MY_LOADER_ID, null, this).forceLoad();getSupportLoaderManager().initLoader(MY_LOADER_ID, null, this).forceLoad(); 使用 LoaderManager 初始化/激活加载器时按方法链进行

      第二个:getSupportLoaderManager().initLoader(...)自动触发的自定义加载器类onStartLoading()回调中

      @Override
      protected void onStartLoading() {
          super.onStartLoading();
          forceLoad(); // call loadInBackground()
      }
      

      显然对于配置更改,这两个方法都将调用 loadInBackground() 方法,因为 onCreate() 方法将在屏幕旋转时触发,随后 getSupportLoaderManager().initLoader(...)forceLoad() 将被相应调用,但隐含地您可以使用第二种方法来通过使用deliverResult() 方法停止不必要地调用loadInBackground(),该方法将先前加载的结果传递给已注册侦听器的onLoadFinished() 方法,这反过来又允许我们跳过loadInBackground() 调用。

      那么,您需要在代码中进行哪些更改:

      @Override
      public void onActivityCreated(Bundle savedInstanceState)
      {
          super.onActivityCreated(savedInstanceState);
          setRetainInstance(true);
          getLoaderManager().initLoader(LOADER_ID, null, this);
      }
      

      这里是加载器

      public class DataLoader extends AsyncTaskLoader<List<RowItem>> {
      
          Context activityContext;
          private String TAG="DataLoader";
          private List<RowItem> rowItems;
      
          public DataLoader(Context context){
              super(context);
              this.activityContext = context;
          }
      
          @Override
          protected void onStartLoading() {
              super.onStartLoading();
              if (rowItems != null) {
                  deliverResult(rowItems); // skip loadInBackground() call
              } else {
                  forceLoad(); // call loadInBackground()
              }
          }
      
      
          @Override
          public List<RowItem> loadInBackground(){
              Log.v(TAG, "loadinBackground() IN");
              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;
          }
      }
      

      值得一提的是,Loaders 自 Android P (API 28) 起已被弃用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-01
        • 2023-03-29
        • 1970-01-01
        相关资源
        最近更新 更多