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,执行相关操作。
- Android 开发培训(04)--Android开发核心(三)
- Android开发培训(02)--Android开发核心
- Android 开发培训(03)--Android开发核心(二)
- Android开发培训(01)--开始
- Android开发培训(06)--分享文件 (二)
- android应用开发培训
- Android开发核心基础知识
- Android开发培训(05)--创建数据共享
- Android开发培训(07)--相机多媒体
- Android开发培训(08)--使用openGL ES作图
- Android开发培训(10)--app网络连接
- Android API 核心开发包
- Android开发系列(三)
- Android开发入门(三)
- Android开发小生(三)
- Android开发教程(三)
- Android蓝牙开发(三)
- Android开发之Android的核心服务
- java与C++的不同(笔记)
- 【HDU
- PHP支持ffmpeg,便用ffmpeg命令处理视频,开启exec权限
- CSS笔记(Bootstrap概览)
- Jzzhu and Sequences CodeForces
- Android 开发培训(04)--Android开发核心(三)
- 将 React Native 项目运行在 Web 浏览器上面
- S01E01 Python自动化测试环境搭建
- hdu 6168 Numbers【map】
- Mysql DB Browser的使用
- stm32不断的进入中断形成死循环
- 在Java中使用迭代器访问集合元素
- windows Nginx重启
- Spark RDD算子【三】combineByKey