• Android入门(十四)内容提供器-实现跨程序共享实例


    原文链接:http://www.orlion.ga/661/

    打开SQLite博文中创建的 DatabaseDemo项目,首先将 MyDatabaseHelper中使用 Toast弹出创建数据库成功的提示去除掉,因为跨程序访问时我们不能直接使用 Toast。然后添加一个 DatabaseProvider类,代码如下所示:

    package ga.orlion.databasedemo;
    
    import android.content.ContentProvider;
    import android.content.ContentValues;
    import android.content.UriMatcher;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    import android.net.Uri;
    
    public class DatabaseProvider extends ContentProvider {
    
    	public static final int BOOK_DIR = 0;
    	
    	public static final int BOOK_ITEM = 1;
    	
    	public static final int CATEGORY_DIR = 2;
    	
    	public static final int CATEGORY_ITEM = 3;
    	
    	public static final String AUTHORITY = "ga.orlion.databasedemo.provider";
    	
    	private static UriMatcher uriMatcher;
    	
    	private MyDatabaseHelper dbHelper;
    	
    	static {
    		uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    		uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
    		uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
    		uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
    		uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
    	}
    	
    	@Override
    	public boolean onCreate() {
    		dbHelper = new MyDatabaseHelper(getContext() , "BookStore.db" , null , 2);
    		return true;
    	}
    
    	@Override
    	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    		
    		SQLiteDatabase db = dbHelper.getReadableDatabase();
    		Cursor cursor = null;
    		switch (uriMatcher.match(uri)) {
    		case BOOK_DIR:
    			cursor = db.query("book", projection, selection, selectionArgs, null, null, sortOrder);
    			break;
    		case BOOK_ITEM:
    			String bookId = uri.getPathSegments().get(1);
    			cursor = db.query("book" , projection , "id = ?" , new String[] {bookId} , null , null , sortOrder);
    			break;
    		case CATEGORY_DIR:
    			cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
    			break;
    		case CATEGORY_ITEM:
    			String categoryId = uri.getPathSegments().get(1);
    			cursor = db.query("Category", projection, "id = ?", new String[]{categoryId}, null, null, sortOrder);
    			break;
    		default:
    			break;
    		}
    		return null;
    	}
    
    	@Override
    	public String getType(Uri uri) {
    		switch (uriMatcher.match(uri)) {
    		case BOOK_DIR:
    			return "vnd.android.cursor.dir/vnd.ga.orlion.databasedemo.provider.book";
    		case BOOK_ITEM:
    			return "vnd.android.cursor.item/vnd.ga.orlion.databasedemo.provider.book";
    		case CATEGORY_DIR:
    			return "vnd.android.cursor.dir/vnd.ga.orlion.databasedemo.provider.category";
    		case CATEGORY_ITEM:
    			return "vnd.android.cursor.item/vnd.ga.orlion.databasedemo.provider.category";
    		}
    		return null;
    	}
    
    	@Override
    	public Uri insert(Uri uri, ContentValues values) {
    		
    		SQLiteDatabase db = dbHelper.getWritableDatabase();
    		Uri uriReturn = null;
    		switch (uriMatcher.match(uri)) {
    		case BOOK_DIR:
    		case BOOK_ITEM:
    			long newBookId = db.insert("book", null, values);
    			uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
    			break;
    		case CATEGORY_DIR:
    		case CATEGORY_ITEM:
    			long newCategoryId = db.insert("Category", null, values);
    			uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
    			break;
    		default:
    			break;
    		}
    		return uriReturn;
    	}
    
    	@Override
    	public int delete(Uri uri, String selection, String[] selectionArgs) {
    		SQLiteDatabase db = dbHelper.getWritableDatabase();
    		int deletedRows = 0;
    		switch (uriMatcher.match(uri)) {
    		case BOOK_DIR:
    			deletedRows = db.delete("Book", selection, selectionArgs);
    			break;
    		case BOOK_ITEM:
    			String bookId = uri.getPathSegments().get(1);
    			deletedRows = db.delete("Book", "id = ?", new String[] { bookId });
    			break;
    		case CATEGORY_DIR:
    			deletedRows = db.delete("Category", selection, selectionArgs);
    			break;
    		case CATEGORY_ITEM:
    			String categoryId = uri.getPathSegments().get(1);
    			deletedRows = db.delete("Category", "id = ?", new String[]
    					{ categoryId });
    			break;
    		default:
    			break;
    		}
    		return deletedRows;
    	}
    
    	@Override
    	public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    		SQLiteDatabase db = dbHelper.getWritableDatabase();
    		int updatedRows = 0;
    		switch (uriMatcher.match(uri)) {
    		case BOOK_DIR:
    			updatedRows = db.update("Book", values, selection, selectionArgs);
    			break;
    		case BOOK_ITEM:
    			String bookId = uri.getPathSegments().get(1);
    			updatedRows = db.update("Book", values, "id = ?", new String[]
    			{ bookId });
    			break;
    		case CATEGORY_DIR:
    			updatedRows = db.update("Category", values, selection,
    			selectionArgs);
    			break;
    		case CATEGORY_ITEM:
    			String categoryId = uri.getPathSegments().get(1);
    			updatedRows = db.update("Category", values, "id = ?", new String[]
    					{ categoryId });
    			break;
    		default:
    			break;	
    		}
    		return updatedRows;
    	}
    
    }

        

        首先在类的一开始,同样是定义了四个常量,分别用于表示访问Book表中的所有数据、访问 Book表中的单条数据、访问 Category表中的所有数据和访问Category表中的单条数据。然后在静态代码块里对 UriMatcher进行了初始化操作,将期望匹

    配的几种 URI格式添加了进去。接下来就是每个抽象方法的具体实现了,先来看下 onCreate()方法,这个方法的代码很短,就是创建了一个 MyDatabaseHelper的实例,然后返回 true表示内容提供器初始化成功,这时数据库就已经完成了创建或升级操作。

    接着看一下 query()方法,在这个方法中先获取到了 SQLiteDatabase的实例,然后根据传入的 Uri参数判断出用户想要访问哪张表,再调用 SQLiteDatabase的 query()进行查询,并将 Cursor对象返回就好了。注意当访问单条数据的时候有一个细节,这里调用了 Uri对象的getPathSegments()方法,它会将内容 URI权限之后的部分以“/”符号进行分割,并把分割后的结果放入到一个字符串列表中,那这个列表的第 0个位置存放的就是路径,第 1个位置存放的就是 id了。得到了 id之后,再通过 selection和 selectionArgs参数进行约束,就实现了查询单条数据的功能。

        再往后就是 insert()方法,同样它也是先获取到了 SQLiteDatabase的实例,然后根据传入的 Uri参数判断出用户想要往哪张表里添加数据,再调用 SQLiteDatabase的 insert()方法进行添加就可以了。注意 insert()方法要求返回一个能够表示这条新增数据的 URI,所以我们还需要调用 Uri.parse()方法来将一个内容 URI解析成 Uri对象,当然这个内容 URI是以新增数据的 id结尾的。

        接下来就是 update()方法了,相信这个方法中的代码已经完全难不倒你了。也是先获取SQLiteDatabase的实例,然后根据传入的 Uri参数判断出用户想要更新哪张表里的数据,再调用 SQLiteDatabase的 update()方法进行更新就好了,受影响的行数将作为返回值返回。。这里仍然是先获取到 SQLiteDatabase的实例,然后根据传入的 Uri参数判断出用户想要删除哪张表里的数据,再调用 SQLiteDatabase的 delete()方法进行删除就好了,被删除的行数将作为返回值返回。

            <provider
                android:name="ga.orlion.databasedemo.DatabaseProvider"
                android:authorities="ga.orlion.databasedemo.provider"
                android:exported="true" >
                
            </provider>

        // 《第一行代码》这里没有加android:exported="true",导致出现了权限问题。

        

        可以看到, 这里我们使用了<provider>标签来对 DatabaseProvider这个内容提供器进行注册,在 android:name属性中指定了该类的全名,又在 android:authorities属性中指定了该内容提供器的权限。

        

        下一步需要将 DatabaseDemo程序从模拟器中删除掉,以防止上一章中产生的遗留数据对我们造成干扰。然后运行一下项目,将 DatabaseDemo程序重新安装在模拟器上了。接着关闭掉DatabaseDemo这个项目,并创建一个新项目 ProviderDemo,我们就将通过这个程序去访问DatabaseDemo中的数据。首先添加两个按钮一个用来添加数据一个用来查看数据,然后在MainActivity.java中绑定点击事件:

    package ga.orlion.providerdemo;
    
    import android.app.Activity;
    import android.content.ContentValues;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
    	private String newId;
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		Button addData = (Button) findViewById(R.id.add_data);
    		addData.setOnClickListener(new View.OnClickListener() {
    			
    			@Override
    			public void onClick(View v) {
    				Uri uri = Uri.parse("content://ga.orlion.databasedemo.provider/book");
    				ContentValues values = new ContentValues();
    				values.put("name", "content provider book");
    				values.put("author", "orlion");
    				values.put("pages", 200);
    				values.put("price", 199);
    				Uri newUri = getContentResolver().insert(uri, values);
    				newId = newUri.getPathSegments().get(1);
    			}
    		});
    		Button queryData = (Button) findViewById(R.id.query_data);
    		queryData.setOnClickListener(new View.OnClickListener() {
    			@Override
    			public void onClick(View v) {
    				// 查询数据
    				Uri uri = Uri.parse("content://ga.orlion.databasedemo.provider/book");
    				Cursor cursor = getContentResolver().query(uri, null, null,null, null);
    				if (cursor != null) {
    					while (cursor.moveToNext()) {
    						String name = cursor.getString(cursor.getColumnIndex("name"));
    						String author = cursor.getString(cursor.getColumnIndex("author"));
    						int pages = cursor.getInt(cursor.getColumnIndex("pages"));
    						double price = cursor.getDouble(cursor.getColumnIndex("price"));
    						Log.d("MainActivity", "book name is " + name);
    						Log.d("MainActivity", "book author is " + author);
    						Log.d("MainActivity", "book pages is " + pages);
    						Log.d("MainActivity", "book price is " + price);
    					}
    					cursor.close();
    				}
    			}
    		});
    	}
    }
  • 相关阅读:
    前端模块的前生今世
    variable fonts
    node
    webpack tree shaking
    es6 proxy浅析
    如何实现优美的骨架屏
    阿里巴巴Java开发手册建议创建HashMap时设置初始化容量,但是多少合适呢?
    新来个技术总监,禁止我们使用Lombok!
    2020年Java程序员应该学习的10大技术
    为啥HashMap的默认容量是16?
  • 原文地址:https://www.cnblogs.com/orlion/p/5350696.html
Copyright © 2020-2023  润新知