Android 开发培训(04)--Android开发核心(三)

来源:互联网 发布:ug编程安全几何体 编辑:程序博客网 时间:2024/05/17 22:45

和其它的app交互

一个android app通常有几个Activity,一个Activity通常展示一个user接口,允许用户表达特定的操作,比如查看地图信息,或者拍照。为了使用户从一个Activity跳转到另外一个Activity,必须使用Intent告诉你的app想要做什么。当你使用startActivity的时候,系统就会利用上面的Intent信息确认你想要开启哪个app部分。使用Intent甚至可以运行你的app启动另外一个app的功能。

一个Intent可以准确地告诉系统它想去和哪个activity交互,比如启动另外一个app,从那个app中获取返回信息,你的app也可以响应其它的app的请求。


第七章 启动另外一个app

Android系统一个重要的功能就是可以根据用户想要的操作发送向另外一个app发送请求。

比如你有一个地址信息,你想在地图上查看这个地址信息,你不需要在你的应用上再建立一个地图。你可以使用Intent创建一个请求,在其它的app的map上查看这个信息。

就像我们在第一章创建第一个程序那样,你必须使用Intent才能够在不同的Activity之间切换。

你使用的是explicit intent完成的这组操作,你指定了一个你想开启的Activity。如果你想使用另外的app执行你的动作,比如查看地图,你可以发送一个implicit intent(隐式)。

这篇文章教你为一个特殊的动作发送隐式Intent,怎么使用它开启一个Activity.

1. 建立一个隐式Intent

隐式Intent没有申明需要开启的Activity,但是定义了需要执行的动作。这个动作表达了你想干什么,比如编辑,发送,或者获取其它的。Intent通常还包含有数据,比如想要查看地图的地址,比如发送email文件的地址。取决于你想创建的Intent,数据可能是Uri,可能是其它的类型,或者不需要数据的Intent.

如果你的数据是一个uri,你可以参考下面的例子创建一个Intent.

Uri number = Uri.parse("tel:5551234");Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
当你的应用程序调用startActivity()的时候,打电话的app就会通过这个number值实例化一个打电话操作。

其它的几种类型

// Map point based on addressUri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");// Or map point based on latitude/longitude// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom levelIntent mapIntent = new Intent(Intent.ACTION_VIEW, location);
Uri webpage = Uri.parse("http://www.android.com");Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
其它隐式intent需要提供不同的数据类型,你可以使用不同的额外信息。

默认的,系统会根据传过去的数据决定数据的类型。但是如果你没有包括Uri在intent中,你需要自己指定数据的类型,使用setType函数,这回让哪个activity接收intent.

这个示例会放更多的数据,是一个邮件

