数据更改时刷新加载程序 - android

Refresh a Loader when data is changed - android

我使用 LoaderManager 和 CursorLoader 使用 ContentProvider 从我的数据库加载数据。 现在,初始负载很好。我有一个 ListView 显示数据库中的所有行(仅名称-字符串适配器)。

现在,当我从数据库中 add/delete 一行时,我想刷新 ListView 以便它显示最近的更改。

目前我只是在提交更改时使用方法 "restartLoader" 重新启动加载程序,但我想问一下是否有另一种方法可以在不重新启动加载程序的情况下执行此操作。

这是我的 activity class 代码: 包裹 com.silverfix.phony.activities;

import java.util.ArrayList;

import com.silverfix.phony.R;
import com.silverfix.phony.contentprovider.PhonyContentProvider;
import com.silverfix.phony.database.RingtonesTable;

import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentValues;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.text.Editable;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnClickListener;
import android.view.View.OnCreateContextMenuListener;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class RingtonesActivity extends Activity implements LoaderCallbacks<Cursor>{

    private final int PICK_RINGTONE_CODE = 1;
    private final int CURSOR_LOADER_ID = 1;
    private final int EDIT_ID = 1;
    private final int DELETE_ID = 2;
    private String[] ContextCommands;
    private ArrayAdapter<String> adapter;
    private ArrayList<String> ringtones;
    private ListView listview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_ringtones);
        listview = (ListView) findViewById(R.id.list);
        Button add = (Button) findViewById(R.id.add_ringtone);
        add.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Intent i = new Intent(
                        Intent.ACTION_PICK,
                        android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
                startActivityForResult(i, PICK_RINGTONE_CODE);
            }
        });
        fillData();
    }

    @Override
    protected void onActivityResult(int arg0, int arg1, Intent arg2) {
        super.onActivityResult(arg0, arg1, arg2);
        switch (arg0) {
        case 1: // PICK_RINGTONE_CODE
            if (arg1 == RESULT_OK) {
                Uri ringtoneURI = arg2.getData();
                String[] projection = { MediaStore.MediaColumns.DISPLAY_NAME };
                Cursor cursor = getContentResolver().query(ringtoneURI,
                        projection, null, null, null);
                cursor.moveToFirst();
                int column = cursor
                        .getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME);
                String displayName = cursor.getString(column);
                addRingtone(ringtoneURI, displayName);
                cursor.close();
            }
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.ringtones, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void fillData() {
        getLoaderManager().initLoader(CURSOR_LOADER_ID, null, this);
        ringtones = new ArrayList<String>();
        adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, ringtones);
        ContextCommands = getResources().getStringArray(R.array.commands);
        listview.setAdapter(adapter);
        listview.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                editRingtone();
            }
        });
        registerForContextMenu(listview);
        listview.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {

            @Override
            public void onCreateContextMenu(ContextMenu menu, View v,
                    ContextMenuInfo menuInfo) {
                if (v.getId()==R.id.list) {
                    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
                    menu.setHeaderTitle(ContextCommands[info.position]);
                    String[] menuItems = getResources().getStringArray(R.array.commands);
                    menu.add(Menu.NONE, EDIT_ID, 0, menuItems[0]);
                    menu.add(Menu.NONE, DELETE_ID, 0, menuItems[1]);
                  }
            }
        });
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        switch(item.getItemId()) {
        case EDIT_ID:
            editRingtone();
            return true;
        case DELETE_ID:
            String name = adapter.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position);
            getContentResolver().delete(PhonyContentProvider.RINGTONES_URI, RingtonesTable.COLUMN_NAME
                    + "='" + name + "'", null);
            return true;
        default:
            return super.onContextItemSelected(item);
        }
    }

    private void editRingtone() {
        Intent i = new Intent(
                Intent.ACTION_PICK,
                android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(i, PICK_RINGTONE_CODE);
    }

    private void addRingtone(Uri uri, String name) {
        String[] projection = { RingtonesTable.COLUMN_NAME };
        Cursor cursor = getContentResolver().query(
                PhonyContentProvider.RINGTONES_URI, projection,
                RingtonesTable.COLUMN_NAME + "='"+name+"'", null, null);
        if (cursor.getCount() == 0) {
            ContentValues values = new ContentValues();
            values.put(RingtonesTable.COLUMN_NAME, name);
            values.put(RingtonesTable.COLUMN_URI, uri.toString());
            getContentResolver().insert(PhonyContentProvider.RINGTONES_URI,
                    values);
            getLoaderManager().restartLoader(CURSOR_LOADER_ID, null, this);
        } else {
            Toast.makeText(this, "You already picked that ringtone!",
                    Toast.LENGTH_LONG).show();
            cursor.close();
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        String[] projection = {RingtonesTable.COLUMN_ID, RingtonesTable.COLUMN_NAME, RingtonesTable.COLUMN_URI};
        return new CursorLoader(this, PhonyContentProvider.RINGTONES_URI, projection, null, null, null);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        swapCursor(data);
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        swapCursor(null);
    }

    private void swapCursor(Cursor cursor) {
        if(cursor != null) {
            cursor.moveToFirst();
            ringtones.clear();
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
                int column = cursor.getColumnIndex(RingtonesTable.COLUMN_NAME);
                ringtones.add(cursor.getString(column));
            }
            adapter.notifyDataSetChanged();
            cursor.close();
            return;
        }
        ringtones.clear();
        adapter.notifyDataSetChanged();
    }
}

由于您已经可以访问加载器,您可能不希望有太大的变化,但另一种实现方式是将游标设置为 PhonyContentProvider.RINGTONES_URI 作为其通知 uri 并在任何时候通知 uri数据库数据发生变化。

相关方法:
setNotificationUri
notifyChange