[转]大话企业级Android应用开发实战 音乐播放器的开发
29.2 创 建 界 面
在main.xml中添按钮等控件,完成音乐播放器的界面,代码如下:
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/filename"
/>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="aa.mp3"
android:id="@+id/filename"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start"
android:id="@+id/startbutton"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="@string/pause"
android:id="@+id/pausebutton"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="@string/stop"
android:id="@+id/stopbutton"
/>
</LinearLayout>
</LinearLayout>
29.3 业 务 代 码
具体实现代码如下:
MusicPlayerActivity.java
package com.sharpandroid.activity;
import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class MusicPlayerActivity extends Activity {
private static final String TAG = "MusicPlayerActivity";
private EditText namefileText;
private MediaPlayer mediaPlayer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
ButtonClickEnvent envent = new ButtonClickEnvent();
Button startbutton = (Button)this.findViewById(R.id.startbutton);
startbutton.setOnClickListener(envent);
Button pausebutton = (Button)this.findViewById(R.id.pausebutton);
pausebutton.setOnClickListener(envent);
Button stopbutton = (Button)this.findViewById(R.id.stopbutton);
stopbutton.setOnClickListener(envent);
namefileText = (EditText) this.findViewById(R.id.filename);
mediaPlayer = new MediaPlayer();
}
private class ButtonClickEnvent implements View.OnClickListener{
@Override
public void onClick(View v) {
try {
switch (v.getId()) {
case R.id.startbutton://播放
String filename = namefileText.getText().toString();
mediaPlayer.reset();//重设
mediaPlayer.setDataSource("/sdcard/"+ filename);
mediaPlayer.prepare();//缓冲
mediaPlayer.start();//播放
break;
case R.id.pausebutton://暂停
if(mediaPlayer.isPlaying()){//正在播放就暂停
mediaPlayer.pause();
((Button) v).setText("继续");
}else{//否则就播放
mediaPlayer.start();
((Button) v).setText("暂停");
}
break;
case R.id.stopbutton://停止
if(mediaPlayer.isPlaying()){
mediaPlayer.stop();
}
break;
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
@Override
protected void onPause() {
if(mediaPlayer!=null){
if(mediaPlayer.isPlaying()) mediaPlayer.pause();
}
super.onPause();
}
@Override
protected void onResume() {
if(mediaPlayer!=null){
if(!mediaPlayer.isPlaying()) mediaPlayer.start();
}
super.onResume();
}
@Override
protected void onDestroy() {
if(mediaPlayer!=null){
if(mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.release();
}
super.onDestroy();
}
}
30 音乐在线播放的开发
30.2 界 面
在main.xml中的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/
android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="10px"
android:background="@drawable/back">
<TextView android:id="@+id/text_kb_streamed"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:text="流媒体测试"/>
<Button android:id="@+id/button_stream"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10px"
style="?android:attr/buttonStyleSmall"
android:text="开始缓冲"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<SeekBar
android:id="@+id/progress_bar"
android:layout_height="wrap_content"
android:layout_width="200px"
style="?android:attr/progressBarStyleHorizontal"
/>
<TextView
android:id="@+id/playTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/progress_bar"
android:text="00:00"
></TextView>
</RelativeLayout>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageButton android:id="@+id/button_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5px"
style="?android:attr/buttonStyleSmall"
android:src="@drawable/button_pause"/>
</RelativeLayout>
</LinearLayout>
30.3 流 媒 体 类
(3)d代码如下:
public void downloadAudioIncrement(String mediaUrl) throws IOException {
URLConnection cn = new URL(mediaUrl).openConnection();
cn.connect();
InputStream stream = cn.getInputStream();
if (stream == null) {
Log.e(getClass().getName(), "Unable to create InputStream for
mediaUrl:" + mediaUrl);
}
downloadingMediaFile = new File(context.getCacheDir(),
"downloadingMedia.dat");
if (downloadingMediaFile.exists()) {
downloadingMediaFile.delete(); //如果下载完成则删除
}
FileOutputStream out = new FileOutputStream(downloadingMediaFile);
byte buf[] = new byte[16384];
int totalBytesRead = 0, incrementalBytesRead = 0;
do {
int numread = stream.read(buf);
if (numread <= 0)
break;
out.write(buf, 0, numread);
totalBytesRead += numread;
incrementalBytesRead += numread;
totalKbRead = totalBytesRead/1000;//totalKbRead表示已经下载的文件大小
testMediaBuffer();
fireDataLoadUpdate();
} while (validateNotInterrupted());
stream.close();
if (validateNotInterrupted()) {
fireDataFullyLoaded();
}
}
private boolean validateNotInterrupted() {
if (isInterrupted) {
if (mediaPlayer != null) {
mediaPlayer.pause();
}
return false;
} else {
return true;
}
}
private void testMediaBuffer() {
Runnable updater = new Runnable() {
public void run() {
if (mediaPlayer == null) {
if ( totalKbRead >= INTIAL_KB_BUFFER) {
try {
startMediaPlayer();
} catch (Exception e) {
Log.e(getClass().getName(), "Error copying
buffered conent.", e);
}
}
} else if ( mediaPlayer.getDuration() - mediaPlayer.
getCurrentPosition() <= 1000 ){
transferBufferToMediaPlayer();
}
}
};
handler.post(updater);
}
(4)startMediaPlayer()方法用来播放音频文件,首先调用moveFile()方法将下载的文件复制,用mediaPlayer的API播放文件,startPlayProgressUpdater()方法更新进度条。代码如下:
private void startMediaPlayer() {
try {
File bufferedFile = new File(context.getCacheDir(),"playingMedia"
+ (counter++) + ".dat");
moveFile(downloadingMediaFile,bufferedFile);
Log.e(getClass().getName(),"Buffered File path: " + bufferedFile.
getAbsolutePath());
Log.e(getClass().getName(),"Buffered File length: " + bufferedFile.
length()+"");
mediaPlayer = createMediaPlayer(bufferedFile);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.start();
startPlayProgressUpdater();
playButton.setEnabled(true);
} catch (IOException e) {
Log.e(getClass().getName(), "Error initializing the MediaPlayer.", e);
}
}
(5)createMediaPlayer()方法用来得到一个MediaPlayer对象。代码如下:
private MediaPlayer createMediaPlayer(File mediaFile)
throws IOException {
MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setOnErrorListener(
new MediaPlayer.OnErrorListener() {
public boolean onError(MediaPlayer mp, int what, int
extra) {
Log.e(getClass().getName(), "Error in MediaPlayer: ("
+ what +") with extra (" +extra +")" );
return false;
}
});
FileInputStream fis = new FileInputStream(mediaFile);
mPlayer.setDataSource(fis.getFD());//此方法返回与流相关联的文件说明符。
mPlayer.prepare();
return mPlayer;
}
(6)transferBufferToMediaPlayer()方法将下载的文件复制到一个临时的缓存文件中,暂停音频播放,如果音频正在播放或者多媒体的总长度和多媒体已播放的长度之差小于一秒的时候继续播放。代码如下:
private void transferBufferToMediaPlayer() {
try {
boolean wasPlaying = mediaPlayer.isPlaying();
int curPosition = mediaPlayer.getCurrentPosition();
File oldBufferedFile = new File(context.getCacheDir(),
"playingMedia" + counter + ".dat");
File bufferedFile = new File(context.getCacheDir(),"playingMedia"
+ (counter++) + ".dat");
bufferedFile.deleteOnExit();
moveFile(downloadingMediaFile,bufferedFile);
mediaPlayer.pause();
mediaPlayer = createMediaPlayer(bufferedFile);
mediaPlayer.seekTo(curPosition);
boolean atEndOfFile = mediaPlayer.getDuration() - mediaPlayer.
getCurrentPosition() <= 1000;
if (wasPlaying || atEndOfFile){
mediaPlayer.start();
}
oldBufferedFile.delete();
}catch (Exception e) {
Log.e(getClass().getName(), "Error updating to newly loaded
content.", e);
}
}
(7)fireDataLoadUpdate()方法开启一个线程根据已下载的文件大小更新进度条。代码如下:
private void fireDataLoadUpdate() {
Runnable updater = new Runnable() {
public void run() {
float loadProgress = ((float)totalKbRead/(float)mediaLengthInKb);
progressBar.setSecondaryProgress((int)(loadProgress*100));
}
};
handler.post(updater);
}
(8)fireDataFullyLoaded()方法开启一个线程调用transferBufferToMediaPlayer()方法复制缓存文件,之后播放,然后删除下载的临时文件。代码如下:
private void fireDataFullyLoaded() {
Runnable updater = new Runnable() {
public void run() {
transferBufferToMediaPlayer();
downloadingMediaFile.delete();
}
};
handler.post(updater);
}
(9)startPlayProgressUpdater()方法根据播放的进度更新进度条,并且显示播放的时间进度。代码如下:
public void startPlayProgressUpdater() {
float progress = (((float)mediaPlayer.getCurrentPosition()/
1000)/mediaLengthInSeconds);
progressBar.setProgress((int)(progress*100));
int pos=mediaPlayer.getCurrentPosition();
int min = (pos/1000)/60;
int sec = (pos/1000)%60;
if(sec<10)
playTime.setText(""+min+":0"+sec);//把音乐播放的进度,转换成时间
else
playTime.setText(""+min+":"+sec);
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
startPlayProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
(10)moveFile(File oldLocation, File newLocation)方法用来实现文件的复制。代码如下:
public void moveFile(File oldLocation, File newLocation)
throws IOException {
if ( oldLocation.exists( )) {
BufferedInputStream reader = new BufferedInputStream( new
FileInputStream(oldLocation) );
BufferedOutputStream writer = new BufferedOutputStream( new
FileOutputStream(newLocation, false));
try {
byte[] buff = new byte[8192];
int numChars;
while((numChars = reader.read(buff, 0, buff.length))!= -1) {
writer.write( buff, 0, numChars );
}
} catch( IOException ex ) {
throw new IOException("IOException when transferring " +
oldLocation.getPath() + " to " + newLocation.getPath());
} finally {
try {
if ( reader != null ){
writer.close();
reader.close();
}
} catch( IOException ex ){
Log.e(getClass().getName(),"Error closing files when
transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
} else {
throw new IOException("Old location does not exist when
transferring " + oldLocation.getPath() + " to " + newLocation.getPath() );
}
}
30.4 业 务 代 码
代码如下:
package com.sharpandroid.music.activity;
import java.io.IOException;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import com.sharpandroid.music.R;
import com.sharpandroid.music.StreamingMediaPlayer;
public class MediaPlayer extends Activity {
private Button streamButton;
private ImageButton playButton;
private boolean isPlaying;
private TextView playTime;
private StreamingMediaPlayer audioStreamer;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
initControls();
}
private void initControls() {
playTime=(TextView) findViewById(R.id.playTime);
streamButton = (Button) findViewById(R.id.button_stream);
streamButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
startStreamingAudio();
}});
playButton = (ImageButton) findViewById(R.id.button_play);
playButton.setEnabled(false);
playButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (audioStreamer.getMediaPlayer().isPlaying()) {
audioStreamer.getMediaPlayer().pause();
playButton.setImageResource(R.drawable.button_play);
} else {
audioStreamer.getMediaPlayer().start();
audioStreamer.startPlayProgressUpdater();
playButton.setImageResource(R.drawable.button_pause);
}
isPlaying = !isPlaying;
}});
}
private void startStreamingAudio() {
try {
final SeekBar progressBar = (SeekBar) findViewById(R.id.
progress_bar);
if ( audioStreamer != null) {
audioStreamer.interrupt();
}
audioStreamer = new StreamingMediaPlayer(this, playButton,
streamButton, progressBar,playTime);
audioStreamer.startStreaming("http://www.ktcm.net/music/
00.mp3",5208, 216);
streamButton.setEnabled(false);
} catch (IOException e) {
Log.e(getClass().getName(), "Error starting to stream audio.", e);
}
}
}
31 视频播放器的开发
31.2 创 建 界 面
在main.xml中实现播放器的界面,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF"
>
<SurfaceView
android:layout_width="fill_parent"
android:layout_height="240dip"
android:id="@+id/surfaceView"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/play"
android:id="@+id/startbutton"
/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:src="@drawable/pause"
android:id="@+id/pausebutton"
/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:src="@drawable/reset"
android:id="@+id/resetbutton"
/>
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:src="@drawable/stop"
android:id="@+id/stopbutton"
/>
</LinearLayout>
</LinearLayout>
31.3 业 务 代 码
做完界面之后,在VideoPlayerActivity中首先要找到SurfaceView,然后调用getHolder(). setFixedSize()方法设置分辨率,单击按钮的事件的处理和之前我们做过的音乐播放器大致相同,VideoPlayerActivity的代码如下:
VideoPlayerActivity.java
package com.sharpandroid.activity;
import android.app.Activity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageButton;
public class VideoPlayerActivity extends Activity {
private SurfaceView surfaceView;
private MediaPlayer mediaPlayer;
private static final String TAG = "VideoPlayActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
surfaceView = (SurfaceView)this.findViewById(R.id.surfaceView);
ButtonOnclickEnvent envent = new ButtonOnclickEnvent();
ImageButton startbutton = (ImageButton)this.findViewById
(R.id.startbutton);
startbutton.setOnClickListener(envent);
ImageButton pausebutton = (ImageButton)this.findViewById
(R.id.pausebutton);
pausebutton.setOnClickListener(envent);
ImageButton resetbutton = (ImageButton)this.findViewById
(R.id.resetbutton);
resetbutton.setOnClickListener(envent);
ImageButton stopbutton = (ImageButton)this.findViewById
(R.id.stopbutton);
stopbutton.setOnClickListener(envent);
surfaceView.getHolder().setFixedSize(176, 144); //设置分辨率
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_
TYPE_PUSH_BUFFERS);
mediaPlayer = new MediaPlayer();
}
@Override
protected void onPause() {
if(mediaPlayer!=null){
if(mediaPlayer.isPlaying()) mediaPlayer.pause();
}
super.onPause();
}
@Override
protected void onResume() {
if(mediaPlayer!=null){
if(!mediaPlayer.isPlaying()) mediaPlayer.start();
}
super.onResume();
}
@Override
protected void onDestroy() {
if(mediaPlayer!=null){
if(mediaPlayer.isPlaying()) mediaPlayer.stop();
mediaPlayer.release();
}
super.onDestroy();
}
private class ButtonOnclickEnvent implements View.OnClickListener{
@Override
public void onClick(View v) {
try {
switch (v.getId()) {
case R.id.startbutton://播放
mediaPlayer.reset();//重设
mediaPlayer.setAudioStreamType(AudioManager.
STREAM_MUSIC);
/* 设置Video影片以SurfaceHolder播放 */
mediaPlayer.setDisplay(surfaceView.getHolder());
mediaPlayer.setDataSource("/sdcard/aa.3gp");
mediaPlayer.prepare();//缓冲
mediaPlayer.start();//播放
break;
case R.id.pausebutton://暂停
if(mediaPlayer.isPlaying()){//正在播放就暂停
mediaPlayer.pause();
}else{//否则就播放
mediaPlayer.start();
}
break;
case R.id.resetbutton://重播
mediaPlayer.seekTo(0);
break;
case R.id.stopbutton://停止
if(mediaPlayer.isPlaying()){
mediaPlayer.stop();
}
break;
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
}
}
32 手机拍照的开发
32.2 创 建 界 面
代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<SurfaceView android:id="@+id/preview_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"/>
</LinearLayout>
32.3 业 务 代 码
代码如下:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
public class CameraActivity extends Activity {
private static final String TAG = "CameraActivity";
private CameraManager cameraManager;
private SurfaceView surfaceView;
private boolean hasSurface;//SurfaceView是否已经创建完成
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window = getWindow();
requestWindowFeature(Window.FEATURE_NO_TITLE);
window.setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,
WindowManager.LayoutParams. FLAG_FULLSCREEN);
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_
SCREEN_ON);//高亮
setContentView(R.layout.main);
cameraManager = new CameraManager(this);
surfaceView = (SurfaceView) findViewById(R.id.preview_view);
}
33 手机录音的开发
33.2 创 建 界 面
在main.xml中,加入三个按钮控件,代码如下:
Main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/status"
/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/record"
android:id="@+id/recordbutton"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="@string/stop"
android:id="@+id/stopbutton"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="@string/play"
android:id="@+id/playbutton"
/>
</LinearLayout>
</LinearLayout>
在AndroidManifest.xml文件中加入,读写SD卡的权限和录音权限,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sharpandroid.redcorder"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/
app_name">
<activity android:name=".RecorderActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_
STORAGE"></uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_
FILESYSTEMS"></uses-permission>
</manifest>
33.3 业 务 代 码
代码如下:
package com.sharpandroid.redcorder;
import java.io.File;
import java.io.IOException;
import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class RecorderActivity extends Activity {
private MediaRecorder mediaRecorder;
private TextView title;
private Button recordButton;
private Button stopButton;
private Button playButton;
private File mediaFile;
private boolean sd;
private File dir;
private boolean isRecord;
public MediaPlayer recordPlayer=new MediaPlayer();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button recordButton=(Button)findViewById(R.id.recordbutton);
Button stopButton=(Button)findViewById(R.id.stopbutton);
Button playButton=(Button)findViewById(R.id.playbutton);
title=(TextView)findViewById(R.id.status);
recordButton.setOnClickListener(listener);
stopButton.setOnClickListener(listener);
playButton.setOnClickListener(listener);
title.setText("开始录音。。。");
/* 判断是否存在SD卡 */
sd = Environment.getExternalStorageState().equals(
android.os.Environment.MEDIA_MOUNTED);
if (sd) //如果SD卡存在的话,得到音频文件要保存的路径
dir = Environment.getExternalStorageDirectory();
}
//处理多个按钮的单击事件
private View.OnClickListener listener=new View.OnClickListener() {
@Override
public void onClick(View v) {
Button button=(Button)v;
switch(button.getId())
{
case R.id.recordbutton: //录音
if(!sd){
Toast.makeText(RecorderActivity.this, "SD卡没有准备好",
2).show();
}
try {
mediaFile = File.createTempFile("newFile", ".amr",
dir); //在SD卡上创建音频文件
mediaRecorder = new MediaRecorder();
/* 设置录音来源为麦克风 */
mediaRecorder
.setAudioSource(MediaRecorder.
AudioSource.MIC);
mediaRecorder
.setOutputFormat(MediaRecorder.
OutputFormat.DEFAULT);
mediaRecorder
.setAudioEncoder(MediaRecorder.
AudioEncoder.DEFAULT);
mediaRecorder.setOutputFile(mediaFile
.getAbsolutePath());
mediaRecorder.prepare();
mediaRecorder.start();
}catch (IOException e) {
e.printStackTrace();
}
title.setText("录音中");
isRecord=true;
break;
case R.id.stopbutton:
/* 停止录音 */
if(mediaFile!=null)
{
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder = null;
title.setText("停止:" + mediaFile.getName());
isRecord = false;
}
break;
case R.id.playbutton:
if(mediaFile!=null&&isRecord==false)
{
/* 打开播放的程序 */
openFile(mediaFile);
}
}
}
};
private void openFile(File f) //根据相应的文件类型,打开相应的程序
{
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
String type = getFileType(f);
intent.setDataAndType(Uri.fromFile(f), type);
startActivity(intent);
}
private String getFileType(File f) //判断要打开的文件类型
{
String end = f.getName().substring(
f.getName().lastIndexOf(".") + 1, f.getName().length())
.toLowerCase();
String type = "";
if (end.equals("mp3") || end.equals("aac") || end.equals("aac")
|| end.equals("amr") || end.equals("mpeg")
|| end.equals("mp4"))
{
type = "audio";
}
else if (end.equals("jpg") || end.equals("gif")
|| end.equals("png") || end.equals("jpeg"))
{
type = "image";
}
else
{
type = "*";
}
type += "/*";
return type;
}
}
34 手机闹钟的开发
34.2 创 建 界 面
在main.xml文件中加入两个按钮,用来实现闹钟和取消闹钟,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="定制闹钟"
android:id="@+id/okButton"
></Button>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/okButton"
android:layout_alignTop="@id/okButton"
android:text="取消闹钟"
android:id="@+id/cannelButton"
></Button>
</RelativeLayout>
</LinearLayout>
34.3 业 务 代 码
代码如下:
TimeReceive.java
package com.sharpandroid.time;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class TimeReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "你的时间到了!!!", 3).show();
}
}
因为使用了BroadcastReceiver服务,因此在AndroidManifest.xml文件中要加入声明,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sharpandroid.time"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/
app_name">
<receiver android:name="TimeReceive" android:process=":remote" />
<activity android:name=".TimeActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="7" />
</manifest>
主要代码如下:
TimeActivity.java
package com.sharpandroid.time;
import java.util.Calendar;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.TimePickerDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TimePicker;
import android.widget.Toast;
public class TimeActivity extends Activity {
/** Called when the activity is first created. */
private Calendar calendar=Calendar.getInstance();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button ok=(Button)findViewById(R.id.okButton);
Button cannel=(Button)findViewById(R.id.cannelButton);
//设置闹钟
ok.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/* 取得系统时间作为TimePickerDialog的默认值 */
calendar.setTimeInMillis(System.currentTimeMillis());
int mHour=calendar.get(Calendar.HOUR_OF_DAY);
int mMinute=calendar.get(Calendar.MINUTE);
new TimePickerDialog(TimeActivity.this,
new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker view, int
hourOfDay, int minute) {
// TODO Auto-generated method stub
/* 取得设置后的时间 */
calendar.setTimeInMillis(System.
currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY,
hourOfDay);
calendar.set(Calendar.MINUTE,minute);
calendar.set(Calendar.SECOND,0);
calendar.set(Calendar.MILLISECOND,0);
/* 指定闹钟设置时间到时提示 */
Intent intent = new Intent(TimeActivity.
this, TimeReceive.class);
/* 创建PendingIntent */
PendingIntent sender=PendingIntent.
getBroadcast(
TimeActivity.this,0, intent, 0);
/*
* 以set()设置的PendingIntent只会运行一次
* */
AlarmManager am;
am = (AlarmManager)getSystemService
(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
sender
);
/* 更新显示的设置闹钟时间 */
String tmpS=format(hourOfDay)+":
"+format(minute);
/* 以Toast提示设置已完成 */
Toast.makeText(TimeActivity.this,"设置闹
钟时间为"+tmpS,
Toast.LENGTH_SHORT)
.show();
}
}
, mHour, mMinute, true).show();
}
});
//取消闹铃
cannel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(TimeActivity.this,
TimeReceive.class);
PendingIntent pendingIntent=PendingIntent.getBroadcast
(TimeActivity.this, 0, intent, 0);
AlarmManager am; //取消闹钟管理
am=(AlarmManager)getSystemService(ALARM_SERVICE);
am.cancel(pendingIntent);
Toast.makeText(TimeActivity.this,"闹钟已取消!",3)
.show();
}
});
}
/* 日期时间显示两位数的方法 */
private String format(int x)
{
String s=""+x;
if(s.length()==1) s="0"+s;
return s;
}
}
35 手势识别的开发
35.2 Android手势识别
35.2.2 创建应用
Layout的代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<android.gesture.GestureOverlayView
android:id="@+id/ usergestures"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
/>
</LinearLayout>
(3)编写Activity。
进行手势识别,得到最配对的,获取手势的名字,并打印。
public class MainActivity extends Activity implements
OnGesturePerformedListener{
GestureLibrary myLibraries;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//获取Layout中的手势图层
GestureOverlayView gestures = (GestureOverlayView)
findViewById(R.id.usergestures);
//设置对该图层的监听
gestures.addOnGesturePerformedListener(this);
//加载已经创建的手势文件
myLibraries = GestureLibraries.fromRawResource(this,
R.raw.gestures);
//检测手势文件读取是否正确
if (!myLibraries.load()) {
Toast.makeText(MainActivity.this, "读取手势文件出错,程序不能正常运
行。", Toast.LENGTH_LONG);
}
}
//传入图层与用户的手势
public void onGesturePerformed(GestureOverlayView overlay, Gesture
gesture) {
//将用户手势与已经建立好的手势进行比对,将结果放入List中
ArrayList<Prediction> predictions = myLibraries.recognize
(gesture);
//判断,如果相似,即打印出手势的名字
if (predictions.size() > 0) {
Prediction prediction = (Prediction) predictions.get(0);
//这里,用户可设置一些自定义的操作,来增加用户体验
if (prediction.score > 1.0) {
Toast.makeText(this, prediction.name,
Toast.LENGTH_SHORT).show();
}
}
}
}
36 图片浏览的开发
36.1 图 片 介 绍
36.1.1 图片列表
(2)在main.xml中修改Layout。这里需要一个GridView的控件。
<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/grid_photo"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:numColumns="auto_fit"
android:verticalSpacing="5dp"
android:horizontalSpacing="5dp"
android:columnWidth="90dp"
android:gravity="center"
/>
(3)编写Activity。
MainActivity.java
public class MainActivity extends Activity {
//将raw的图片索引值放入数组中
private Integer[] photos = {
R.drawable.android_01, R.drawable.android_02, R.drawable.
android_03,
…
R.drawable.android_24
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//加载在layout中添加的GridView控件
GridView grid_photo = (GridView)findViewById(R.id.grid_photo);
grid_photo.setAdapter(new PhotoAdapter(this));
grid_photo.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
Intent intent = new
//通过Intent打开showPhoto,并将相应的图片ID传递给它
Intent(MainActivity.this,showPhoto.class);
intent.putExtra("position", position);
startActivity(intent);
}
});
}
//继承了BaseAdapter的方法,对其进行封装,添加相应显示图片的参数
public class PhotoAdapter extends BaseAdapter {
private Context mContext;
public PhotoAdapter Context c) {
mContext = c;
}
public int getCount() {
return photos.length;
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return 0;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView;
if (convertView == null) {
imageView = new ImageView(mContext);
//分别代表着左、上、右、下的边框宽度
imageView.setPadding(4, 4, 4, 4);
//图片的显示大小的参数
imageView.setLayoutParams(new GridView.LayoutParams(85,
100));
//图片的显示方式(拉伸、居中、适应等类似与windows中壁纸的显示方式)
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} else {
imageView = (ImageView) convertView;
}
imageView.setImageResource(photos[position]);
return imageView;
}
}
}
36.1.3 加入手势
(1)将我们前面提到的android.gesture.GestureOverlayView添加到layout中。
<android.gesture.GestureOverlayView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/usergestures"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
>
<ImageSwitcher
android:id="@+id/switcher"
………
/>
</android.gesture.GestureOverlayView>
(2)在showPhoto.java中添加相应的处理代码。
public class showPhoto extends Activity implements ViewSwitcher.
ViewFactory,
OnGesturePerformedListener{
private Integer[] photos = {
R.drawable.android_01, R.drawable.android_02,
R.drawable.android_03,
……
R.drawable.android_24
};
private ImageSwitcher mSwitcher;
//记录当前图片的索引值
private int currentposition ;
//图片数量,这里是事先加载好的可以直接赋值,实际应用中,我们可以在GridView
页面
//时,通过adapter中getCount()来获得,然后通过Intent传递过来
private static final int MAXSIZE = 23;
GestureLibrary myLibraries;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//取消应用Title栏的显示,增加图片的显示效果
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.show_photo);
mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
//在使用mSwitcher之前一定要调用setFactory方法,它的作用是创建两个图
层,用以ImageSwitcher过渡时使用
mSwitcher.setFactory(this);
//设置图片文件出现的动画效果
mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.slide_in_left));
//设置图片文件消失的动画效果
mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,
android.R.anim.slide_out_right));
//获取Layout中的手势图层
GestureOverlayView gestures = (GestureOverlayView)
findViewById(R.id.usergestures);
//设置对该图层的监听
gestures.addOnGesturePerformedListener(this);
//加载已经创建的手势文件
myLibraries = GestureLibraries.fromRawResource(this,
R.raw.gestures);
//检测手势文件读取是否正确
if (!myLibraries.load()) {
Toast.makeText(showPhoto.this, "读取手势文件出错,程序可能无法
正常运行", Toast.LENGTH_LONG).show();
}
//获得携带数据的Intent,
Intent intent = getIntent();
int index = intent.getIntExtra("position", 0);
currentposition = index;
//通过传递过来的值,设定当前需要显示的图片
mSwitcher.setImageResource(photos[index]);
}
//大图显示
public View makeView() {
ImageView i = new ImageView(this);
i.setBackgroundColor(0xFF000000);
//添加图片显示的样式
i.setScaleType(ImageView.ScaleType.FIT_CENTER);
//设置图片全局显示
i.setLayoutParams(new ImageSwitcher.LayoutParams
(LayoutParams.FILL_PARENT,
LayoutParams.FILL_PARENT));
return i;
}
public void onGesturePerformed(GestureOverlayView overlay, Gesture
gesture) {
//将用户手势与已经建立好的手势进行比对,将结果放入List中
ArrayList<Prediction> predictions = myLibraries.recognize
(gesture);
if (predictions.size() > 0) {
Prediction prediction = (Prediction) predictions.get(0);
//判断,如果相似
if (prediction.score > 1.0) {
if("R".equals(prediction.name)){
//这里需要做一个判断,如果是最后一张的话,需要提示用户
if(currentposition==MAXSIZE){
Toast.makeText(showPhoto.this, "已经是最后一张",
Toast.LENGTH_SHORT).show();
}else{
++currentposition;
mSwitcher.setImageResource(photos[currentposition]);
}
}
//在第一张的时候,同样需要做一个页数的判断,如果是第一张,需要
提示用户
if("L".equals(prediction.name)){
if(currentposition==0){
Toast.makeText(showPhoto.this, "已经是第一张",
Toast.LENGTH_SHORT).show();
}else{
--currentposition;
mSwitcher.setImageResource(photos[currentposition]);
}
}
}
}
}
}
邮箱:steven9801@163.com
QQ: 48039387