====================================
====== 第八章:丰富你的程序 — 运用手机多媒体 ======
====================================
从Android4.2开始,开发者选型默认是隐藏的,你需要先进入“关于手机”界面,然后对着最下面的版本号那一栏连续点击,才会让开发者选项显示出来。
8.1 将程序运行到真机上
1、将手机连接到电脑
2、进入手机的设置 —》开发者选项,勾选USB调试选项(Android4.2开始,开发者选项默认是隐藏的,需要先进入到“关于手机”界面,然后对着最下面的版本号一栏连续点击,才会让开发者选项显示出来)
3、观察Android Monitor,发现当前设备是有两个设备在线的。
8.2 使用通知:
通知Notification是Android系统中比较有特色的功能。
8.2.1 通知的基本功能:
通知的使用方法比较灵活:既可以在活动里面创建、也可以在广播接收器里创建,当然也可以在我们这一章的服务里创建。(在活动里创建通知的场景比较少,因为一般在程序进入后台的时候我们才需要使用通知)。
现在我们来学习一下创建通知的步骤:
1、需要一个NotificationManager对象:通过调用Context的getSystemService()方法获取到。Context.NOTIFICATION_SERVICE作为参数。
如:
NotificationManager manager = (NotificationManger)getSystemService(Context.NOTIFICATION_SERVICE);
2、使用一个Builder构造器来创建Notification对象。API不稳定性在通知上突显的特别明显。解决办法就是使用support库中提供的兼容API,support-v4库中提供了一个NotificationCompat类,使用这个类的构造器来创建Notificaition对象,就可以保证所有系统都能用。
如:
Notificaition notification = new NotificationCompat.Builder(context).build();
上面的代码只是创建了一个空的Notification对象。
3、一些基本的设置:
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle(“This is content title”)
.setContextText(“This is content text”)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawale.small_icon);
.setLargeIcon(BitmapFactory.decodeResource(getResource().R.drawable.large_icon))
.build();
// 设置标题、设置正文、指定通知被创建的时间、设置通知小图标、设置通知大图标
4、只需要调用NotificationManger的notify()方法,就可以让通知显示出来了。notify方法接收两个参数,第一个是id,要保证每个通知所指定的id都是不同的,第二个参数是Notification对象。
如:
manager.notify(1, notification);
新建一个NotificationTest项目:
1、修改activity_main.xml文件:
android:orientation=“vertical” android:layout_width=“match_parent” android:layout_height=“match_parent” >
2、修改MainActivity代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstnceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button sendNotice = (Button) findViewById(R.id.send_notice);
sendNotice.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.send_notice:
NotificationManager manager = (NotificationManager) getSystemServdise(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(this, “1”)
.setContentTitle(“This is content title”)
.setContentText(“This is content text”)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_lancher)
.setLargeIcon(BitmapFactory.decodeResource(getResources().R.mipmap.i c_launcher))
.build();
manager.notify(1, notification);
break;
default:
break;
}
}
}
但是这条通知是没法点击的。
需要新概念PendingIntent:Intent用于立即执行某个动作,PendingIntent更加倾向于在某个合适的时机去执行某个动作。可以理解为延迟执行的Intent;
可以通过getActivity() getBroadcast() getService()方法之一来获取PendingIntent。这三个方法都接受四个参数,1、Context,2、传0即可。3、是一个Intent对象。4、有FLAG_ONE_SHOT、FLAG_NO_CREATE、FLAG_CHANEL_CURRNT、FLAG_UPDATE_CURRENT四种值可选。
NotificationCompat.Builder可以再链接setContentIntent()方法。接收的参数正式PendingIntent对象。
优化一下刚才的NotificationTest项目:
给刚才的通知加上点击功能。
5、右键com.example.notification包,New —> Activity —> Empty Activity 新建NotificationActivity,名字叫做notification_layout
android:layout_width=“match_parent” android:layout_height=“match_parent” > android:layout_width=“wrap_content” android:layout_height=“wrap_content” android:layout_centerInParent=“true” android:textSize=“24sp” android:text=“This is notification layout” />
6、再次修改MainActivity的代码
public class MainActivity extends AppCompatActivity implements View.OnClickLinster {
…
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.send_notice:
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.build(this, “1”)
.setContentTitle(“This is content title”)
.setContentText(“This is content text”)
.setSmallIcon(…)
.setLargeIcon(…)
.setContentIntent(pi)
.build();
manager.notify(1, notification);
break;
default:
break;
}
}
}
6、在通知的时候再链接一个setAutoCancel()方法,或者再显式的调用NotificationManager的cancel()方法,即可将它取消。
第一种方法:链接setAutoCancel():
Notification notification = new NotificationCompat.Builder(this).
.setContentTitle(“This is content title”)
.setAutoCancel(true)
.build();
可以看到,setAutoCancel()方法传入true,就表示当点击了这个通知的时候,通知会自动取消掉。
第二种方法写法:
public class NotificationActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_layout);
NotificationManger manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1);
}
}
cancel中传入的1就是我们创建通知的时候指定的id。
8.2.2 通知的进阶技巧
实际上,NotificationCompat.Builder中提供了非常丰富的API来让我们创建出更加多样的通知效果。
1、先看看setSound()方法吧。它接收一个Uri参数,如:
Notification notification = new NotificationCompat.Builder(this)
…
.setSound(Uri.fromFile(new File(“/system/media/audio/ringtones/Luna.ogg”);
.build();
2、setVibrate()方法可以设置手机振动。它接收一个毫秒为单位的long类型的数组。
如new long[] {0, 1000, 1000, 1000}
// 数组0位表示手机静止时长
// 数组1位表示手机振动时长
// 数组2位表示手机静止时长
// 数组3位表示手机振动时长
控制手机振动,还需要声明权限,因此需要编辑AndroidManifest.xml文件
package=“com.example.notificationtest” android:versionCode=“1” android:versionName=“1.0” > … … 3、setLights()方法可以设置LED灯闪烁。接收三个参数, 参数1:LED灯颜色 参数2:LED灯亮起时长(毫秒) 参数3:LED等暗去的时长(毫秒) .setLights(Color.GREEN, 1000, 1000) 如果不想做这么多负责设置,直接只用通知的默认效果,让手机根据环境来决定播放的铃声、振动: .setDefaults(NotificationCompat.DEFAULT_ALL); .build(); 8.2.3 通知的高级功能 继续观察NotificationCompat.Builder这个类,会发现里面还有很多API是我们没有使用过的。 1、setStyle()方法:构建出富文本的通知内容。接收一个NotificationCompat.Style参数。如: Notification notification = new NotificationCompat.Builder(this) … .setStyle(new NotificationCompat.BigPictureStyle().bigPicture(BitmapFactory.decodeResource(getResource(),R.drawable.big_image))) ,build(); 2、setPriority()设置重要程度。5个可选值:PRIORITY_MIN、PRIORITY_LOW、PRIORITY_DEFAULT、PRIORITY_HIGH、PRIORITY_MAX setPrority(NotificationCompat.PRIORITY_MAX); 8.3 调用摄像头和相册。 新建一个CameraAlbumTest项目 1、Button+ImageView android:orientation=“vertical” android:layout_width=“match_parent” android:layout_height=“match_parent” > 2、调用摄像头逻辑: public class MainActivity extends AppCompatActivity { public static final int TAKE_PHOTO = 1; private ImageView picture; private Uri imageUri; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button takePhoto = (Button) findViewById(R.id.take_photo); picture = (ImageView) findViewById(R.id.picture); takePhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建File对象,用于存储拍照后的图片 File outputImage = new File(getExternalCacheDir(), “output_image.jpg”); try { if (outputImage.exists() { outputImage.delete(); } } catch (IOException e) { e.printStackTrace(); } if (Build.VERSION.SDK_INT >= 24) { imageUri = FIleProvider.getUriForFile(MainActivity.this, “com.example.cameraalbumtest.fileprovider” outputImage); } else { imageUri = Uri.fromFile(outputImage); } // 启动相机程序 Intent intent = new Intent(“android.media.action.IMAGE_CAPTURE”); Intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent, TAKE_PHOTO); } }); } @Override protected void onActivityResult(int requestCode, inte resultCode, Intent data) { switch (requestCode) { case TAKE_PHOTO: if (resultCode == RESULT_OK) { try { // 将拍摄的照片显示出来 Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageUri); picture.setImageBitmap(bitmap); } catch (FileNotFoundException e) { e.printStackTrace(); } } break; default: break; } } } 备注: 1、SD卡中专门用于存放当前应用缓存数据的位置,调用getExtranalCacheDir()方法可以得到这个目录。 2、如果Android7.0以下,调用Uri的fromFile()方法将File对象转换为Uri对象。如果是Android7.0以上,调用FileProvider的getUriForFile()方法将File对象转换成一个封装过的Uri对象。三个参数,1Context 2任意字符串 3File对象。 3、构建一个Intent,将action指定为android.media.action.IMAGE_CAPTURE,然后调用startActivityForResult()来启动活动。 4、拍照完成后会返回onActivityResult()方法中 3、需要再AndroidManifest.xml中对内容提供器进行注册: package=“com.example.cameraalbumtest” > android:allowBackup=“true” android:icon=“@mipmap/ic_launcher” android:label=“@string/app_name” android:supportsRtl=“true” android:theme=“@style/AppTheme” > … android:name=“android.support.v4.content.FileProvider” android:authorities=“com.example.cameraalbumtest.fileprovider” android:exported=“false” android:grantUriPermissions=“true” > android:name=“android.support.FILE_PROVIDER_PATHS” android:resource=“@xml/file_paths” /> 备注: 1、android:name的值是固定的。 2、android:authorities的值必须和刚才FileProvider.getUriForFIle()方法中的第二个参数字符串一致。 3、 新增这个file_path的xml文件: 右键res目录,New —》 Dirctory,创建一个xml目录,右键xml目录创建一个file_paths.xml文件: 其中,external-path就是用来指定Uri共享的。 4、还需要在AndroidMainifest.xml中声明一下访问SD卡的权限: package=“com.example.cameraalbumtest” > … 8.3.2 从相册中选择照片 从CameraAlbumTest项目基础进行修改。 1、修改activity_main.xml,增加一个按钮