Intent emailIntent = new Intent(Intent.ACTION_SEND);// The intent does not have a URI, so declare the "text/plain" MIME typeemailIntent.setType(HTTP.PLAIN_TEXT_TYPE);emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipientsemailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));// You can also attach multiple items by passing an ArrayList of Uris
改变calendar的事件

Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());calendarIntent.putExtra(Events.TITLE, "Ninja class");calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
你应该尽量具体你的intent是干什么的,比如如果你想显示一张图片,需要使用ACTION_VIEW,你应该指定mine类型为image/*,这可以放置其它的程序也被这个intent触发。

2. 确定这里有接收intent的app

虽然android系统确保了没有intent都会有对应的内置app完成相应的工作,比如(电话,邮箱,日历),你性该包含一个确认信息在调用intent之前。

如果没有app为你这个intent服务,你的app就会发生crash.

调用queryIntentActivities()函数获取可以服务这个intent的activity或者程序。如果返回的list不为空,你可以安全地使用这个intent.

比如

PackageManager packageManager = getPackageManager();List activities = packageManager.queryIntentActivities(intent,        PackageManager.MATCH_DEFAULT_ONLY);boolean isIntentSafe = activities.size() > 0
如果变量isIntentSafe 是true,那么至少有一个app可以响应这个intent.

如果你确保有其它的app可以服务这个intent,你可以引导用户下载相应的app.

3. 使用intent值开启一个activity

一旦你建立了一个intent,也设置了额外的信息,你就可以调用startActivity()函数把intent发送给系统。如果这个系统识别不止一个app可以处理这个intent,那么它会弹出一个提示框供用户选择,如果这里只有一个app,那么系统就会直接打开这个app.

startActivity(intent);
这里有个完整的示例是如何调用地图程序查看位置,确认有一个app可以响应这个intent,然后开启它

// Build the intentUri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);// Verify it resolvesPackageManager packageManager = getPackageManager();List<ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);boolean isIntentSafe = activities.size() > 0;// Start an activity if it's safeif (isIntentSafe) {    startActivity(mapIntent);}
4. 打开app选择器

当用户通过startActivity传递intent,启用其它的app的时候,通常这里不止有一个app可以响应这个intent,用户可以通过底下的提示框选择一个默认的app.当用户每次想用一个默认的app响应响应的功能的时候就能这样做。比如每次想要浏览网页的时候就能打开默认的浏览器。

但是如果用户每次都想使用不同的app处理这个intent,那么就需要明确地显示app选择器给用于,这个选择框每次都会弹出供用户选择。

为了表示怎么选择,下面给出一个示例

Intent intent = new Intent(Intent.ACTION_SEND);...// Always use string resources for UI text.// This says something like "Share this photo with"String title = getResources().getString(R.string.chooser_title);// Create intent to show chooserIntent chooser = Intent.createChooser(intent, title);// Verify the intent will resolve to at least one activityif (intent.resolveActivity(getPackageManager()) != null) {    startActivity(chooser);}

第八章    从其它的Activity中获取结果

不仅仅可以开启其它的app,而且可以通过调用startActivityForResult函数获取返回结果。

比如,你可以打开一个相机app然后从相机中获取想要的数据。或者你打开一个联系人app,然后想获取联系人的详细信息。

当然处理intent的activity必须能够返回消息才行,当这个activity完成之后,它会发送另外一个Intent对象,你的activity就可以通过onActivityResult获取到。

1. 开始一个Activity

和之前的Intent值没有什么任何的不同,除了你需要传递一个额外的integer类型的参数给startActivityForResult函数。

这个参数是一个request code,作用是区别你的请求。

下面是一个示例,开启一个activity去选择用户需要的联系方式

static final int PICK_CONTACT_REQUEST = 1;  // The request code...private void pickContact() {    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts"));    pickContactIntent.setType(Phone.CONTENT_TYPE); // Show user only contacts w/ phone numbers    startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);}
2. 接收结果

当用户处理完这个intent之后会返回到原来的app中,系统会调用你的onActivityResult方法,这个方法包括三个参数。

你通过startActivityForResult()传递的request code.

第二个程序也还会返回这个intent是执行成功还是失败,RESULT_OK或者RESULT_CANCELED.

第三个是Intent带回来的数据。

比如这是你如何handle一个获取联系人的示例

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {    // Check which request we're responding to    if (requestCode == PICK_CONTACT_REQUEST) {        // Make sure the request was successful        if (resultCode == RESULT_OK) {            // The user picked a contact.            // The Intent's data Uri identifies which contact was selected.            // Do something with the contact here (bigger example below)        }    }}
这个例子中,通过联系人返回的intent可以向发送intent的app提供相关的uri信息。

为了成功地处理相关的信息,你必须知道Intent的格式,如果这个会返回的activity是自己程序的activity,那就很容易知道。一些andoid平台的app也比较容易确认。比如联系人app经常会返回一个文本的uri信息确定选择的信息,一个camera app会返回一个bitmap。

额外的:从返回的数据中获取结果

上面的例子只是展示了如何从联系人app中获取结果,但是没有真正地去读取数据,因为这涉及到后面的content providers的内容。但是,如果你比较好奇,这里写了一些如何从选取的联系人中获取更多的结果。

@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {    // Check which request it is that we're responding to    if (requestCode == PICK_CONTACT_REQUEST) {        // Make sure the request was successful        if (resultCode == RESULT_OK) {            // Get the URI that points to the selected contact            Uri contactUri = data.getData();            // We only need the NUMBER column, because there will be only one row in the result            String[] projection = {Phone.NUMBER};            // Perform the query on the contact to get the NUMBER column            // We don't need a selection or sort order (there's only one result for the given URI)            // CAUTION: The query() method should be called from a separate thread to avoid blocking            // your app's UI thread. (For simplicity of the sample, this code doesn't do that.)            // Consider using CursorLoader to perform the query.            Cursor cursor = getContentResolver()                    .query(contactUri, projection, null, null, null);            cursor.moveToFirst();            // Retrieve the phone number from the NUMBER column            int column = cursor.getColumnIndex(Phone.NUMBER);            String number = cursor.getString(column);            // Do something with the phone number...        }    }}


第九章    允许其它的app启动你的Activity

之前的两张关注于你给别的app发送intent,但是也有可能你的app对别人有用,所以你的app需要响应别人的请求。比如你建了一个社交的app可以发送消息以及和好友分享照片,你的actvity最好能够支持ACTION_SEND intent这样其它的app就能启动你的app进行相关操作。

为了允许别人启动你的activity,你需要在你的manifest文件元素<activity>中增加<intent-filter>

当你的app安装到系统中,系统就会识别你的intent过滤器,把它添加到一个泪奔的分类好的intent中。当一个app调用startActivity()或者startActivityForResult()的时候,如果是隐式消息,系统就会去寻找那个activity可以响应这些信息。

1. 增加一个intent过滤器

为了准确地表达你的activity可以处理什么样的intent,你的过滤器必须尽量地具体,它可以接收什么累心的动作以及什么数据。

系统会将intent发送给一个activity,如果这个activity的过滤器满足下面的条件:

动作:

一个表示执行什么动作的字符串,通常平台定义的值有ACTION_SEND和ACTION_VIEW.

你的程序中可以使用<action>原来来指定intent 过滤器,这个元素必须是整个字符串的全称。

数据:

intent中的数据

通过intent中的<data>元素指定,使用一个或者多个属性,你可以制定这个数据mime类型,或者是一个uri前缀,或者是其它的组合,总之能够识别是能够接受的类型。

注释:如果你不需要申明元素的具体类型,你需要申明android:mimeType属性,去描述你的Activity会进行什么操作,比如text/plain或者image/jpeg.

分类:

为你的activity处理intent提供了额外的特性,通常关系到用户的手势或者是从哪里开始的。

这里有几个系统支持的不同分类,但是大部分的系统都是默认CATEGORY_DEFAULT类型。

通过<category>元素指定。

你可以在你的xml文件中定义<intent-filter>

比如下面这个会处理ACTION_SEND类型的数据类型可以是text或者是image

<activity android:name="ShareActivity">    <intent-filter>        <action android:name="android.intent.action.SEND"/>        <category android:name="android.intent.category.DEFAULT"/>        <data android:mimeType="text/plain"/>        <data android:mimeType="image/*"/>    </intent-filter></activity>
每个intent命令只有一个action和一个data type,但是可以在<intent-filter>中定义更多的<cation><category>和<data>实例。

如果过滤器中的两个action或者是data冲突,你需要创建一个新的intent过滤器来接收传递过来的数据。

比如你的activity可以同事处理ACION_SEND和ACTION_SENDTO数据类型,这时你需要定义两个intent filter,因为ACTION_SENDTO必须使用Uri数据来指定地址。

<activity android:name="ShareActivity">    <!-- filter for sending text; accepts SENDTO action with sms URI schemes -->    <intent-filter>        <action android:name="android.intent.action.SENDTO"/>        <category android:name="android.intent.category.DEFAULT"/>        <data android:scheme="sms" />        <data android:scheme="smsto" />    </intent-filter>    <!-- filter for sending text or images; accepts SEND action and text or image data -->    <intent-filter>        <action android:name="android.intent.action.SEND"/>        <category android:name="android.intent.category.DEFAULT"/>        <data android:mimeType="image/*"/>        <data android:mimeType="text/plain"/>    </intent-filter></activity>
3. 在你的activity中处理消息

你可以读取intent中的内容,决定你的activity执行什么动作。

在你的activity中你可以调用getIntent函数获取intent变量开启activity,然后你可以做任何想做的事情,但是你应该在onCreate() 或者onStart()中做些其它的回调。

比如

@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    // Get the intent that started this activity    Intent intent = getIntent();    Uri data = intent.getData();    // Figure out what to do based on the intent type    if (intent.getType().indexOf("image/") != -1) {        // Handle intents with image data ...    } else if (intent.getType().equals("text/plain")) {        // Handle intents with text ...    }}

4. 返回结果

如果你想向调用你的activity中返回结果,你可以调用setResult函数指定返回结果的数值以及返回的intent.当你的程序处理完成之后,你应该返回到原来的activity当中,可以通过调用finish()函数关闭以及销毁你的activity。

比如

// Create intent to deliver some kind of result dataIntent result = new Intent("com.example.RESULT_ACTION", Uri.parse("content://result_uri"));setResult(Activity.RESULT_OK, result);finish();
你必须对返回结果返回相应的返回值,可以是RESULT_OK或者是RESULT_CANCELED.如果必须的话你还可以使用intent提供额外的数据。

注意这个RESULT_CANCELED是系统默认的结果,如果用于在完成动作之前按了返回健,原来的activity就会收到cancel的消息。

如果你需要返回一个整形值来表示几个结果信息,你可以设置大于0的返回值,如果你不包括返回intent而使用返回值来传递整形值,你只需要调用setResult()而已,下面是实例

setResult(RESULT_COLOR_RED);finish();
这个例子中,只有一个返回结果,因此这个返回结果值通常定义为大于0的整形值。当返回结果到你的app的时候,这个很有作用,因为app可以通过这个参考返回值知道返回的结果是什么。

注意通过调用startActivity()或者startActivityForResult(),去检查返回结果不是必须的。如果你的程序希望回去返回信息的时候,只需要调用setResult函数就可以,如果activity调用了startActivityForResult函数,系统会补充上setResult,如果你不指定的话。



第十章 系统权限问题

为了保护系统和用户的隐私,android系统运行都在一个有限的权限沙箱中运行程序。如果程序需要使用沙箱以外的资源和信息,这个app就不能不去申请权限。取决于你需要申请什么样的权限,系统可能会自动地给你分配,有些情况系统夜壶询问用户是否给予权限给你。

1. 申请权限

每个app都运行在沙箱中,如果一个app需要使用沙箱以外的资源。你可以在你的app manifest中定义相关的权限。

取决于你的权限的敏感程度,系统可能自动会为你分配权限,也有可能去向用户申请权限。

取决于系统,需要用户手动允许的权限可能会出现在app安装的时候,也可能会出现在程序运行的时候。

2. 你的app需要什么样的权限

你在开发app的时候,需要知道你的app会使用什么样的权限。通常来说一个当一个app在它使用的资源或者信息不能自己创建的时候,或者是需要执行特定的动作的时候就需要申请权限。比如,一个app如果需要接触网络,或者使用相机设备,或者其它的权限,如果需要了解所有的权限,可以查看Nromal and Dangerour Permissions.

只有当你的app直接操作action的时候才需要权限,当你的app请求其它的app去完成相应的功能的时候不需要申请。比如,你的app需要读取用户的通讯录,这个app需要一个READ_CONTACTS权限。但是你的app如果去通过intent请求一个contact app去读取的话,你的app就不需要去申请权限,但是contact app需要这个权限。

3. 在Manifest中增加权限

通过在<manifest>中的子元素中增加<uses-permission>来申明你的权限。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"        package="com.example.snazzyapp">    <uses-permission android:name="android.permission.SEND_SMS"/>        <application ...>        ...    </application></manifest>
系统会自动为你给你执行权限如果你的权限不涉及到敏感信息,或者不会去读取用户的信息,否则,系统会向去向用户咨询相关的信息。

更多的信息请查看,Normal and Dangerous Permissions章节。


4. 运行时申请权限

从android 6.0开始,用户允许权限已经移植到运行的时候,而不是在安装的时候。这种做法简化了app的安装流程,因此用户不在需要确定是否在安装或者更新的时候给app分配权限。它同事给你用户对于app的更多控制。比如,用户允许app去获取相机而不允许用户获取位置信息。用户可以在设置中在任何时候重置权限。

系统权限分成两种,一种是正常,一种危险。

正常的权限不会触及到用户的隐私,这种权限系统会自动给app。

危险权限是app会去获取用户的数据,这个时候由用户决定是否分配权限。

在android所有的版本中,当你需要这些权限的时候,你都要在app manifest中申明正常权限或者是危险权限。但是申明的效果取决于你系统的版本或者是sdk的版本。

如果你的设备运行android 5.1之前的sdk,如果你在你的manifest中列出有危险权限,就会在程序安装的时候,去向用户获取这些权限。如果没有获取到相应的权限,系统都不会去装这个app。

如果设备运行6.0或者更高的sdk版本,app必须在manifest中申明权限,同时在app运行的时候需要获取用户的同意。用户可以否定这些权限,这个app还是可以运行的只是不能进行相应的操作,如果用户否决申请的权限的话。

这个教程使用support library去检查请求获取权限,使用support library会让操作过程变得更简单,因为app不用去检查android 的版本,在调用响应的方法之前。

5. 检查权限

如果你的app需要危险权限,当app每次需要这个权限的时候你都要去确认是否允许执行。用户可以重置设置信息,所以说昨天相机已经获取了权限,可能今天还要继续获取相关的权限。

检查你是否有这个权限,需要调用ContextCompat.checkSelfPermission()方法,比如这个小片段就向我们展示了activity如何写calendar的权限

// Assume thisActivity is the current activityint permissionCheck = ContextCompat.checkSelfPermission(thisActivity,        Manifest.permission.WRITE_CALENDAR);
如果app有这个权限,这个方法会返回一个PackageManager.PERMISSION_GRANTED变量,app然后进行相应的处理,如果app没有这个权限,那么这个方法会返回PERMISSION_DENIED,然后app会向用户申请这个权限。

6.请求权限

如果你的app manifest列表中需要一个危险权限,它必须向用户申请,Android系统提供了几个你可以使用的申请权限的方法。调用这些方法会弹出一个标准的android提示框:

解释为什么app需要权限

在一些环境中,你需要帮助用户理解为什么你的app需要这个权限,比如如果用户启动一个相机拍照的程序,用户可能对于app请求使用相机不会感到诧异,但是用户不理解为什么需要获取用户的联系人信息和位置信息。在你申请权限之前,你应该给用户提供一个解释,记住不要说得太多,如果你提供太多的解释,用户可能会觉得这个app不好用而把它删除掉。

一个提供解释的途径是当用户拒绝了你的申请权限之后,这个时候你需要提供解释。如果用户继续使用那个需要权限的功能,但是用户又不给那个功能权限,这个时候就需要程序向用户解释为什么这个功能需要这个权限。

为了帮助开发者需要给用户提供解释,android提供了一个shouldShowRequestPermissionRationale()方法,如果app申请了权限,而用户拒绝了它就会返回true.

注意如果用户拒绝了申请这个权限,而且点了Don't ask again提示框,那么这个方法也会返回false.这个方法也会在设备策略不允许有这个权限的时候返回false.

申请你需要的权限

如果i的app没有你需要的权限,你必须调用requestPermissions()方案去申请合适的权限。你的app传递你想要的权限,一般是用一个integer值表示。这个方法是异步的,它会马上返回,当用户响应了提示框之后,系统会调用app的回调函数,传递相同的申请值。

这个下面的代码片段检查app是否有读取用户联系人的权限,如果没有的话就会去申请这个权限

// Here, thisActivity is the current activityif (ContextCompat.checkSelfPermission(thisActivity,                Manifest.permission.READ_CONTACTS)        != PackageManager.PERMISSION_GRANTED) {    // Should we show an explanation?    if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,            Manifest.permission.READ_CONTACTS)) {        // Show an explanation to the user *asynchronously* -- don't block        // this thread waiting for the user's response! After the user        // sees the explanation, try again to request the permission.    } else {        // No explanation needed, we can request the permission.        ActivityCompat.requestPermissions(thisActivity,                new String[]{Manifest.permission.READ_CONTACTS},                MY_PERMISSIONS_REQUEST_READ_CONTACTS);        // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an        // app-defined int constant. The callback method gets the        // result of the request.    }}
当你调用requestPermission()的时候,系统会显示一个标准的对话框,你的程序不能改变这个对话框,如果你需要向用户提供额外的信息,你应该在requestPermission()函数之前完成。

7. 处理回复消息

当你的app请求权限之后,系统就会给用户呈现一个对话框。当用户响应完成之后,系统会调用onRequestPermissionResult()方法。你的app应该重写这个方法,确认是否获得权限,这个回调会传递你传递给requestPermission相同的请求code.比如,你的app请求READ_CONTACTS获取权限,会有下面的回调方法。

@Overridepublic void onRequestPermissionsResult(int requestCode,        String permissions[], int[] grantResults) {    switch (requestCode) {        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {            // If request is cancelled, the result arrays are empty.            if (grantResults.length > 0                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {                // permission was granted, yay! Do the                // contacts-related task you need to do.            } else {                // permission denied, boo! Disable the                // functionality that depends on this permission.            }            return;        }        // other 'case' lines to check for other        // permissions this app might request    }}
这个对话框不会提供额外的信息,比如你需要READ_CONTACTS权限,这个系统的提示框仅会告诉你的app需要这个权限。

8. 权限使用需要注意的事项

app通常都忽略权限的请求,如果用户发现app难用,或者用户担心app会窃取用户的信息,用户就不会使用这个app,甚至完全卸载。

下面是一个提升用户体验的最佳建议:

一, 考虑使用Intent

如果你有一个ACTION_IMAGE_CAPTURE请求,你可以发送一个intent让用户转移到camera app上去完成这个任务,然后在onActivityResult中获取返回结果。

二, 仅仅去请求你需要的权限

三, 不要忽略用户

四, 解释你为什么需要权限

五, 测试两个权限模型

一个用户权限申请实例

mainfest文件

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"          package="com.example.www.permissiontest">        <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>    <application        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme">        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN"/>                <category android:name="android.intent.category.LAUNCHER"/>            </intent-filter>        </activity>    </application></manifest>

activity文件

package com.example.www.permissiontest;import android.Manifest;import android.app.Activity;import android.content.pm.PackageManager;import android.support.annotation.NonNull;import android.support.v4.app.ActivityCompat;import android.support.v4.content.ContextCompat;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.util.Log;public class MainActivity extends AppCompatActivity {    private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)                != PackageManager.PERMISSION_GRANTED) {            if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) {                Log.d("wangrl0", "wangrl0");            } else {                ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS},                        MY_PERMISSIONS_REQUEST_READ_CONTACTS);                Log.d("wangrl3", "wangrl3");            }         }    }    @Override    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {        switch (requestCode) {            case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {                if (grantResults.length > 0 &&                        grantResults[0] == PackageManager.PERMISSION_GRANTED) {                    Log.d("wangrl1", "wangrl1");                } else {                    Log.d("wangrl2", "wangrl2");                }            }            return ;        }    }}
第一次询问权限的时候会打印3,然后拒绝的话会打印2,如果再次开启程序会打印0.

第一次询问的时候会打印3,然后同意的话会打印1,执行相关操作。








原创粉丝点击