我有一个DialogFragment
,我正在努力展示两个旋转器,并排显示一个驱动器列表,另一个显示车辆列表。
从sqlite数据库中检索填充这些微调器的数据。我正在尝试使用LoaderManager
来更新微调器或与数据库表(驱动程序和工具)保持同步。
当我在数据库的驱动程序表或车辆表中添加/删除/编辑记录时,微调器不会更新,驱动程序或车辆在微调器中保持不变。
我不确定我缺少什么,因为我认为LoaderManager
应该保持列表更新或自动与数据库表同步?
我创建了一个名为addDriverVehicle()
的按钮,该按钮应该允许用户在将来添加另一个驱动程序/车辆但是现在我用它作为测试来删除驱动程序以模拟数据库表格改变,所以我可以看到微调器是否自动更新,但它没有发生。该记录正在删除,但是微调器继续显示它。
public class DriverVehiclePickersDialogFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemSelectedListener {
public static final String ARG_LISTENER_TYPE = "listenerType";
public static final String ARG_DIALOG_TYPE = "dialogType";
public static final String ARG_TITLE_RESOURCE = "titleResource";
public static final String ARG_SET_DRIVER = "setDriver";
public static final String ARG_SET_VEHICLE = "setVehicle";
private static final int DRIVERS_LOADER = 0;
private static final int VEHICLES_LOADER = 1;
private DriverVehicleDialogListener mListener;
// These are the Adapter being used to display the driver's and vehicle's data.
SimpleCursorAdapter mDriversAdapter, mVehiclesAdapter;
// Define Dialog view
private View mView;
// Store Driver and Vehicle Selected
private long[] mDrivers, mVehicles;
// Spinners Containing Driver and Vehicle List
private Spinner driversSpinner;
private Spinner vehiclesSpinner;
private static enum ListenerType {
ACTIVITY, FRAGMENT
}
public static enum DialogType {
DRIVER_SPINNER, VEHICLE_SPINNER, DRIVER_VEHICLE_SPINNER
}
public interface DriverVehicleDialogListener {
public void onDialogPositiveClick(long[] mDrivers, long[] mVehicles);
}
public DriverVehiclePickersDialogFragment() {
// Empty Constructor
Log.d("default", "default constructor ran");
}
public static DriverVehiclePickersDialogFragment newInstance(DriverVehicleDialogListener listener, Bundle dialogSettings) {
final DriverVehiclePickersDialogFragment instance;
if (listener instanceof Activity) {
instance = createInstance(ListenerType.ACTIVITY, dialogSettings);
} else if (listener instanceof Fragment) {
instance = createInstance(ListenerType.FRAGMENT, dialogSettings);
instance.setTargetFragment((Fragment) listener, 0);
} else {
throw new IllegalArgumentException(listener.getClass() + " must be either an Activity or a Fragment");
}
return instance;
}
private static DriverVehiclePickersDialogFragment createInstance(ListenerType listenerType, Bundle dialogSettings) {
DriverVehiclePickersDialogFragment fragment = new DriverVehiclePickersDialogFragment();
if (!dialogSettings.containsKey(ARG_LISTENER_TYPE)) {
dialogSettings.putSerializable(ARG_LISTENER_TYPE, listenerType);
}
if (!dialogSettings.containsKey(ARG_DIALOG_TYPE)) {
dialogSettings.putSerializable(ARG_DIALOG_TYPE, DialogType.DRIVER_VEHICLE_SPINNER);
}
if (!dialogSettings.containsKey(ARG_TITLE_RESOURCE)) {
dialogSettings.putInt(ARG_TITLE_RESOURCE, 0);
}
fragment.setArguments(dialogSettings);
return fragment;
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Find out how to get the DialogListener instance to send the callback events to
Bundle args = getArguments();
ListenerType listenerType = (ListenerType) args.getSerializable(ARG_LISTENER_TYPE);
switch (listenerType) {
case ACTIVITY: {
// Send callback events to the hosting activity
mListener = (DriverVehicleDialogListener) activity;
break;
}
case FRAGMENT: {
// Send callback events to the "target" fragment
mListener = (DriverVehicleDialogListener) getTargetFragment();
break;
}
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
Button btnAddDriverVehicle = (Button) mView.findViewById(R.id.addDriverVehicleButton);
btnAddDriverVehicle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DatabaseHelper1 mOpenHelper = new DatabaseHelper1(getActivity());
try {
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
db.delete("drivers", " driver_number = 70", null);
} catch (SQLException e) {
}
}
});
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
Bundle args = getArguments();
int titleResource = args.getInt(ARG_TITLE_RESOURCE);
DialogType dialogType = (DialogType) args.getSerializable(ARG_DIALOG_TYPE);
if (args.containsKey(ARG_SET_DRIVER)) {
mDrivers = args.getLongArray(ARG_SET_DRIVER);
}
if (args.containsKey(ARG_SET_VEHICLE)) {
mVehicles = args.getLongArray(ARG_SET_VEHICLE);
}
mView = LayoutInflater.from(getActivity()).inflate(R.layout.driver_vehicle_dialog, null);
if ((dialogType == DialogType.DRIVER_SPINNER) || (dialogType == DialogType.DRIVER_VEHICLE_SPINNER)) {
driversSpinner = (Spinner) mView.findViewById(R.id.driversSpinner);
vehiclesSpinner = (Spinner) mView.findViewById(R.id.vehiclesSpinner);
driversSpinner.setVisibility(View.VISIBLE);
mDriversAdapter = new SimpleCursorAdapter(getActivity(), R.layout.driver_listview_row, null, new String[] { ConsoleContract.Drivers.DRIVER_NUMBER,
ConsoleContract.Drivers.DRIVER_NAME }, new int[] { R.id.driver_number, R.id.driver_name }, 0);
driversSpinner.setAdapter(mDriversAdapter);
driversSpinner.setOnItemSelectedListener(this);
}
if ((dialogType == DialogType.VEHICLE_SPINNER) || (dialogType == DialogType.DRIVER_VEHICLE_SPINNER)) {
vehiclesSpinner.setVisibility(View.VISIBLE);
mVehiclesAdapter = new SimpleCursorAdapter(getActivity(), R.layout.vehicle_listview_row, null, new String[] { ConsoleContract.Vehicles.VEHICLE_NUMBER,
ConsoleContract.Vehicles.VEHICLE_VIN }, new int[] { R.id.vehicle_number, R.id.vehicle_vin }, 0);
vehiclesSpinner.setAdapter(mVehiclesAdapter);
vehiclesSpinner.setOnItemSelectedListener(this);
}
// Prepare the loader. Either re-connect with an existing one, or start a new one.
getLoaderManager().initLoader(DRIVERS_LOADER, null, this);
getLoaderManager().initLoader(VEHICLES_LOADER, null, this);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(mView);
if (titleResource == 0) {
builder.setMessage("Select Driver and Vehicle");
} else {
builder.setMessage(getString(titleResource));
}
builder.setPositiveButton(android.R.string.ok, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mListener.onDialogPositiveClick(mDrivers, mVehicles);
}
});
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
private static class DatabaseHelper1 extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "test.db";
private static final int DATABASE_VERSION = 1;
DatabaseHelper1(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
// These are the Contacts rows that we will retrieve.
static final String[] DRIVERS_SUMMARY_PROJECTION = new String[] { ConsoleContract.Drivers._ID, ConsoleContract.Drivers.DRIVER_ID, ConsoleContract.Drivers.DRIVER_NUMBER,
ConsoleContract.Drivers.DRIVER_NAME };
static final String[] VEHICLES_SUMMARY_PROJECTION = new String[] { ConsoleContract.Vehicles._ID, ConsoleContract.Vehicles.VEHICLE_ID, ConsoleContract.Vehicles.VEHICLE_NUMBER,
ConsoleContract.Vehicles.VEHICLE_VIN };
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// First, pick the base URI to use depending on whether we are
// currently filtering.
Uri baseUri = null;
String select = null, sortOrder = null;
String[] projection = null;
switch (id) {
case DRIVERS_LOADER:
baseUri = ConsoleContract.Drivers.CONTENT_URI;
select = "((" + Drivers.DRIVER_NAME + " NOT NULL) AND (" + Drivers.DRIVER_NAME + " != '' ))";
sortOrder = Drivers.DRIVER_NUMBER;
projection = DRIVERS_SUMMARY_PROJECTION;
break;
case VEHICLES_LOADER:
baseUri = ConsoleContract.Vehicles.CONTENT_URI;
select = "((" + Vehicles.VEHICLE_NUMBER + " NOT NULL) AND (" + Vehicles.VEHICLE_NUMBER + " != '' ))";
sortOrder = Vehicles.VEHICLE_NUMBER;
projection = VEHICLES_SUMMARY_PROJECTION;
break;
}
return new CursorLoader(getActivity(), baseUri, projection, select, null, sortOrder);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
int id = loader.getId();
MatrixCursor newCursor = null;
switch (id) {
case DRIVERS_LOADER:
newCursor = new MatrixCursor(DRIVERS_SUMMARY_PROJECTION);
break;
case VEHICLES_LOADER:
newCursor = new MatrixCursor(VEHICLES_SUMMARY_PROJECTION);
break;
}
newCursor.addRow(new String[] { "0", "0", "", "" });
Cursor[] cursors = { newCursor, data };
Cursor mergedCursor = new MergeCursor(cursors);
switch (id) {
case DRIVERS_LOADER:
mDriversAdapter.swapCursor(mergedCursor);
break;
case VEHICLES_LOADER:
mVehiclesAdapter.swapCursor(mergedCursor);
break;
}
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
int id = loader.getId();
switch (id) {
case DRIVERS_LOADER:
mDriversAdapter.swapCursor(null);
break;
case VEHICLES_LOADER:
mVehiclesAdapter.swapCursor(null);
break;
}
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (parent.getId() == R.id.driversSpinner) {
mDriver = id;
} else {
mVehicle = id;
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
}
答案 0 :(得分:1)
确保ContentProvider
在插入,删除和更新方法中调用notifyChange()
方法。
public Uri insert(Uri uri, ContentValues values) {
if (URI_MATCHER.match(uri) != LENTITEM_LIST) {
throw new IllegalArgumentException("Unsupported URI for insertion: " + uri);
}
long id = db.insert(DBSchema.TBL_ITEMS, null, values);
if (id > 0) {
// notify all listeners of changes and return itemUri:
Uri itemUri = ContentUris.withAppendedId(uri, id);
getContext().getContentResolver().notifyChange(itemUri, null);
return itemUri;
}
// s.th. went wrong:
throw new SQLException("Problem while inserting into " + DBSchema.TBL_ITEMS + ", uri: " + uri); // use another exception here!!!
}
相反,您的Loader不会“听到”DB更改。
答案 1 :(得分:0)
@Override
public Cursor query(Uri uri,String [] projection,String selection,String [] selectionArgs,String sort){
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
Cursor cursor = queryBuilder.query(dbHelper.getReadableDatabase(), 投影, 选择, selectionArgs两个, 空值, 空值, 排序);
cursor.setNotificationUri(getContext()。getContentResolver(),uri);
返回光标;
}