需求:当某个应用程序希望向用户发送一些提示信息又不在前台运行时.
新建一个项目, 修改 activity_main.xml, 添加一个按钮, 用来弹出通知.
新建布局文件 notification_layout.xml, 作为点击通知后出现的活动的布局. 相对布局, 含有一个局中显示的 TextView.
新建活动 NotificationActivity , 代码:
public class NotificationActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.notification_layout);
//通知图标消失
NotificationManager manager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(1);//1为通知的id
}
}
别忘了在 清单文件 中注册这个活动.
然后修改 MainActivity 的代码:
public class MainActivity extends Activity implements View.OnClickListener {
private Button sendNotice;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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) getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.mipmap.ic_launcher,
"This is ticker text", System.currentTimeMillis());
Intent intent = new Intent(this, NotificationActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
notification.setLatestEventInfo(this, "This is content title",
"This is content text", pi);
manager.notify(1, notification);
break;
default:
break;
}
}
}
可见, 创建通知的步骤:
* 调用 Context 的 getSystemService()
方法得到 NotificationManager 对象, 来对通知进行管理.
* 创建一个 Notification 对象. 该类的有参构造函数需要三个参数, 第一个指定通知的图标, 传入图片id, 第二个指定通知的 ticker 内容, 第三个指定通知的创建时间, 以毫秒为单位.
* 对通知的布局进行设定, 调用 Notification 的 setLatestEventInfo()
方法, 该方法接受四个参数, 第一个 Context, 第二个指定标题内容, 第三个指定通知正文内容, 第四个指定 PendingIntent 对象.
* PendingIntent, 可理解为延迟指定的 Intent. 提供了几个静态方法用于获取它的实例, 比如 getActivity()
, getBroadcast()
, getService()
. 这几个方法要的参数都一样, 第一个是 Context, 第二个是请求码, 一般传入0, 第三个是 Intent 对象, 使用这个Intent对象来构建出 PendingIntent 的”意图”. 第四个参数用于确定 PendingIntent 的行为, 有四个值可以选: FLAG_ONE_SHOT, FLAG_NO_CREATE, FLAG_CANCEL_CURRENT, FLAG_UPDATE_CURRENT.
* 将通知显示出来. 调用 NotificationManager 的 notify()
方法. 该方法两个参数, 第一个是id, 第二个是 Notification 对象.
Uri soundUri = Uri.fromFile(new File("/system/media/audio/ringtones/Basic_tone.ogg"));
notification.sound = soundUri;
vibrate
属性. 这个一个长整形数组, 用于设置手机静止和震动的时常, 以毫秒为单位. 下标为0的值表示手机静止的时长, 下标为1的表示震动的时长, 下标为2的又表示静止的时长, 以此类推. 例如, 如果想要手机在通知到来的时候立刻震动1秒, 然后静止1秒, 再震动1秒, 代码:long[] vibrates = {0, 1000, 1000, 1000};
notification.vibrate = vibrates;
notification.ledARGB = Color.GREEN;
notification.ledOnMS = 1000;
notification.ledOffMS = 1000;
notification.flags = Notification.FLAG_SHOW_LIGHTS;
如果不想进行这么多设置, 可以直接使用通知的默认效果, 会根据当前手机的环境来决定播放什么铃声以及如何震动, 写法:
notification.defaults = Notification.DEAFAULT_ALL;
新建一个项目, 修改布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="From" />
<TextView
android:id="@+id/sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="Cotent" />
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
LinearLayout>
LinearLayout>
修改 MainActivity , 利用广播机制接受短信:
public class MainActivity extends Activity {
private TextView sender;
private TextView content;
private IntentFilter receiveFilter;
private MessageReceiver messageReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sender = (TextView) findViewById(R.id.sender);
content = (TextView) findViewById(R.id.content);
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
}
class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
//使用pdu密钥来提取一个 SMS pdus 数组, 每一个pdu都表示一条短信消息
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
//获取发送方号码
String address = messages[0].getOriginatingAddress();
//获取短信内容
String fullMessage = "";
for (SmsMessage message : messages) {
fullMessage = fullMessage + message.getMessageBody();
}
sender.setText(address);
content.setText(fullMessage);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(messageReceiver);
}
}
最后, 在清单文件中声明权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
很简单, 只需要两步.
在onCreate()
方法中, 给 receiveFilter添加好动作之后加入:
receiveFilter.setPriority(100);
在内部类的onReceive()
方法中, 最后添加拦截广播的代码:
abortBroadcast();
修改 activity_main.xml :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="From" />
<TextView
android:id="@+id/sender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="Cotent" />
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:text="To:" />
<EditText
android:id="@+id/to"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />
LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp">
<EditText
android:id="@+id/msg_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="Send" />
LinearLayout>
LinearLayout>
修改 MainActivity :
public class MainActivity extends Activity {
private TextView sender;
private TextView content;
private IntentFilter receiveFilter;
private MessageReceiver messageReceiver;
private EditText to;
private EditText msgInput;
private Button send;
private IntentFilter sendFilter;
private SendStatusReceiver sendStatusReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sender = (TextView) findViewById(R.id.sender);
content = (TextView) findViewById(R.id.content);
receiveFilter = new IntentFilter();
receiveFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
receiveFilter.setPriority(100);
messageReceiver = new MessageReceiver();
registerReceiver(messageReceiver, receiveFilter);
to = (EditText) findViewById(R.id.to);
msgInput = (EditText) findViewById(R.id.msg_input);
send = (Button) findViewById(R.id.send);
sendFilter = new IntentFilter();
sendFilter.addAction("SENT_SMS_ACTION");
sendStatusReceiver = new SendStatusReceiver();
registerReceiver(sendStatusReceiver, sendFilter);
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SmsManager smsManager = SmsManager.getDefault();
Intent sentIntent = new Intent("SENT_SMS_ACTION");
PendingIntent pi =
PendingIntent.getBroadcast(MainActivity.this, 0, sentIntent, 0);
smsManager.sendTextMessage(to.getText().toString(), null,
msgInput.getText().toString(), pi, null);
}
});
}
class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
//使用pdu密钥来提取一个 SMS pdus 数组, 每一个pdu都表示一条短信消息
Object[] pdus = (Object[]) bundle.get("pdus");
SmsMessage[] messages = new SmsMessage[pdus.length];
for (int i = 0; i < messages.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
}
//获取发送方号码
String address = messages[0].getOriginatingAddress();
//获取短信内容
String fullMessage = "";
for (SmsMessage message : messages) {
fullMessage = fullMessage + message.getMessageBody();
}
sender.setText(address);
content.setText(fullMessage);
abortBroadcast();//拦截广播
}
}
class SendStatusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (getResultCode() == RESULT_OK) {
Toast.makeText(context, "Send succeeded", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "Send failed", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(messageReceiver);
unregisterReceiver(sendStatusReceiver);
}
}
别忘了最后添加发送短信的权限:
新建一个项目, 修改布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/take_photo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Take Photo" />
<Button
android:id="@+id/choose_from_album"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Choose From Album" />
<ImageView
android:id="@+id/picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
LinearLayout>
修改 MainActivity , 加入逻辑:
public class MainActivity extends Activity {
//定义 startActivityForResult 的请求码
public static final int TAKE_PHOTO = 1;
public static final int CROP_PHOTO = 2;
private Button takePhoto;
private Button chooseFromeAlbum;
private ImageView picture;
private Uri imageUri;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
takePhoto = (Button) findViewById(R.id.take_photo);
chooseFromeAlbum = (Button) findViewById(R.id.choose_from_album);
picture = (ImageView) findViewById(R.id.picture);
takePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//创建 File 对象, 用于存储拍照后的图片, 存储在 SD卡根目录下
File outputImage =
new File(Environment.getExternalStorageDirectory(), "output_image.jpg");
if (outputImage.exists()) {
outputImage.delete();
}
try {
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, TAKE_PHOTO);
}
});
chooseFromeAlbum.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
File outputImage =
new File(Environment.getExternalStorageDirectory(), "output_image.jpg");
if (outputImage.exists()) {
outputImage.delete();
}
try {
outputImage.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
imageUri = Uri.fromFile(outputImage);
Intent intent = new Intent("android.intent.action.GET_CONTENT");
intent.setType("image/*");
intent.putExtra("crop", true);
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case TAKE_PHOTO:
if (resultCode == RESULT_OK) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(imageUri, "image/*");
intent.putExtra("scale", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, CROP_PHOTO);
}
break;
case CROP_PHOTO:
if (resultCode == RESULT_OK) {
try {
Bitmap bitmap = BitmapFactory.decodeStream
(getContentResolver().openInputStream(imageUri));
picture.setImageBitmap(bitmap);//裁剪后的照片显示出来
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
break;
default:
break;
}
}
}
最后, 添加权限:
使用 MediaPlayer 来实现.
新建一个项目, 修改 activity_main.xml :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Play" />
<Button
android:id="@+id/pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pause" />
<Button
android:id="@+id/stop"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Stop" />
LinearLayout>
修改 MainActivity :
public class MainActivity extends Activity implements View.OnClickListener {
private Button play;
private Button pause;
private Button stop;
private MediaPlayer mediaPlayer = new MediaPlayer();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
play = (Button) findViewById(R.id.play);
pause = (Button) findViewById(R.id.pause);
stop = (Button) findViewById(R.id.stop);
play.setOnClickListener(this);
pause.setOnClickListener(this);
stop.setOnClickListener(this);
initMediaPlayer();//初始化
}
private void initMediaPlayer() {
try {
File file = new File(Environment.getExternalStorageDirectory(), "1.mp3");
mediaPlayer.setDataSource(file.getPath());
mediaPlayer.prepare();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!mediaPlayer.isPlaying()) {
mediaPlayer.start();
}
break;
case R.id.pause:
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
break;
case R.id.stop:
if (mediaPlayer.isPlaying()) {
mediaPlayer.reset();
initMediaPlayer();
}
break;
default:
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
}
}
}
最后, 添加权限:
新建一个项目, 布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<VideoView
android:id="@+id/video_view"
android:layout_width="match_parent"
android:layout_height="370dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/play"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Play" />
<Button
android:id="@+id/pause"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Pause" />
<Button
android:id="@+id/replay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Replay" />
LinearLayout>
LinearLayout>
修改 MainActivity :
public class MainActivity extends Activity implements View.OnClickListener {
private VideoView videoView;
private Button play;
private Button pause;
private Button replay;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
play = (Button) findViewById(R.id.play);
pause = (Button) findViewById(R.id.pause);
replay = (Button) findViewById(R.id.replay);
videoView = (VideoView) findViewById(R.id.video_view);
play.setOnClickListener(this);
pause.setOnClickListener(this);
replay.setOnClickListener(this);
initVideoPath();
}
private void initVideoPath() {
File file = new File(Environment.getExternalStorageDirectory(), "movie.3gp");
videoView.setVideoPath(file.getPath());//指定视频文件的路径
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.play:
if (!videoView.isPlaying()) {
videoView.start();
}
break;
case R.id.pause:
if (videoView.isPlaying()) {
videoView.pause();
}
break;
case R.id.replay:
if (videoView.isPlaying()) {
videoView.resume();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (videoView != null) {
videoView.suspend();//释放资源
}
}
}
添加权限:
注意, 其实 VideoView只是对 MediaPlayer 进行了很好的封装, 它的背后仍然是使用 MediaPlayer 来对视频文件进行控制的. 而且, VideoView 并不是一个万能的视频播放工具类, 在视频格式和播放效率都存在不足. 对于播放一些游戏的片头动画或者某个应用的视频宣传, 使用 VideoView 还是比较靠谱的.