ContentResolver Client App无法从ContentProvider中找到表

时间:2015-08-05 15:07:42

标签: android android-sqlite android-contentprovider

无法真正找到这个特定案例的答案。我正在尝试从我的contentprovider应用程序已经存在的数据库中实现对所有行的非常简单的提取,并在列表视图中填充行。

我的客户端收到经典错误

android.database.sqlite.SQLiteException: no such table: names (code 1): , while compiling: SELECT * FROM names
            at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:181)
            at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
            at android.content.ContentProviderProxy.query(ContentProviderNative.java:421)
            at android.content.ContentResolver.query(ContentResolver.java:478)
            at android.content.CursorLoader.loadInBackground(CursorLoader.java:64)
            at com.example.user.myclient.MainActivity.onCreate(MainActivity.java:25)

以下是MyClient主要的简单代码:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Uri uri = Uri.parse("content://map524.myfriends");
        Cursor c;
        CursorLoader cl = new CursorLoader(this, uri, null, null, null, null);
        c = cl.loadInBackground();

        String[] columns = new String[] {
            "Id", "name", "phone", "email"
        };

        int[] views = new int[] {
          R.id.namesId, R.id.names, R.id.phone, R.id.email
        };
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns, views);

        ListView lv = (ListView)findViewById(R.id.listView);
        lv.setAdapter(adapter);
    }

内容提供者的类只执行“SELECT * FROM names”,它是数据库中的现有表。此查询在包含数据库文件作为资产的本地应用程序上完美运行。 当我继续运行内容提供商应用程序,然后尝试在同一个AVD 上运行我的内容解析器/客户端应用程序时,会发生错误:

// MyDBProvider class
public class FriendsProvider extends ContentProvider {
    MySQLiteHelper dbHelper;

// ... Required blank methods all exist of course, but not implemented
 @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.

        dbHelper = new MySQLiteHelper(getContext());
        return false;
    }
@Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        // TODO: Implement this to handle query requests from clients.
        SQLiteDatabase db = dbHelper.getReadableDatabase();

        return db.query("names", projection, selection, selectionArgs, null, null, sortOrder);
    } 

此代码在contentProvider的本地应用程序中运行良好:

public class MySQLiteHelper extends SQLiteOpenHelper {
    public static final String TABLE_NAMES = "names";
    public static final String COLUMN_ID = "_id";
    public static final String COLUMN_NAME = "name";

    private static final String DATABASE_NAME = "names.db";
    private static String DB_PATH = "";
    private static final int DATABASE_VERSION = 3;
    private static final String DATABASE_CREATE = "CREATE TABLE names (_id integer PRIMARY KEY, name text, phone text, email text);";
    private final Context mContext;
    private SQLiteDatabase mDataBase;

    public MySQLiteHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        DB_PATH = context.getDatabasePath(DATABASE_NAME).getPath();

        this.mContext = context;
    }

    public void createDataBase() throws IOException {
        //If database not exists copy it from the assets
        boolean mDataBaseExist = checkDataBase();
        if(!mDataBaseExist)
        {
            this.getReadableDatabase();
            try
            {
                //Copy the database from assets
                copyDataBase();
                Log.e("MySQLiteHelper", "createDatabase database created");
            }
            catch (IOException mIOException)
            {
                throw new Error("ErrorCopyingDataBase");
            }
        }
    }

    private boolean checkDataBase() {
        File dbFile = new File(DB_PATH + DATABASE_NAME);
        //Log.v("dbFile", dbFile + "   "+ dbFile.exists());
        return dbFile.exists();
    }

    private void copyDataBase() throws IOException
    {
        InputStream mInput = mContext.getAssets().open(DATABASE_NAME);
        String outFileName = DB_PATH + DATABASE_NAME;
        OutputStream mOutput = new FileOutputStream(outFileName);
        byte[] mBuffer = new byte[1024];
        int mLength;
        while ((mLength = mInput.read(mBuffer))>0)
        {
            mOutput.write(mBuffer, 0, mLength);
        }
        mOutput.flush();
        mOutput.close();
        mInput.close();
    }

    public boolean openDataBase() throws SQLException
    {
        String mPath = DB_PATH + DATABASE_NAME;
        mDataBase = SQLiteDatabase.openDatabase(mPath, null, SQLiteDatabase.CREATE_IF_NECESSARY);
        return mDataBase != null;
    }

    @Override
    public void onCreate(SQLiteDatabase database) {
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

    public Cursor fetchRows() {
        String query = "SELECT * FROM " + TABLE_NAMES;
        Cursor cursor = mDataBase.rawQuery(query, null);
        return cursor;
    }

    @Override
    public synchronized void close()
    {
        if(mDataBase != null)
            mDataBase.close();
        super.close();
    }

提前谢谢,一如既往。     }

1 个答案:

答案 0 :(得分:0)

显然这里的问题是我的内容提供者逻辑最终试图直接访问SQLiteHelper实例,而不是使用处理它的数据访问对象/数据库适配器类逻辑。我的理解是,在这种情况下尝试直接使用SQLiteHelper实例实现原始查询是尝试从没有任何表的文件结构中的数据库中查询表。

我的新工作逻辑是这样的:

// In the provider class instance
NamesDataSource dbHelper;

 @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.
        dbHelper = new NamesDataSource(getContext());
        try {
            dbHelper.open();
        }
        catch (SQLException se) {
            se.printStackTrace();
        }
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        // TODO: Implement this to handle query requests from clients.
        //return db.query("names", projection, selection, selectionArgs, null, null,  sortOrder);
        return dbHelper.getRowsCursor();
    }
// ... rest of blank required implementation methods
}

数据访问对象/数据库适配器类:

public class NamesDataSource {
    private MySQLiteHelper dbHelper;

public NamesDataSource(Context context) {
        dbHelper = new MySQLiteHelper(context);
    }

public void open() throws SQLException {
        try {
            dbHelper.createDataBase();
        }
        catch (Exception ioe) {
            throw new Error("Unable to create database");
        }
        try {
            dbHelper.openDataBase();
        }
        catch(Exception se){
            se.printStackTrace();
        }
    }

public Cursor getRowsCursor() {
        return dbHelper.fetchRows();
    }
}

SQLiteHelper类不会改变其逻辑。客户端应用程序代码现在使用此逻辑来检索查询数据:

public class MainActivity extends Activity {
    Uri uri = Uri.parse("content://map524.myfriends");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("CLIENT", "Starting");
        fetchAll();
    }

public void fetchAll() {
        Cursor c = getContentResolver().query(uri, null,null,null,null);

        String[] columns = new String[] {
                "_id", "name", "phone", "email"
        };

        int[] views = new int[] {
                R.id.namesId, R.id.names, R.id.phone, R.id.email
        };

        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.activity_main, c, columns, views);

        ListView lv = (ListView)findViewById(R.id.listView);
        lv.setAdapter(adapter);
    }
}