0

我有一个DialogFragment我正在努力显示两个微调器,并排显示一个驱动程序列表,另一个显示车辆列表。

填充这些微调器的数据是从 sqlite 数据库中检索的。我正在尝试使用 aLoaderManager来保持微调器的更新或与数据库表(驱动程序和车辆)同步。

当我在数据库的驱动程序表或车辆表中添加/删除/编辑记录时,微调器不会更新,驱动程序或车辆在微调器中保持不变。

我不确定我错过了什么,因为我认为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) {
    }
}
4

2 回答 2

1

确保在您ContentProvider调用notifyChange()插入、删除和更新方法中的方法。

这里摘自Grokking Android 博客的片段

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!!!
} 

相反,您的加载程序不会“听到”数据库更改。

于 2013-05-03T17:36:27.557 回答
0

@rciovati 的回答对我很好。但对我来说,我在列表视图中使用了光标加载器,因此它还需要在我的 ContentProvider 中的查询方法。在您的 ContentProvider 类中,查询方法还需要在查询后调用通知,如下面的代码 -

@覆盖

公共游标查询(Uri uri,String[] 投影,String 选择,String[] selectionArgs,String 排序){

SQLiteQueryBuilder queryBuilder=new SQLiteQueryBuilder();

光标 cursor=queryBuilder.query(dbHelper.getReadableDatabase(), 投影, 选择, selectionArgs, null, null, sort);

cursor.setNotificationUri(getContext().getContentResolver(), uri);

返回光标;

}

于 2014-12-16T20:21:47.487 回答