ContentResolver 客户端应用无法从 ContentProvider 中找到 table
ContentResolver Client App cannot find table from ContentProvider
无法真正找到这个特定案例的答案。我正在尝试从我的 contentprovider 应用程序的现有数据库中实现对所有行的非常简单的提取,并在列表视图中填充这些行。
我的客户端收到 classic 错误
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的main中的简单代码:
@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);
}
内容提供者的 class 只是执行一个 "SELECT * FROM names",这是数据库中现有的 table。此查询在包含数据库文件作为资产的本地应用程序上完美运行。 当我继续 运行 内容提供商应用程序,然后尝试 运行 我的内容 resolver/client 应用程序在同一个 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();
}
一如既往地提前致谢。
}
显然这里的问题是我的内容提供程序逻辑最终尝试直接访问 SQLiteHelper 实例,而不是使用处理它的数据访问 Object/Database 适配器 class 逻辑。我的理解是,在这种情况下,尝试直接使用 SQLiteHelper 实例实现原始查询是试图从文件结构中没有任何 table 的数据库中查询 table。
我的新工作逻辑是这样的:
// 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
}
数据访问Object/Database适配器Class:
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 class 没有改变它的逻辑。客户端应用程序代码现在使用此逻辑来检索查询数据:
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);
}
}
无法真正找到这个特定案例的答案。我正在尝试从我的 contentprovider 应用程序的现有数据库中实现对所有行的非常简单的提取,并在列表视图中填充这些行。
我的客户端收到 classic 错误
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的main中的简单代码:
@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);
}
内容提供者的 class 只是执行一个 "SELECT * FROM names",这是数据库中现有的 table。此查询在包含数据库文件作为资产的本地应用程序上完美运行。 当我继续 运行 内容提供商应用程序,然后尝试 运行 我的内容 resolver/client 应用程序在同一个 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();
}
一如既往地提前致谢。 }
显然这里的问题是我的内容提供程序逻辑最终尝试直接访问 SQLiteHelper 实例,而不是使用处理它的数据访问 Object/Database 适配器 class 逻辑。我的理解是,在这种情况下,尝试直接使用 SQLiteHelper 实例实现原始查询是试图从文件结构中没有任何 table 的数据库中查询 table。
我的新工作逻辑是这样的:
// 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
}
数据访问Object/Database适配器Class:
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 class 没有改变它的逻辑。客户端应用程序代码现在使用此逻辑来检索查询数据:
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);
}
}