此博客为学习Android开发的笔记型博客,若有不妥或补充之处希望各位大神给予指正
Android权限
Android权限机制
Android权限分为普通权限和危险权限
对于普通权限,一般系统会自动帮我们授权,但对于危险权限需要用户手动授权。
下面是Android中所有的危险权限:其他表中没有列出的权限就全都是普通权限。
Android中系统完整的权限列表:http://developer.android.com/reference/android/Manifest.permission.html
在程序运行时申请权限
在这里我们模拟点击按钮后,呼叫10086。(由于我们使用的是虚拟机所以不会真的呼出去的,不会给他人造成不便,这点请放心)
1.在配置文件中声明权限:
<uses-permission android:name="android.permission.CALL_PHONE"/>
2.给button添加事件:
首先我们检测权限是否已被授权:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ContextCompat.checkSelfPermission(FirstActivity.this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(FirstActivity.this, new String[]{Manifest.permission.CALL_PHONE}, 1);
} else {
call();
}
}
});
使用ContextCompat.checkSelfPermission()方法,传入两个参数:Context 和所需要的权限。
Manifest.permission.CALL_PHONE为拨号权限的常量。
同理,PackageManager.PERMISSION_GRANTED也是常量,是已授权的常量。
这里当没有授权时,调用ActivityCompat.requestPermissions()方法申请权限,传入三个参数:Context,申请权限列表(String[ ]),请求码(唯一即可)。
3.授权和回调onRequestPermissionsResult 方法
然后系统会弹出一个申请权限的对话框,无论是否授权,都会回调onRequestPermissionsResult 方法,里面有三个参数:请求码,权限列表(String[ ]),权限的处理结果(int[ ])
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
//请求码 权限列表 权限的处理结果
switch (requestCode){
case 1:
if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
call();
}else{
Toast.makeText(FirstActivity.this,"You denied the permission",Toast.LENGTH_SHORT).show();
}
break;
default:
}
}
4.执行呼号操作
void call() {
try {
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:10086"));
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
return;
}
startActivity(intent);
}catch (Exception e){
e.printStackTrace();
}
}
访问其他程序中的数据
内容提供器:主要用于在不同程序之间实现数据共享功能。它提供了一套机制,允许一个程序访问另一个程序的数据。内容提供器可以选择只对哪一部分的数据进行共享,保证了数据的安全性。
要想访问内容提供器中的数据,就要借助ContentResolver类,可以通过context类中的getContentResolver()方法获得该类实例。
ContentResolver提供了一系列方法对数据进行操作:
insert(): 添加
update():更新
delete():删除
query():查找
没错,类似于SQLite的操作。只不过这里传的不是表名,而是uri。
uri:authority+path
authority:用于区分不同的应用程序。一般为了避免冲突采用程序包名来命名。
path:用于区分同一应用程序中的不同表
首先我们学习使用现有的内容提供器。
1.将uri字符串解析为uri对象:
Uri uri=Uri.parse("contect://com.example.app.provider/table1");
2.查询
Cursor cursor=getContentResolver().query(
uri,
projection,
selection,
selectionArgs,
sortOrder()
);
3.取出数据:
if(cursor != null){
while(cursor.moveToNext()){
String data=cursor.getString(cursor.getColumnIndex("column1"));
}
cursor.close();
}
4.添加:
ContentValues values=new ContentValues();
values.put("column1","tom");
getContentResolver().insert(uri,values);
5.修改:
//将 符合条件的 column1一列的值清空
ContentValues values=new ContentValues();
values.put("column1","");
getContentResolver().update(uri,values,"column1 = ? and column2 = ?",new String[]{"tom","1"});
6.删除:
getContentResolver().delete(uri,"column2 = ?" new String[]{"1"});
创建内容提供器
新建一个类继承ContentProvider类,创建自己的内容提供器。
需要重写6个抽象方法:
onCreate():
初始化内容提供器时调用,通常在这里完成数据库的创建和升级。
query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder):
返回Cursor
insert(Uri uri, ContentValues values):
返回一个用于表示这条新记录的URI(Uri)
update(Uri uri, ContentValues values, String selection,String[] selectionArgs):
返回受影响的行数(int)
delete(Uri uri, String selection, String[] selectionArgs):
返回被删除的行数(int)
getType(Uri uri):
返回MIMI(String)
MIMI格式:
uri以路径结尾:
“vnd”+“android.cursor.dir/”+“vnd.< authority >.< path >”
uri 以id结尾:
“vnd"+“android.cursor.item/”+“vnd.< authority >.< path >”
实战:
1.使用UriMatcher类匹配Uri
public class MyContentProvider extends ContentProvider {
public static final int BOOK_DIR=0;
public static final int BOOK_ITEM=1;
public static final String AUTHORITY="com.example.databasetest.provider";
private static UriMatcher matcher;
private static MyDatabaseHelper databaseHelper;
static {
matcher=new UriMatcher(UriMatcher.NO_MATCH);
matcher.addURI(AUTHORITY,"book",BOOK_DIR);
matcher.addURI(AUTHORITY,"book/#",BOOK_ITEM);
}
2.重写insert方法:
public Uri insert(Uri uri, ContentValues values) {
// TODO: Implement this to handle requests to insert a new row.
// throw new UnsupportedOperationException("Not yet implemented");
Uri uriReturn=null;
SQLiteDatabase db = databaseHelper.getReadableDatabase();
switch (matcher.match(uri)){
case BOOK_DIR:
case BOOK_ITEM:
long newBookId= db.insert("Book",null,values);
uriReturn=Uri.parse("content://"+AUTHORITY+"/book/"+newBookId);
break;
default:
break;
}
return uriReturn;
}
3.重写delete方法:
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Implement this to handle requests to delete one or more rows.
// throw new UnsupportedOperationException("Not yet implemented");
int rows=0;
SQLiteDatabase db=databaseHelper.getReadableDatabase();
switch (matcher.match(uri)){
case BOOK_DIR:
rows=db.delete("Book",selection,selectionArgs);
break;
case BOOK_ITEM:
String bookId=uri.getPathSegments().get(1);
rows=db.delete("Book","id = ?",new String[]{bookId});
break;
default:
break;
}
return rows;
}
4.重写query方法:
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// TODO: Implement this to handle query requests from clients.
Cursor cursor=null;
SQLiteDatabase db = databaseHelper.getReadableDatabase();
switch (matcher.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;
default:
break;
}
return cursor;
}
5.重写update方法:
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO: Implement this to handle requests to update one or more rows.
// throw new UnsupportedOperationException("Not yet implemented");
int rows=0;
SQLiteDatabase db=databaseHelper.getReadableDatabase();
switch (matcher.match(uri)){
case BOOK_DIR:
rows=db.update("Book",values,selection,selectionArgs);
break;
case BOOK_ITEM:
String bookId= uri.getPathSegments().get(1);
rows=db.update("Book",values,"id = ?",new String[]{bookId});
break;
default:
break;
}
return rows;
}
6.重写getType方法:
public String getType(Uri uri) {
// TODO: Implement this to handle requests for the MIME type of the data
// at the given URI.
// throw new UnsupportedOperationException("Not yet implemented");
switch (matcher.match(uri)){
case BOOK_DIR:
return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book";
case BOOK_ITEM:
return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book";
default:
break;
}
return null;
}
7.在secondActivity的listView中展现出来,即调用query方法:
oncreate():
ListView listView=(ListView) findViewById(R.id.second_listview);
adapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,contactsList);
listView.setAdapter(adapter);
initialList();
initialList():
void initialList(){
Uri uri=Uri.parse("content://com.example.databasetest.provider/book");
ContentResolver contentResolver=getContentResolver();
Cursor cursor=null;
try {
cursor=contentResolver.query(uri,null,null,null,null);
if(cursor!=null){
while (cursor.moveToNext()){
String id =cursor.getString(cursor.getColumnIndex("id"));
String name=cursor.getString(cursor.getColumnIndex("name"));
contactsList.add(id+"\n"+name);
}
adapter.notifyDataSetChanged();
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(cursor!=null) {
cursor.close();
}
}
}
结果: