使用AsyncTaskLoader填充ListView

时间:2013-07-05 12:40:11

标签: android asynctaskloader

我在使用AsyncTaskLoader时遇到问题。这是我第一次尝试使用加载程序从 SQLite 数据库填充 ListView

一切似乎都没问题,当我旋转屏幕时,数据被缓存并且不再进行任何查询。但是当我按下主页按钮并再次启动我的应用程序时,数据会再次加载。

注意Usuario表示User,因此我使用用户列表填充 ListView

public class Main extends SherlockFragmentActivity
        implements LoaderManager.LoaderCallbacks<ArrayList<Usuario>> {
    UsuarioAdapter adapter;
    ListView listView;
    Database db;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        listView = (ListView) findViewById(R.id.lista);
        db       = new Database(this);
        adapter  = new UsuarioAdapter(this, new ArrayList<Usuario>());
        listView.setAdapter(adapter);
        getSupportLoaderManager().initLoader(0, null, this);
    }

    @Override
    public Loader<ArrayList<Usuario>> onCreateLoader(int id, Bundle args) {
        return new UsuariosLoader(this, db);
    }

    @Override
    public void onLoadFinished(Loader<ArrayList<Usuario>> loader,
                           ArrayList<Usuario> usuarios) {
       //adapter.notifyDataSetChanged();
      listView.setAdapter(new UsuarioAdapter(this, usuarios));
      // ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
    }

    @Override
    public void onLoaderReset(Loader<ArrayList<Usuario>> loader) {
        listView.setAdapter(null);
    }
}

// THE LOADER
class UsuariosLoader extends AsyncTaskLoader<ArrayList<Usuario>> {
    private ArrayList<Usuario> usuarios;
    private Database db;

    public UsuariosLoader(Context context, Database db) {
        super(context);
        this.db = db;
    }

    @Override
    protected void onStartLoading() {
        if (usuarios != null) {
          deliverResult(usuarios); // Use the cache
        }
       forceLoad();
    }

    @Override
    protected void onStopLoading() {
        // The Loader is in a stopped state, so we should attempt to cancel the
        // current load (if there is one).
        cancelLoad();
    }

    @Override
    public ArrayList<Usuario> loadInBackground() {              
        db.open();  // Query the database
        ArrayList<Usuario> usuarios = db.getUsuarios();
        db.close();
        return usuarios;
    }

    @Override
    public void deliverResult(ArrayList<Usuario> data) {
        usuarios = data; // Caching
        super.deliverResult(data);
    }

    @Override
    protected void onReset() {
       super.onReset();
       // Stop the loader if it is currently running
       onStopLoading();
       // Get rid of our cache if it exists
       usuarios = null;
    }

    @Override
    public void onCanceled(ArrayList<Usuario> data) {
       // Attempt to cancel the current async load
       super.onCanceled(data);
       usuarios = null;
   }
}

我觉得这个片段做得不好。我正在创建一个新的适配器,而不是更新数据。

    @Override
    public void onLoadFinished(Loader<ArrayList<Usuario>> loader,
                           ArrayList<Usuario> usuarios) {
        //adapter.notifyDataSetChanged();
        listView.setAdapter(new UsuarioAdapter(this, usuarios));
        //((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();
    }

为什么adapter.notifyDataSetChanged()不起作用?

所以,基本上,我的应用程序不会崩溃,但每次重新启动应用程序时,我的所有数据都会重新加载。

修改:这是我的适配器代码:

    class UsuarioAdapter extends BaseAdapter {
    private ArrayList<Usuario> usuarios;
    private LayoutInflater inflater;

    public UsuarioAdapter(Context context, ArrayList<Usuario> usuarios) {
        this.usuarios = usuarios;
        this.inflater = LayoutInflater.from(context);
    }

    @Override
    public int getCount() { return usuarios.size(); }
    @Override
    public Object getItem(int pos) { return usuarios.get(pos); }
    @Override
    public long getItemId(int pos) { return pos; }

    @Override
    public View getView(int pos, View convertView, ViewGroup arg) {
        LinearLayout itemView;
        if (convertView == null) {
            itemView = (LinearLayout) inflater.inflate(R.layout.list_item, null);
        } else {
            itemView = (LinearLayout) convertView;
        }

        ImageView avatar = (ImageView) itemView.findViewById(R.id.avatar);
        TextView nombre  = (TextView) itemView.findViewById(R.id.nombre);
        TextView edad    = (TextView)itemView.findViewById(R.id.edad);

        // Set the image ... TODO
        nombre.setText(usuarios.get(pos).getNombre());
        edad.setText(String.valueOf(usuarios.get(pos).getEdad()));
        return itemView;
    }
}

2 个答案:

答案 0 :(得分:3)

notifyDataSetChanged()的调用不会更改适配器正在使用的数据。您需要更新适配器具有的数据,然后调用该方法。

NotifyDataSetChanged()只会告诉适配器创建视图所需的适配器,但它不会更改数据。你需要自己处理。

在适配器中添加:

public void setUsuario(List<Usuario> usuarios) {
    this.usuarios = usuarios;
}

然后在onLoadFinished()中调用新方法,然后notifyDataSetChanged()

listView.getAdapter().setUsuario(usuarios);
listView.getAdapter().notifiyDataSetChanged();

答案 1 :(得分:2)

我找到了解决方案。 onStartLoading是有罪的:

    @Override
    protected void onStartLoading() {
        if (usuarios != null) {
            deliverResult(usuarios); // Use cache
        } else {
            forceLoad();
        }
    }

我的原始帖子forceLoad总是被调用。它必须位于else分支。