一、Image的获取可以通过调Android自带的Camera应用来完成。该应用含有一个Intent-Filter。通过使用
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);startActivityForResult(intent)就可以启动Camera应用了。
二、Image存储,Android系统中含有一个多媒体库,其中包括所有Image、Video、Audio的数据。通过MediaStore对象可以访问相关数据。
闲话少说,直接看例子,这是一本英文书上的,觉得写的很好,自己翻译了一下,并加入了很多注释。以备查询。
package demo.camera;
import java.io.File;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
/**
* 这里多媒体第一个示例,主要介绍Image的获取和存储
* Image的获取可以通过Android自带的Camera应用来获得,
* 图片的存储需要用到MediaStore对象。Android中的多媒体库。
*
* @author Administrator
*
*/
public class MainActivity extends Activity {
private static final int RESULT_CODE = 1;
private Button btnCamera;
private ImageView imageView;
private Uri imageFilePath;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageView = (ImageView)this.findViewById(R.id.imageView);
btnCamera = (Button)this.findViewById(R.id.camera);
btnCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 由于Camara返回的是缩略图,我们可以传递给他一个参数EXTRA_OUTPUT,
* 来将用Camera获取到的图片存储在一个指定的URI位置处。
* 下面就指定image存储在SDCard上,并且文件名为123.jpg
* imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"123.jpg";
* File file = new File(imageFilePath); //创建一个文件
* Uri imageUri = Uri.fromFile(file);
* 然而Android已经提供了一个多媒体库,那里统一存放了设备上所有的多媒体数据。所以,
* 我们可以将获取到的图片存放在那个多媒体库中。
* Android提供了MediaStore类,该类是一个ContentProvider,管理着设备上自带的和外部的多媒体文件,
* 同时包含着每一个多媒体文件的数据信息。
* 为了将数据存储在多媒体库,使用ContentResolver对象来操纵MediaStore对象
* 在MediaStore.Images.Media中有两个URI常量,一个是 EXTERNAL_CONTENT_URI,另一个是INTERNAL_CONTENT_URI
* 第一个URI对应着外部设备(SDCard),第二个URI对应着系统设备内部存储位置。
* 对于多媒体文件,一般比较大,我们选择外部存储方式
* 通过使用ContentResolver对象的insert方法我们可以向MediaStore中插入一条数据
* 这样在检索那张图片的时候,不再使用文件的路径,而是根据insert数据时返回的URI,获取一个InputStream
* 并传给BitmapFactory
*/
//在这里启动Camera。
//Camera中定义了一个Intent-Filter,其中Action是android.media.action.IMAGE_CAPTURE
//我们使用的时候,最好不要直接使用这个,而是用MediaStore中的常量ACTION_IMAGE_CAPTURE.
//这个常量就是对应的上面的action
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//这里我们插入一条数据,ContentValues是我们希望这条记录被创建时包含的数据信息
//这些数据的名称已经作为常量在MediaStore.Images.Media中,有的存储在MediaStore.MediaColumn中了
//ContentValues values = new ContentValues();
ContentValues values = new ContentValues(3);
values.put(MediaStore.Images.Media.DISPLAY_NAME, "testing");
values.put(MediaStore.Images.Media.DESCRIPTION, "this is description");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
imageFilePath = MainActivity.this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFilePath); //这样就将文件的存储方式和uri指定到了Camera应用中
//由于我们需要调用完Camera后,可以返回Camera获取到的图片,
//所以,我们使用startActivityForResult来启动Camera
startActivityForResult(intent, RESULT_CODE);
}
});
}
/**
* 为了获取Camera返回的图片信息,重写该方法。
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CODE){
//说明是由Camera返回的数据
//由Camera应用返回的图片数据是一个Camera对象,存储在一个名为data的extra域
//然后将获取到的图片存储显示在ImageView中
try {
Bundle extra = data.getExtras();
/**
* 然而为了节约内存的消耗,这里返回的图片是一个121*162的缩略图。
* 那么如何返回我们需要的大图呢?看上面
* 然而存储了图片。有了图片的存储位置,能不能直接将图片显示出来呢》
* 这个问题就设计到对于图片的处理和显示,是非常消耗内存的,对于PC来说可能不算什么,但是对于手机来说
* 很可能使你的应用因为内存耗尽而死亡。不过还好,Android为我们考虑到了这一点
* Android中可以使用BitmapFactory类和他的一个内部类BitmapFactory.Options来实现图片的处理和显示
* BitmapFactory是一个工具类,里面包含了很多种获取Bitmap的方法。BitmapFactory.Options类中有一个inSampleSize,比如设定他的值为8,则加载到内存中的图片的大小将
* 是原图片的1/8大小。这样就远远降低了内存的消耗。
* BitmapFactory.Options op = new BitmapFactory.Options();
* op.inSampleSize = 8;
* Bitmap pic = BitmapFactory.decodeFile(imageFilePath, op);
* 这是一种快捷的方式来加载一张大图,因为他不用考虑整个显示屏幕的大小和图片的原始大小
* 然而有时候,我需要根据我们的屏幕来做相应的缩放,如何操作呢?
*
*/
//首先取得屏幕对象
Display display = this.getWindowManager().getDefaultDisplay();
//获取屏幕的宽和高
int dw = display.getWidth();
int dh = display.getHeight();
/**
* 为了计算缩放的比例,我们需要获取整个图片的尺寸,而不是图片
* BitmapFactory.Options类中有一个布尔型变量inJustDecodeBounds,将其设置为true
* 这样,我们获取到的就是图片的尺寸,而不用加载图片了。
* 当我们设置这个值的时候,我们接着就可以从BitmapFactory.Options的outWidth和outHeight中获取到值
*/
BitmapFactory.Options op = new BitmapFactory.Options();
//op.inSampleSize = 8;
op.inJustDecodeBounds = true;
//Bitmap pic = BitmapFactory.decodeFile(imageFilePath, op);//调用这个方法以后,op中的outWidth和outHeight就有值了
//由于使用了MediaStore存储,这里根据URI获取输入流的形式
Bitmap pic = BitmapFactory.decodeStream(this
.getContentResolver().openInputStream(imageFilePath),
null, op);
int wRatio = (int) Math.ceil(op.outWidth / (float) dw); //计算宽度比例
int hRatio = (int) Math.ceil(op.outHeight / (float) dh); //计算高度比例
Log.v("Width Ratio:", wRatio + "");
Log.v("Height Ratio:", hRatio + "");
/**
* 接下来,我们就需要判断是否需要缩放以及到底对宽还是高进行缩放。
* 如果高和宽不是全都超出了屏幕,那么无需缩放。
* 如果高和宽都超出了屏幕大小,则如何选择缩放呢》
* 这需要判断wRatio和hRatio的大小
* 大的一个将被缩放,因为缩放大的时,小的应该自动进行同比率缩放。
* 缩放使用的还是inSampleSize变量
*/
if (wRatio > 1 && hRatio > 1) {
if (wRatio > hRatio) {
op.inSampleSize = wRatio;
} else {
op.inSampleSize = hRatio;
}
}
op.inJustDecodeBounds = false; //注意这里,一定要设置为false,因为上面我们将其设置为true来获取图片尺寸了
pic = BitmapFactory.decodeStream(this.getContentResolver()
.openInputStream(imageFilePath), null, op);
imageView.setImageBitmap(pic);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
package demo.camera;
import java.io.File;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
/**
* 这里多媒体第一个示例,主要介绍Image的获取和存储
* Image的获取可以通过Android自带的Camera应用来获得,
* 图片的存储需要用到MediaStore对象。Android中的多媒体库。
*
* @author Administrator
*
*/
public class MainActivity extends Activity {
private static final int RESULT_CODE = 1;
private Button btnCamera;
private ImageView imageView;
private Uri imageFilePath;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imageView = (ImageView)this.findViewById(R.id.imageView);
btnCamera = (Button)this.findViewById(R.id.camera);
btnCamera.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/**
* 由于Camara返回的是缩略图,我们可以传递给他一个参数EXTRA_OUTPUT,
* 来将用Camera获取到的图片存储在一个指定的URI位置处。
* 下面就指定image存储在SDCard上,并且文件名为123.jpg
* imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath()+"123.jpg";
* File file = new File(imageFilePath); //创建一个文件
* Uri imageUri = Uri.fromFile(file);
* 然而Android已经提供了一个多媒体库,那里统一存放了设备上所有的多媒体数据。所以,
* 我们可以将获取到的图片存放在那个多媒体库中。
* Android提供了MediaStore类,该类是一个ContentProvider,管理着设备上自带的和外部的多媒体文件,
* 同时包含着每一个多媒体文件的数据信息。
* 为了将数据存储在多媒体库,使用ContentResolver对象来操纵MediaStore对象
* 在MediaStore.Images.Media中有两个URI常量,一个是 EXTERNAL_CONTENT_URI,另一个是INTERNAL_CONTENT_URI
* 第一个URI对应着外部设备(SDCard),第二个URI对应着系统设备内部存储位置。
* 对于多媒体文件,一般比较大,我们选择外部存储方式
* 通过使用ContentResolver对象的insert方法我们可以向MediaStore中插入一条数据
* 这样在检索那张图片的时候,不再使用文件的路径,而是根据insert数据时返回的URI,获取一个InputStream
* 并传给BitmapFactory
*/
//在这里启动Camera。
//Camera中定义了一个Intent-Filter,其中Action是android.media.action.IMAGE_CAPTURE
//我们使用的时候,最好不要直接使用这个,而是用MediaStore中的常量ACTION_IMAGE_CAPTURE.
//这个常量就是对应的上面的action
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//这里我们插入一条数据,ContentValues是我们希望这条记录被创建时包含的数据信息
//这些数据的名称已经作为常量在MediaStore.Images.Media中,有的存储在MediaStore.MediaColumn中了
//ContentValues values = new ContentValues();
ContentValues values = new ContentValues(3);
values.put(MediaStore.Images.Media.DISPLAY_NAME, "testing");
values.put(MediaStore.Images.Media.DESCRIPTION, "this is description");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
imageFilePath = MainActivity.this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageFilePath); //这样就将文件的存储方式和uri指定到了Camera应用中
//由于我们需要调用完Camera后,可以返回Camera获取到的图片,
//所以,我们使用startActivityForResult来启动Camera
startActivityForResult(intent, RESULT_CODE);
}
});
}
/**
* 为了获取Camera返回的图片信息,重写该方法。
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_CODE){
//说明是由Camera返回的数据
//由Camera应用返回的图片数据是一个Camera对象,存储在一个名为data的extra域
//然后将获取到的图片存储显示在ImageView中
try {
Bundle extra = data.getExtras();
/**
* 然而为了节约内存的消耗,这里返回的图片是一个121*162的缩略图。
* 那么如何返回我们需要的大图呢?看上面
* 然而存储了图片。有了图片的存储位置,能不能直接将图片显示出来呢》
* 这个问题就设计到对于图片的处理和显示,是非常消耗内存的,对于PC来说可能不算什么,但是对于手机来说
* 很可能使你的应用因为内存耗尽而死亡。不过还好,Android为我们考虑到了这一点
* Android中可以使用BitmapFactory类和他的一个内部类BitmapFactory.Options来实现图片的处理和显示
* BitmapFactory是一个工具类,里面包含了很多种获取Bitmap的方法。BitmapFactory.Options类中有一个inSampleSize,比如设定他的值为8,则加载到内存中的图片的大小将
* 是原图片的1/8大小。这样就远远降低了内存的消耗。
* BitmapFactory.Options op = new BitmapFactory.Options();
* op.inSampleSize = 8;
* Bitmap pic = BitmapFactory.decodeFile(imageFilePath, op);
* 这是一种快捷的方式来加载一张大图,因为他不用考虑整个显示屏幕的大小和图片的原始大小
* 然而有时候,我需要根据我们的屏幕来做相应的缩放,如何操作呢?
*
*/
//首先取得屏幕对象
Display display = this.getWindowManager().getDefaultDisplay();
//获取屏幕的宽和高
int dw = display.getWidth();
int dh = display.getHeight();
/**
* 为了计算缩放的比例,我们需要获取整个图片的尺寸,而不是图片
* BitmapFactory.Options类中有一个布尔型变量inJustDecodeBounds,将其设置为true
* 这样,我们获取到的就是图片的尺寸,而不用加载图片了。
* 当我们设置这个值的时候,我们接着就可以从BitmapFactory.Options的outWidth和outHeight中获取到值
*/
BitmapFactory.Options op = new BitmapFactory.Options();
//op.inSampleSize = 8;
op.inJustDecodeBounds = true;
//Bitmap pic = BitmapFactory.decodeFile(imageFilePath, op);//调用这个方法以后,op中的outWidth和outHeight就有值了
//由于使用了MediaStore存储,这里根据URI获取输入流的形式
Bitmap pic = BitmapFactory.decodeStream(this
.getContentResolver().openInputStream(imageFilePath),
null, op);
int wRatio = (int) Math.ceil(op.outWidth / (float) dw); //计算宽度比例
int hRatio = (int) Math.ceil(op.outHeight / (float) dh); //计算高度比例
Log.v("Width Ratio:", wRatio + "");
Log.v("Height Ratio:", hRatio + "");
/**
* 接下来,我们就需要判断是否需要缩放以及到底对宽还是高进行缩放。
* 如果高和宽不是全都超出了屏幕,那么无需缩放。
* 如果高和宽都超出了屏幕大小,则如何选择缩放呢》
* 这需要判断wRatio和hRatio的大小
* 大的一个将被缩放,因为缩放大的时,小的应该自动进行同比率缩放。
* 缩放使用的还是inSampleSize变量
*/
if (wRatio > 1 && hRatio > 1) {
if (wRatio > hRatio) {
op.inSampleSize = wRatio;
} else {
op.inSampleSize = hRatio;
}
}
op.inJustDecodeBounds = false; //注意这里,一定要设置为false,因为上面我们将其设置为true来获取图片尺寸了
pic = BitmapFactory.decodeStream(this.getContentResolver()
.openInputStream(imageFilePath), null, op);
imageView.setImageBitmap(pic);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
检索并显示媒体库中的图片
如果你在模拟器已经启动的情况下,push了几张图片到SDCard中,建议将模拟器关了,再重新启动一下,否则,刚刚添加的图片,是没有办法获取到的。这是因为Android是在系统启动的时候来扫描模拟器上SDCard中多媒体文件的。
package demo.camera;
import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
/**
* 该类完成图片的检索,显示功能
* @author Administrator
*
*/
public class PhotoManager extends Activity {
public static final float DISPLAY_WIDTH = 200;
public static final float DISPLAY_HEIGHT = 200;
//这里采用ImageButton的原因是有Button的作用
private ImageButton photoView;
private TextView nameView;
private Cursor cursor;
private String photoPath; //存放某张图片对应的位置信息
private Bitmap currPhoto;
//这三个变量主要用来保存Media.DATA,Media.TITLE,Media.DISPLAY_NAME的索引号,来获取每列的数据
private int photoIndex;
//private int titleIndex;
private int nameIndex;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_view);
photoView = (ImageButton)this.findViewById(R.id.image_view);
photoView.setOnClickListener(clickListener);
nameView = (TextView)this.findViewById(R.id.view_name);
//指定获取的列
String columns[] = new String[]{
Media.DATA,Media._ID,Media.TITLE,Media.DISPLAY_NAME
};
//cursor = this.managedQuery(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);
cursor = this.getContentResolver().query(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);
photoIndex = cursor.getColumnIndexOrThrow(Media.DATA);
//titleIndex = cursor.getColumnIndexOrThrow(Media.TITLE);
nameIndex = cursor.getColumnIndexOrThrow(Media.DISPLAY_NAME);
Log.v("HERE First:", "First Debug");
//显示第一张图片,但是首先要判断一下,Cursor是否有值
if(cursor.moveToFirst()){
showImage();
}
}
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(cursor.moveToNext()){
showImage();
}
}
};
/**
* 显示图像信息
*/
private void showImage(){
photoPath = cursor.getString(photoIndex); //这里获取到的就是图片存储的位置信息
//这里怎样获取图片呢?看decodeBitmap
Log.v("Photo Path:", photoPath);
currPhoto = decodeBitmap(photoPath);
photoView.setImageBitmap(currPhoto);
nameView.setText(cursor.getString(nameIndex));
}
/**
* 从path中获取图片信息
* @param path
* @return
*/
private Bitmap decodeBitmap(String path){
BitmapFactory.Options op = new BitmapFactory.Options();
op.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(path, op); //获取尺寸信息
//获取比例大小
int wRatio = (int)Math.ceil(op.outWidth/DISPLAY_WIDTH);
int hRatio = (int)Math.ceil(op.outHeight/DISPLAY_HEIGHT);
//如果超出指定大小,则缩小相应的比例
if(wRatio > 1 && hRatio > 1){
if(wRatio > hRatio){
op.inSampleSize = wRatio;
}else{
op.inSampleSize = hRatio;
}
}
op.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeFile(path, op);
return bmp;
}
}
package demo.camera;
import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.provider.MediaStore.Images.Media;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
/**
* 该类完成图片的检索,显示功能
* @author Administrator
*
*/
public class PhotoManager extends Activity {
public static final float DISPLAY_WIDTH = 200;
public static final float DISPLAY_HEIGHT = 200;
//这里采用ImageButton的原因是有Button的作用
private ImageButton photoView;
private TextView nameView;
private Cursor cursor;
private String photoPath; //存放某张图片对应的位置信息
private Bitmap currPhoto;
//这三个变量主要用来保存Media.DATA,Media.TITLE,Media.DISPLAY_NAME的索引号,来获取每列的数据
private int photoIndex;
//private int titleIndex;
private int nameIndex;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.photo_view);
photoView = (ImageButton)this.findViewById(R.id.image_view);
photoView.setOnClickListener(clickListener);
nameView = (TextView)this.findViewById(R.id.view_name);
//指定获取的列
String columns[] = new String[]{
Media.DATA,Media._ID,Media.TITLE,Media.DISPLAY_NAME
};
//cursor = this.managedQuery(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);
cursor = this.getContentResolver().query(Media.EXTERNAL_CONTENT_URI, columns, null, null, null);
photoIndex = cursor.getColumnIndexOrThrow(Media.DATA);
//titleIndex = cursor.getColumnIndexOrThrow(Media.TITLE);
nameIndex = cursor.getColumnIndexOrThrow(Media.DISPLAY_NAME);
Log.v("HERE First:", "First Debug");
//显示第一张图片,但是首先要判断一下,Cursor是否有值
if(cursor.moveToFirst()){
showImage();
}
}
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(cursor.moveToNext()){
showImage();
}
}
};
/**
* 显示图像信息
*/
private void showImage(){
photoPath = cursor.getString(photoIndex); //这里获取到的就是图片存储的位置信息
//这里怎样获取图片呢?看decodeBitmap
Log.v("Photo Path:", photoPath);
currPhoto = decodeBitmap(photoPath);
photoView.setImageBitmap(currPhoto);
nameView.setText(cursor.getString(nameIndex));
}
/**
* 从path中获取图片信息
* @param path
* @return
*/
private Bitmap decodeBitmap(String path){
BitmapFactory.Options op = new BitmapFactory.Options();
op.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeFile(path, op); //获取尺寸信息
//获取比例大小
int wRatio = (int)Math.ceil(op.outWidth/DISPLAY_WIDTH);
int hRatio = (int)Math.ceil(op.outHeight/DISPLAY_HEIGHT);
//如果超出指定大小,则缩小相应的比例
if(wRatio > 1 && hRatio > 1){
if(wRatio > hRatio){
op.inSampleSize = wRatio;
}else{
op.inSampleSize = hRatio;
}
}
op.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeFile(path, op);
return bmp;
}
}
Android自带的Camera应用虽然可以满足大多数情景,但是其灵活性上还有不足。但是Android允许我们定制自己的Camera。
在Android的hardware包中有一个Camera类。这个类就是获取Camera服务的,可以定制Camera等。
可以通过open()方法获取其实例。在使用这个类是需要在AndroidManifest.xml文件中加入相应的权限和特性
如: <uses-permission android:name = "android.permission.CAMERA" />
<uses-feature android:name = "android.hardware.camera" />
<uses-feature android:name = "android.hardware.camera.autofocus" /> 等。
package demo.camera;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.LinearLayout;
/**
* Android自带的Camera应用程序可以完成很多功能。但是当其不能满足我们需要的时候
* 我们可以定制自己的Camera。Android提供了Camera类来辅助我们实现自己的Camera。
* 这个例子就来定义一个自己的Camera
* 首先,在Manifest中需要引入权限<uses-permission android:name="android:permission.CAMERA"/>
* 我们需要用来存放取景器的容器,这个容器就是SurfaceView。
* 使用SurfaceView的同时,我们还需要使用到SurfaceHolder,SurfaceHolder相当于一个监听器,可以监听
* Surface上的变化,通过其内部类CallBack来实现。
* 为了可以获取图片,我们需要使用Camera的takePicture方法同时我们需要实现Camera.PictureCallBack类,实现onPictureTaken方法
* @author Administrator
*
*/
public class MyCamera extends Activity implements SurfaceHolder.Callback,Camera.PictureCallback{
public static final int MAX_WIDTH = 200;
public static final int MAX_HEIGHT = 200;
private SurfaceView surfaceView;
private Camera camera; //这个是hardare的Camera对象
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.camera);
surfaceView = (SurfaceView)this.findViewById(R.id.myCameraView);
surfaceView.setFocusable(true);
surfaceView.setFocusableInTouchMode(true);
surfaceView.setClickable(true);
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
camera.takePicture(null, null, null, MyCamera.this);
}
});
//SurfaceView中的getHolder方法可以获取到一个SurfaceHolder实例
SurfaceHolder holder = surfaceView.getHolder();
//为了实现照片预览功能,需要将SurfaceHolder的类型设置为PUSH
//这样,画图缓存就由Camera类来管理,画图缓存是独立于Surface的
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 当Surface被创建的时候,该方法被调用,可以在这里实例化Camera对象
//同时可以对Camera进行定制
camera = Camera.open(); //获取Camera实例
/**
* Camera对象中含有一个内部类Camera.Parameters.该类可以对Camera的特性进行定制
* 在Parameters中设置完成后,需要调用Camera.setParameters()方法,相应的设置才会生效
* 由于不同的设备,Camera的特性是不同的,所以在设置时,需要首先判断设备对应的特性,再加以设置
* 比如在调用setEffects之前最好先调用getSupportedColorEffects。如果设备不支持颜色特性,那么该方法将
* 返回一个null
*/
try {
Camera.Parameters param = camera.getParameters();
if(this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){
//如果是竖屏
param.set("orientation", "portrait");
//在2.2以上可以使用
//camera.setDisplayOrientation(90);
}else{
param.set("orientation", "landscape");
//在2.2以上可以使用
//camera.setDisplayOrientation(0);
}
//首先获取系统设备支持的所有颜色特效,有复合我们的,则设置;否则不设置
List<String> colorEffects = param.getSupportedColorEffects();
Iterator<String> colorItor = colorEffects.iterator();
while(colorItor.hasNext()){
String currColor = colorItor.next();
if(currColor.equals(Camera.Parameters.EFFECT_SOLARIZE)){
param.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);
break;
}
}
//设置完成需要再次调用setParameter方法才能生效
camera.setParameters(param);
camera.setPreviewDisplay(holder);
/**
* 在显示了预览后,我们有时候希望限制预览的Size
* 我们并不是自己指定一个SIze而是指定一个Size,然后
* 获取系统支持的SIZE,然后选择一个比指定SIZE小且最接近所指定SIZE的一个
* Camera.Size对象就是该SIZE。
*
*/
int bestWidth = 0;
int bestHeight = 0;
List<Camera.Size> sizeList = param.getSupportedPreviewSizes();
//如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择
if(sizeList.size() > 1){
Iterator<Camera.Size> itor = sizeList.iterator();
while(itor.hasNext()){
Camera.Size cur = itor.next();
if(cur.width > bestWidth && cur.height>bestHeight && cur.width <MAX_WIDTH && cur.height < MAX_HEIGHT){
bestWidth = cur.width;
bestHeight = cur.height;
}
}
if(bestWidth != 0 && bestHeight != 0){
param.setPreviewSize(bestWidth, bestHeight);
//这里改变了SIze后,我们还要告诉SurfaceView,否则,Surface将不会改变大小,进入Camera的图像将质量很差
surfaceView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth, bestHeight));
}
}
camera.setParameters(param);
} catch (Exception e) {
// 如果出现异常,则释放Camera对象
camera.release();
}
//启动预览功能
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 当Surface被销毁的时候,该方法被调用
//在这里需要释放Camera资源
camera.stopPreview();
camera.release();
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// data是一个原始的JPEG图像数据,
//在这里我们可以存储图片,很显然可以采用MediaStore
//注意保存图片后,再次调用startPreview()回到预览
Uri imageUri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
try {
OutputStream os = this.getContentResolver().openOutputStream(imageUri);
os.write(data);
os.flush();
os.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
camera.startPreview();
}
}
package demo.camera;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.List;
import android.app.Activity;
import android.content.ContentValues;
import android.content.res.Configuration;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.LinearLayout;
/**
* Android自带的Camera应用程序可以完成很多功能。但是当其不能满足我们需要的时候
* 我们可以定制自己的Camera。Android提供了Camera类来辅助我们实现自己的Camera。
* 这个例子就来定义一个自己的Camera
* 首先,在Manifest中需要引入权限<uses-permission android:name="android:permission.CAMERA"/>
* 我们需要用来存放取景器的容器,这个容器就是SurfaceView。
* 使用SurfaceView的同时,我们还需要使用到SurfaceHolder,SurfaceHolder相当于一个监听器,可以监听
* Surface上的变化,通过其内部类CallBack来实现。
* 为了可以获取图片,我们需要使用Camera的takePicture方法同时我们需要实现Camera.PictureCallBack类,实现onPictureTaken方法
* @author Administrator
*
*/
public class MyCamera extends Activity implements SurfaceHolder.Callback,Camera.PictureCallback{
public static final int MAX_WIDTH = 200;
public static final int MAX_HEIGHT = 200;
private SurfaceView surfaceView;
private Camera camera; //这个是hardare的Camera对象
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.camera);
surfaceView = (SurfaceView)this.findViewById(R.id.myCameraView);
surfaceView.setFocusable(true);
surfaceView.setFocusableInTouchMode(true);
surfaceView.setClickable(true);
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
camera.takePicture(null, null, null, MyCamera.this);
}
});
//SurfaceView中的getHolder方法可以获取到一个SurfaceHolder实例
SurfaceHolder holder = surfaceView.getHolder();
//为了实现照片预览功能,需要将SurfaceHolder的类型设置为PUSH
//这样,画图缓存就由Camera类来管理,画图缓存是独立于Surface的
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(this);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// 当Surface被创建的时候,该方法被调用,可以在这里实例化Camera对象
//同时可以对Camera进行定制
camera = Camera.open(); //获取Camera实例
/**
* Camera对象中含有一个内部类Camera.Parameters.该类可以对Camera的特性进行定制
* 在Parameters中设置完成后,需要调用Camera.setParameters()方法,相应的设置才会生效
* 由于不同的设备,Camera的特性是不同的,所以在设置时,需要首先判断设备对应的特性,再加以设置
* 比如在调用setEffects之前最好先调用getSupportedColorEffects。如果设备不支持颜色特性,那么该方法将
* 返回一个null
*/
try {
Camera.Parameters param = camera.getParameters();
if(this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){
//如果是竖屏
param.set("orientation", "portrait");
//在2.2以上可以使用
//camera.setDisplayOrientation(90);
}else{
param.set("orientation", "landscape");
//在2.2以上可以使用
//camera.setDisplayOrientation(0);
}
//首先获取系统设备支持的所有颜色特效,有复合我们的,则设置;否则不设置
List<String> colorEffects = param.getSupportedColorEffects();
Iterator<String> colorItor = colorEffects.iterator();
while(colorItor.hasNext()){
String currColor = colorItor.next();
if(currColor.equals(Camera.Parameters.EFFECT_SOLARIZE)){
param.setColorEffect(Camera.Parameters.EFFECT_SOLARIZE);
break;
}
}
//设置完成需要再次调用setParameter方法才能生效
camera.setParameters(param);
camera.setPreviewDisplay(holder);
/**
* 在显示了预览后,我们有时候希望限制预览的Size
* 我们并不是自己指定一个SIze而是指定一个Size,然后
* 获取系统支持的SIZE,然后选择一个比指定SIZE小且最接近所指定SIZE的一个
* Camera.Size对象就是该SIZE。
*
*/
int bestWidth = 0;
int bestHeight = 0;
List<Camera.Size> sizeList = param.getSupportedPreviewSizes();
//如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择
if(sizeList.size() > 1){
Iterator<Camera.Size> itor = sizeList.iterator();
while(itor.hasNext()){
Camera.Size cur = itor.next();
if(cur.width > bestWidth && cur.height>bestHeight && cur.width <MAX_WIDTH && cur.height < MAX_HEIGHT){
bestWidth = cur.width;
bestHeight = cur.height;
}
}
if(bestWidth != 0 && bestHeight != 0){
param.setPreviewSize(bestWidth, bestHeight);
//这里改变了SIze后,我们还要告诉SurfaceView,否则,Surface将不会改变大小,进入Camera的图像将质量很差
surfaceView.setLayoutParams(new LinearLayout.LayoutParams(bestWidth, bestHeight));
}
}
camera.setParameters(param);
} catch (Exception e) {
// 如果出现异常,则释放Camera对象
camera.release();
}
//启动预览功能
camera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// 当Surface被销毁的时候,该方法被调用
//在这里需要释放Camera资源
camera.stopPreview();
camera.release();
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// data是一个原始的JPEG图像数据,
//在这里我们可以存储图片,很显然可以采用MediaStore
//注意保存图片后,再次调用startPreview()回到预览
Uri imageUri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
try {
OutputStream os = this.getContentResolver().openOutputStream(imageUri);
os.write(data);
os.flush();
os.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
camera.startPreview();
}
}
图像的编辑和合成
package demo.camera;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
/**
* 在Android中我们可以对图像进行编辑处理等操作
* 包括放大缩小,旋转,偏移,裁剪,以及更改亮度,饱和度等
*
* 1、首先,从SDCard中选择图片,采用Android自带的Callery应用获得
* Gallery是Android自带的图片和视频管理应用
* 使用Intent来启动Gallery应用,需要指定两个参数,一个是Action,另一个是多媒体存放的URI
* Action是一个通用的Action叫ACTION_PICK,来告诉Gallery,我们想检索数据。
* 第二个是Data,是一个URI,这里当然是MediaStore.Images.Media.EXTERNAL_CONTENT_URI
* 当在Gallery中选择了一个图片的时候,返回的Intent中的Data域就是所选图片对应的URI
*
* @author Administrator
*
*/
public class PhotoProcess extends Activity{
public static final int FIRST_PIC = 0;
public static final int SECOND_PIC = 1;
public static final int MAX_WIDTH = 240;
public static final int MAX_HEIGHT = 180;
private Button btnSelect,btnSelect2;
private ImageView srcImageView, dstImageView;
private Bitmap srcBitmap, dstBitmap;
private Uri imageUri;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.process);
this.btnSelect = (Button)this.findViewById(R.id.btn_select);
btnSelect.setOnClickListener(clickListener);
this.btnSelect2 = (Button)this.findViewById(R.id.btn_select2);
btnSelect2.setOnClickListener(clickListener2);
srcImageView = (ImageView)this.findViewById(R.id.img_src);
dstImageView = (ImageView)this.findViewById(R.id.img_dst);
}
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 启动Gallery应用
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, FIRST_PIC);
}
};
private View.OnClickListener clickListener2 = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 启动Gallery应用
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, SECOND_PIC);
}
};
public boolean onCreateOptionsMenu(Menu menu){
//super.onCreateOptionsMenu(menu);
//MenuInflater menuInflater = new MenuInflater(this);
//menuInflater.inflate(R.layout.image, menu)
menu.add(Menu.NONE,1,Menu.NONE,"复制");
menu.add(Menu.NONE,2,Menu.NONE,"变换");
menu.add(Menu.NONE,3,Menu.NONE,"亮度");
menu.add(Menu.NONE,4,Menu.NONE,"合成");
return super.onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(MenuItem item){
int id = item.getItemId();
switch(id){
case 1:
//复制一个图像
if(srcBitmap != null){
dstBitmap = getDstImage(null);//这里没有变换
dstImageView.setImageBitmap(dstBitmap);
}
break;
case 2:
//对复制后的图像进行变换
if(srcBitmap != null){
dstBitmap = transferImage();
dstImageView.setImageBitmap(dstBitmap);
}
break;
case 3:
//改变图像的色彩
if(srcBitmap != null){
dstBitmap = ajustImage();
dstImageView.setImageBitmap(dstBitmap);
}
break;
case 4:
if(srcBitmap != null && dstBitmap != null){
dstBitmap = compositeImages();
dstImageView.setImageBitmap(dstBitmap);
}
break;
}
return true;
}
/**
* 为了创建一个图像的副本,我们可以在创建一个新的空的Bitmap,然后在这个Bitmap上绘制一个Bitmap
* 这个空的Bitmap应该和已存在的Bitmap具有相同的尺寸和颜色深度
*
* 然后我们需要一个Canvas对象,一个Canvas简单说,就是一个画布,存放Bitmap,在构造时,就可以传入Bitmap对象
* 同时,Canvas中定义了很多便捷的画图方法,方便我们绘制各种图形
* 接下来,如果我们需要处理颜色和对比度,我们需要一个Paint对象,通过Paint我们可以设置画笔的各种特性。
*
* 最后,我们调用Canvas的drawBitmap就可以将原Bitmap绘制在dstBitmap上了
*
*/
private Bitmap getDstImage(Matrix matrix){
Bitmap bmp = null;
//下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
//返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了
bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//创建Canvas对象,
Canvas canvas = new Canvas(bmp);
//创建Paint对象,这里先不用
Paint paint = new Paint();
//在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了
if(matrix != null){
//如果matrix存在,则采用变换
canvas.drawBitmap(dstBitmap, matrix, paint);
}else{
canvas.drawBitmap(srcBitmap, 0, 0, paint);
}
return bmp;
}
/**
* 重载getDstImage函数,传入定制的Paint对象
* @param matrix
* @param paint
* @return
*/
private Bitmap getDstImage(Matrix matrix, Paint paint){
Bitmap bmp = null;
//下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
//返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了
bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//创建Canvas对象,
Canvas canvas = new Canvas(bmp);
//在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了
if(matrix != null){
//如果matrix存在,则采用变换
canvas.drawBitmap(dstBitmap, matrix, paint);
}else{
canvas.drawBitmap(srcBitmap, 0, 0, paint);
}
return bmp;
}
/**
* 为了放大缩小、旋转图像,我们要使用Matrix类。Matrix类是一个三维矩阵。
* 在Android屏幕中,图像的每个像素对应都是一个坐标,一个坐标由x/y/z组成
* ------------------------
* cosX -sinX translateX
* sinX cosX translateY
* 0 0 scale
* ------------------------
* 第一行的值,影响着x坐标。比如 1 0 0 =>x = 1*x + 0*y + 0*z
* 第二行的值,影响着y坐标。比如0 1 0 => y = 0*x + 1*y + 0*z
* 第三行的值,影响着z坐标。比如 0 0 1 => z = 0*x + 0*y + 1*z
*
* 我们自己计算一个矩阵然后通过Matrax.setValues设置。
* 这样,在调用canvas的drawBitmap方法时,传入matrix
*
* Matrix类并不提倡我们使用这种方式来操作变换,Matrix针对不同的变换都相应的有pre,set,post三种方法
* 可以使用。
* pre是矩阵前乘
* set是直接设置
* post是矩阵后乘
*/
private Bitmap transferImage(){
Matrix matrix = new Matrix();
matrix.setValues(new float[]{
.5f,0,0,//这里只会影响到x轴,所以,图片的长度将是原来的一半
0,1,0,
0,0,1
});
return this.getDstImage(matrix);
}
/**
* 该方法中我们将对图像的颜色,亮度,对比度等进行设置
* 需要用到ColorMatrix类。ColorMatrix类是一个四行五列的矩阵
* 每一行影响着[R,G,B,A]中的一个
* -------------------------
* a1 b1 c1 d1 e1
* a2 b2 c2 d2 e2
* a3 b3 c3 d3 e3
* a4 b4 c4 d4 e4
* -------------------------
* Rnew => a1*R+b1*G+c1*B+d1*A+e1
* Gnew => a2*R+b2*G+c2*B+d2*A+e2
* Bnew => a3*R+b3*G+c3*B+d3*A+e3
* Gnew => a4*R+b4*G+c4*B+d4*A+e4
* 其中R,G,B的值是128,A的值是0
*
* 最后将颜色的修改,通过Paint.setColorFilter应用到Paint对象中。
* 主要对于ColorMatrix,需要将其包装成ColorMatrixColorFilter对象,再传给Paint对象
*
* 同样的,ColorMatrix提供给我们相应的方法,setSaturation()就可以设置一个饱和度
*/
private Bitmap ajustImage(){
ColorMatrix cMatrix = new ColorMatrix();
// int brightIndex = -25;
// int doubleColor = 2;
// cMatrix.set(new float[]{
// doubleColor,0,0,0,brightIndex, //这里将1改为2则我们让Red的值为原来的两倍
// 0,doubleColor,0,0,brightIndex,//改变最后一列的值,我们可以不改变RGB同道颜色的基础上,改变亮度
// 0,0,doubleColor,0,brightIndex,
// 0,0,0,doubleColor,0
// });
//cMatrix.setSaturation(2.0f);//设置饱和度
cMatrix.setScale(2.0f, 2.0f, 2.0f, 2.0f);//设置颜色同道色彩缩放
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));
return this.getDstImage(null, paint);
}
/**
* 图像的合成,可以通过在同一个Canvas中绘制两张图片。
* 只是在绘制第二章图片的时候,需要给Paint指定一个变幻模式TransferMode。
* 在Android中有一个XFermode所有的变幻模式都是这个类的子类
* 我们需要用到它的一个子类PorterDuffXfermode,关于这个类,其中用到PorterDuff类
* 这个类很简单,就包含一个Enum是Mode,其中定义了一组规则,这组规则就是如何将
* 一张图像和另一种图像进行合成
* 关于图像合成有四种模式,LIGHTEN,DRAKEN,MULTIPLY,SCREEN
*/
private Bitmap compositeImages(){
Bitmap bmp = null;
//下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
Paint paint = new Paint();
Canvas canvas = new Canvas(bmp);
//首先绘制第一张图片,很简单,就是和方法中getDstImage一样
canvas.drawBitmap(srcBitmap, 0, 0, paint);
//在绘制第二张图片的时候,我们需要指定一个Xfermode
//这里采用Multiply模式,这个模式是将两张图片的对应的点的像素相乘
//,再除以255,然后以新的像素来重新绘制显示合成后的图像
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(dstBitmap, 0, 0, paint);
return bmp;
}
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
Log.v("Result OK Value:", resultCode+"");
Log.v("RequestCode Value", requestCode+"");
if(resultCode == RESULT_OK){
imageUri = data.getData();
if(requestCode == FIRST_PIC){
//在Gallery中选中一个图片时,返回来的Intent中的Data就是选择图片的Uri
srcBitmap = getSrcImage(imageUri);
srcImageView.setImageBitmap(srcBitmap);
}else if(requestCode == SECOND_PIC){
//这里处理用户选择的第二张图片
dstBitmap = getSrcImage(imageUri);
dstImageView.setImageBitmap(dstBitmap);
}
}
}
/**
* 需要加载的图片可能是大图,我们需要对其进行合适的缩小处理
* @param imageUri
*/
private Bitmap getSrcImage(Uri imageUri){
//Display display = this.getWindowManager().getDefaultDisplay();
try {
BitmapFactory.Options ops = new BitmapFactory.Options();
ops.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);
int wRatio = (int)Math.ceil(ops.outWidth/(float)MAX_WIDTH);
int hRatio = (int)Math.ceil(ops.outHeight/(float)MAX_HEIGHT);
if(wRatio > 1 && hRatio > 1){
if(wRatio > hRatio){
ops.inSampleSize = wRatio;
}else{
ops.inSampleSize = hRatio;
}
}
ops.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);
return bmp;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(this.getClass().getName(), e.getMessage());
}
return null;
}
}
package demo.camera;
import java.io.FileNotFoundException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
/**
* 在Android中我们可以对图像进行编辑处理等操作
* 包括放大缩小,旋转,偏移,裁剪,以及更改亮度,饱和度等
*
* 1、首先,从SDCard中选择图片,采用Android自带的Callery应用获得
* Gallery是Android自带的图片和视频管理应用
* 使用Intent来启动Gallery应用,需要指定两个参数,一个是Action,另一个是多媒体存放的URI
* Action是一个通用的Action叫ACTION_PICK,来告诉Gallery,我们想检索数据。
* 第二个是Data,是一个URI,这里当然是MediaStore.Images.Media.EXTERNAL_CONTENT_URI
* 当在Gallery中选择了一个图片的时候,返回的Intent中的Data域就是所选图片对应的URI
*
* @author Administrator
*
*/
public class PhotoProcess extends Activity{
public static final int FIRST_PIC = 0;
public static final int SECOND_PIC = 1;
public static final int MAX_WIDTH = 240;
public static final int MAX_HEIGHT = 180;
private Button btnSelect,btnSelect2;
private ImageView srcImageView, dstImageView;
private Bitmap srcBitmap, dstBitmap;
private Uri imageUri;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.process);
this.btnSelect = (Button)this.findViewById(R.id.btn_select);
btnSelect.setOnClickListener(clickListener);
this.btnSelect2 = (Button)this.findViewById(R.id.btn_select2);
btnSelect2.setOnClickListener(clickListener2);
srcImageView = (ImageView)this.findViewById(R.id.img_src);
dstImageView = (ImageView)this.findViewById(R.id.img_dst);
}
private View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 启动Gallery应用
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, FIRST_PIC);
}
};
private View.OnClickListener clickListener2 = new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// 启动Gallery应用
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, SECOND_PIC);
}
};
public boolean onCreateOptionsMenu(Menu menu){
//super.onCreateOptionsMenu(menu);
//MenuInflater menuInflater = new MenuInflater(this);
//menuInflater.inflate(R.layout.image, menu)
menu.add(Menu.NONE,1,Menu.NONE,"复制");
menu.add(Menu.NONE,2,Menu.NONE,"变换");
menu.add(Menu.NONE,3,Menu.NONE,"亮度");
menu.add(Menu.NONE,4,Menu.NONE,"合成");
return super.onCreateOptionsMenu(menu);
}
public boolean onOptionsItemSelected(MenuItem item){
int id = item.getItemId();
switch(id){
case 1:
//复制一个图像
if(srcBitmap != null){
dstBitmap = getDstImage(null);//这里没有变换
dstImageView.setImageBitmap(dstBitmap);
}
break;
case 2:
//对复制后的图像进行变换
if(srcBitmap != null){
dstBitmap = transferImage();
dstImageView.setImageBitmap(dstBitmap);
}
break;
case 3:
//改变图像的色彩
if(srcBitmap != null){
dstBitmap = ajustImage();
dstImageView.setImageBitmap(dstBitmap);
}
break;
case 4:
if(srcBitmap != null && dstBitmap != null){
dstBitmap = compositeImages();
dstImageView.setImageBitmap(dstBitmap);
}
break;
}
return true;
}
/**
* 为了创建一个图像的副本,我们可以在创建一个新的空的Bitmap,然后在这个Bitmap上绘制一个Bitmap
* 这个空的Bitmap应该和已存在的Bitmap具有相同的尺寸和颜色深度
*
* 然后我们需要一个Canvas对象,一个Canvas简单说,就是一个画布,存放Bitmap,在构造时,就可以传入Bitmap对象
* 同时,Canvas中定义了很多便捷的画图方法,方便我们绘制各种图形
* 接下来,如果我们需要处理颜色和对比度,我们需要一个Paint对象,通过Paint我们可以设置画笔的各种特性。
*
* 最后,我们调用Canvas的drawBitmap就可以将原Bitmap绘制在dstBitmap上了
*
*/
private Bitmap getDstImage(Matrix matrix){
Bitmap bmp = null;
//下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
//返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了
bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//创建Canvas对象,
Canvas canvas = new Canvas(bmp);
//创建Paint对象,这里先不用
Paint paint = new Paint();
//在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了
if(matrix != null){
//如果matrix存在,则采用变换
canvas.drawBitmap(dstBitmap, matrix, paint);
}else{
canvas.drawBitmap(srcBitmap, 0, 0, paint);
}
return bmp;
}
/**
* 重载getDstImage函数,传入定制的Paint对象
* @param matrix
* @param paint
* @return
*/
private Bitmap getDstImage(Matrix matrix, Paint paint){
Bitmap bmp = null;
//下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
//返回的是一个可以改变的Bitmap对象,这样我们后面就可以对其进行变换和颜色调整等操作了
bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
//创建Canvas对象,
Canvas canvas = new Canvas(bmp);
//在Canvas上绘制一个已经存在的Bitmap。这样,dstBitmap就和srcBitmap一摸一样了
if(matrix != null){
//如果matrix存在,则采用变换
canvas.drawBitmap(dstBitmap, matrix, paint);
}else{
canvas.drawBitmap(srcBitmap, 0, 0, paint);
}
return bmp;
}
/**
* 为了放大缩小、旋转图像,我们要使用Matrix类。Matrix类是一个三维矩阵。
* 在Android屏幕中,图像的每个像素对应都是一个坐标,一个坐标由x/y/z组成
* ------------------------
* cosX -sinX translateX
* sinX cosX translateY
* 0 0 scale
* ------------------------
* 第一行的值,影响着x坐标。比如 1 0 0 =>x = 1*x + 0*y + 0*z
* 第二行的值,影响着y坐标。比如0 1 0 => y = 0*x + 1*y + 0*z
* 第三行的值,影响着z坐标。比如 0 0 1 => z = 0*x + 0*y + 1*z
*
* 我们自己计算一个矩阵然后通过Matrax.setValues设置。
* 这样,在调用canvas的drawBitmap方法时,传入matrix
*
* Matrix类并不提倡我们使用这种方式来操作变换,Matrix针对不同的变换都相应的有pre,set,post三种方法
* 可以使用。
* pre是矩阵前乘
* set是直接设置
* post是矩阵后乘
*/
private Bitmap transferImage(){
Matrix matrix = new Matrix();
matrix.setValues(new float[]{
.5f,0,0,//这里只会影响到x轴,所以,图片的长度将是原来的一半
0,1,0,
0,0,1
});
return this.getDstImage(matrix);
}
/**
* 该方法中我们将对图像的颜色,亮度,对比度等进行设置
* 需要用到ColorMatrix类。ColorMatrix类是一个四行五列的矩阵
* 每一行影响着[R,G,B,A]中的一个
* -------------------------
* a1 b1 c1 d1 e1
* a2 b2 c2 d2 e2
* a3 b3 c3 d3 e3
* a4 b4 c4 d4 e4
* -------------------------
* Rnew => a1*R+b1*G+c1*B+d1*A+e1
* Gnew => a2*R+b2*G+c2*B+d2*A+e2
* Bnew => a3*R+b3*G+c3*B+d3*A+e3
* Gnew => a4*R+b4*G+c4*B+d4*A+e4
* 其中R,G,B的值是128,A的值是0
*
* 最后将颜色的修改,通过Paint.setColorFilter应用到Paint对象中。
* 主要对于ColorMatrix,需要将其包装成ColorMatrixColorFilter对象,再传给Paint对象
*
* 同样的,ColorMatrix提供给我们相应的方法,setSaturation()就可以设置一个饱和度
*/
private Bitmap ajustImage(){
ColorMatrix cMatrix = new ColorMatrix();
// int brightIndex = -25;
// int doubleColor = 2;
// cMatrix.set(new float[]{
// doubleColor,0,0,0,brightIndex, //这里将1改为2则我们让Red的值为原来的两倍
// 0,doubleColor,0,0,brightIndex,//改变最后一列的值,我们可以不改变RGB同道颜色的基础上,改变亮度
// 0,0,doubleColor,0,brightIndex,
// 0,0,0,doubleColor,0
// });
//cMatrix.setSaturation(2.0f);//设置饱和度
cMatrix.setScale(2.0f, 2.0f, 2.0f, 2.0f);//设置颜色同道色彩缩放
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));
return this.getDstImage(null, paint);
}
/**
* 图像的合成,可以通过在同一个Canvas中绘制两张图片。
* 只是在绘制第二章图片的时候,需要给Paint指定一个变幻模式TransferMode。
* 在Android中有一个XFermode所有的变幻模式都是这个类的子类
* 我们需要用到它的一个子类PorterDuffXfermode,关于这个类,其中用到PorterDuff类
* 这个类很简单,就包含一个Enum是Mode,其中定义了一组规则,这组规则就是如何将
* 一张图像和另一种图像进行合成
* 关于图像合成有四种模式,LIGHTEN,DRAKEN,MULTIPLY,SCREEN
*/
private Bitmap compositeImages(){
Bitmap bmp = null;
//下面这个Bitmap中创建的函数就可以创建一个空的Bitmap
bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());
Paint paint = new Paint();
Canvas canvas = new Canvas(bmp);
//首先绘制第一张图片,很简单,就是和方法中getDstImage一样
canvas.drawBitmap(srcBitmap, 0, 0, paint);
//在绘制第二张图片的时候,我们需要指定一个Xfermode
//这里采用Multiply模式,这个模式是将两张图片的对应的点的像素相乘
//,再除以255,然后以新的像素来重新绘制显示合成后的图像
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawBitmap(dstBitmap, 0, 0, paint);
return bmp;
}
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
Log.v("Result OK Value:", resultCode+"");
Log.v("RequestCode Value", requestCode+"");
if(resultCode == RESULT_OK){
imageUri = data.getData();
if(requestCode == FIRST_PIC){
//在Gallery中选中一个图片时,返回来的Intent中的Data就是选择图片的Uri
srcBitmap = getSrcImage(imageUri);
srcImageView.setImageBitmap(srcBitmap);
}else if(requestCode == SECOND_PIC){
//这里处理用户选择的第二张图片
dstBitmap = getSrcImage(imageUri);
dstImageView.setImageBitmap(dstBitmap);
}
}
}
/**
* 需要加载的图片可能是大图,我们需要对其进行合适的缩小处理
* @param imageUri
*/
private Bitmap getSrcImage(Uri imageUri){
//Display display = this.getWindowManager().getDefaultDisplay();
try {
BitmapFactory.Options ops = new BitmapFactory.Options();
ops.inJustDecodeBounds = true;
Bitmap bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);
int wRatio = (int)Math.ceil(ops.outWidth/(float)MAX_WIDTH);
int hRatio = (int)Math.ceil(ops.outHeight/(float)MAX_HEIGHT);
if(wRatio > 1 && hRatio > 1){
if(wRatio > hRatio){
ops.inSampleSize = wRatio;
}else{
ops.inSampleSize = hRatio;
}
}
ops.inJustDecodeBounds = false;
bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);
return bmp;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.e(this.getClass().getName(), e.getMessage());
}
return null;
}
}
调用Android自带的播放器播放audio
Android有其自带的播放器,我们可以使用隐式Intent来调用它:通过传入一个Action为ACTION_VIEW同时,指定Data为所要播放的Audio的Uri对象,并指定格式信息,则我们就可以调用播放器来播放该Audio了。
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri, MimeType);
startActivity(intent);
本文我们需要访问MediaStore,来获取所有Audio信息,我们首先将获取所有的Album,然后当用户点击某个Album时,显示该Album下所有的Audio,然后当用户点击某个Audio时,调用系统自带的播放器播放该Audio。
package demo.camera;
import java.io.File;
import org.apache.http.client.utils.URIUtils;
import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Audio.Albums;
import android.view.View;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
/**
* 本示例演示如何利用Android自带的Music来播放程序
* 和Camera一样,可以通过Intent来启动它。
* 我们需要指定一个ACTION_VIEW的Action
* 同时一个Uri来指定我们要播放文件的路径
* 最后指定一个MIME类型,指定所要播放的文件类型
* 每种文件类型对应的都有一个MIME,他一般是类似于audio/mp3格式
* 前部分是一个较大的类型,后面是更具体的类型
*
* 同样的,对于Audio类型的多媒体,系统存储在MediaStore.Audio中
* 包括Media,Album,Genre等信息体
*
* 本文将以列表的形式列出所有的Album信息,供用户选择
* 当用户选择某个Album时,系统将打开这个ALbum下的所有Audio
* @author Administrator
*
*/
public class AudioDemo extends ListActivity {
private Button btnMusic;
private boolean isAlbum = true; //true时,说明当前列表的内容是Album,false时,说明是Media
private Cursor cursor; //游标对象,
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.audio);
btnMusic = (Button)this.findViewById(R.id.btn_music);
btnMusic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Intent intent = new Intent(Intent.ACTION_VIEW);
// //这里我们先从SDCard文件中获取指定文件的URi
// File sdcard = Environment.getExternalStorageDirectory(); //这个是获取SDCard路径
// File audioFile = new File(sdcard.getPath()+"/music/tt.mp3");
// //然后需要获取该文件的Uri
// Uri audioUri = Uri.fromFile(audioFile);
// //然后指定Uri和MIME
// intent.setDataAndType(audioUri, "audio/mp3");
// startActivity(intent);
//获取Album列表
getAlbums();
isAlbum = true;
}
});
}
public void onListItemClick(ListView l, View v, int position, long id){
//判断当前是哪个列表
if(isAlbum){
//如果是Album,当用户点击某一个时,获取该Album下的所有media
//l.getChildAt(position);
if(cursor.moveToPosition(position)){
getMedias(cursor.getInt(cursor.getColumnIndexOrThrow(Albums._ID)));
isAlbum = false;
}
}else{
//如果是Media,则当用户点击某一个时,则播放该Media
//调用系统自带的MediaPlayer来播放
if(cursor.moveToPosition(position)){
String mediaUri = cursor.getString(cursor.getColumnIndexOrThrow(Audio.Media.DATA));
String type = cursor.getString(cursor.getColumnIndexOrThrow(Audio.Media.MIME_TYPE));
Uri data = Uri.fromFile(new File(mediaUri));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(data, type);
startActivity(intent);
}
}
//super.onListItemClick(l, v, position, id);
}
//获取所有Albums
public void getAlbums(){
String[] columns = new String[]{
Albums._ID,
Albums.ALBUM
};
String[] from = new String[]{
Albums.ALBUM
};
int[] to = new int[]{
android.R.id.text1
};
cursor = this.managedQuery(Albums.EXTERNAL_CONTENT_URI, columns, null, null, Albums.DEFAULT_SORT_ORDER);
CursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, from, to);
this.setListAdapter(adapter);
//this.isAlbum = true;
}
//获取某个Albums下对应的medias
public void getMedias(int albumId){
String[] columns = new String[]{
Audio.Media._ID,
Audio.Media.DATA,
Audio.Media.DISPLAY_NAME,
Audio.Media.MIME_TYPE
};
String selection = Audio.Media.ALBUM_ID + "=?";
String[] selectionArgs = new String[]{
albumId+""
};
String[] from = new String[]{
Audio.Media.DISPLAY_NAME
};
int[] to = new int[]{
android.R.id.text1
};
cursor = this.managedQuery(Audio.Media.EXTERNAL_CONTENT_URI, columns, selection, selectionArgs, Audio.Media.TITLE);
CursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1,cursor,from,to);
this.setListAdapter(adapter);
}
}
package demo.camera;
import java.io.File;
import org.apache.http.client.utils.URIUtils;
import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio;
import android.provider.MediaStore.Audio.Albums;
import android.view.View;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
/**
* 本示例演示如何利用Android自带的Music来播放程序
* 和Camera一样,可以通过Intent来启动它。
* 我们需要指定一个ACTION_VIEW的Action
* 同时一个Uri来指定我们要播放文件的路径
* 最后指定一个MIME类型,指定所要播放的文件类型
* 每种文件类型对应的都有一个MIME,他一般是类似于audio/mp3格式
* 前部分是一个较大的类型,后面是更具体的类型
*
* 同样的,对于Audio类型的多媒体,系统存储在MediaStore.Audio中
* 包括Media,Album,Genre等信息体
*
* 本文将以列表的形式列出所有的Album信息,供用户选择
* 当用户选择某个Album时,系统将打开这个ALbum下的所有Audio
* @author Administrator
*
*/
public class AudioDemo extends ListActivity {
private Button btnMusic;
private boolean isAlbum = true; //true时,说明当前列表的内容是Album,false时,说明是Media
private Cursor cursor; //游标对象,
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(R.layout.audio);
btnMusic = (Button)this.findViewById(R.id.btn_music);
btnMusic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Intent intent = new Intent(Intent.ACTION_VIEW);
// //这里我们先从SDCard文件中获取指定文件的URi
// File sdcard = Environment.getExternalStorageDirectory(); //这个是获取SDCard路径
// File audioFile = new File(sdcard.getPath()+"/music/tt.mp3");
// //然后需要获取该文件的Uri
// Uri audioUri = Uri.fromFile(audioFile);
// //然后指定Uri和MIME
// intent.setDataAndType(audioUri, "audio/mp3");
// startActivity(intent);
//获取Album列表
getAlbums();
isAlbum = true;
}
});
}
public void onListItemClick(ListView l, View v, int position, long id){
//判断当前是哪个列表
if(isAlbum){
//如果是Album,当用户点击某一个时,获取该Album下的所有media
//l.getChildAt(position);
if(cursor.moveToPosition(position)){
getMedias(cursor.getInt(cursor.getColumnIndexOrThrow(Albums._ID)));
isAlbum = false;
}
}else{
//如果是Media,则当用户点击某一个时,则播放该Media
//调用系统自带的MediaPlayer来播放
if(cursor.moveToPosition(position)){
String mediaUri = cursor.getString(cursor.getColumnIndexOrThrow(Audio.Media.DATA));
String type = cursor.getString(cursor.getColumnIndexOrThrow(Audio.Media.MIME_TYPE));
Uri data = Uri.fromFile(new File(mediaUri));
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(data, type);
startActivity(intent);
}
}
//super.onListItemClick(l, v, position, id);
}
//获取所有Albums
public void getAlbums(){
String[] columns = new String[]{
Albums._ID,
Albums.ALBUM
};
String[] from = new String[]{
Albums.ALBUM
};
int[] to = new int[]{
android.R.id.text1
};
cursor = this.managedQuery(Albums.EXTERNAL_CONTENT_URI, columns, null, null, Albums.DEFAULT_SORT_ORDER);
CursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, cursor, from, to);
this.setListAdapter(adapter);
//this.isAlbum = true;
}
//获取某个Albums下对应的medias
public void getMedias(int albumId){
String[] columns = new String[]{
Audio.Media._ID,
Audio.Media.DATA,
Audio.Media.DISPLAY_NAME,
Audio.Media.MIME_TYPE
};
String selection = Audio.Media.ALBUM_ID + "=?";
String[] selectionArgs = new String[]{
albumId+""
};
String[] from = new String[]{
Audio.Media.DISPLAY_NAME
};
int[] to = new int[]{
android.R.id.text1
};
cursor = this.managedQuery(Audio.Media.EXTERNAL_CONTENT_URI, columns, selection, selectionArgs, Audio.Media.TITLE);
CursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1,cursor,from,to);
this.setListAdapter(adapter);
}
}
利用Service实现背景音乐的播放
利用Service实现背景音乐的播放
Activity类
package demo.camera;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
/**
* 演示Activity如何利用Service来完成后台Audio的播放功能
* 同时如何将Service和Activity进行绑定
* @author Administrator
*
*/
public class BackgroundAudioDemo extends Activity {
private AudioService audioService;
//使用ServiceConnection来监听Service状态的变化
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
audioService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//这里我们实例化audioService,通过binder来实现
audioService = ((AudioService.AudioBinder)binder).getService();
}
};
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.back_audio);
}
public void onClick(View v){
int id = v.getId();
Intent intent = new Intent();
intent.setClass(this, AudioService.class);
if(id == R.id.btn_start){
//启动Service,然后绑定该Service,这样我们可以在同时销毁该Activity,看看歌曲是否还在播放
startService(intent);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
finish();
}else if(id == R.id.btn_end){
//结束Service
unbindService(conn);
stopService(intent);
finish();
}else if(id == R.id.btn_fun){
audioService.haveFun();
}
}
}
package demo.camera;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
/**
* 演示Activity如何利用Service来完成后台Audio的播放功能
* 同时如何将Service和Activity进行绑定
* @author Administrator
*
*/
public class BackgroundAudioDemo extends Activity {
private AudioService audioService;
//使用ServiceConnection来监听Service状态的变化
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
audioService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
//这里我们实例化audioService,通过binder来实现
audioService = ((AudioService.AudioBinder)binder).getService();
}
};
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.back_audio);
}
public void onClick(View v){
int id = v.getId();
Intent intent = new Intent();
intent.setClass(this, AudioService.class);
if(id == R.id.btn_start){
//启动Service,然后绑定该Service,这样我们可以在同时销毁该Activity,看看歌曲是否还在播放
startService(intent);
bindService(intent, conn, Context.BIND_AUTO_CREATE);
finish();
}else if(id == R.id.btn_end){
//结束Service
unbindService(conn);
stopService(intent);
finish();
}else if(id == R.id.btn_fun){
audioService.haveFun();
}
}
}
Service类
package demo.camera;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.widget.MediaController.MediaPlayerControl;
/**
* 为了可以使得在后台播放音乐,我们需要Service
* Service就是用来在后台完成一些不需要和用户交互的动作
* @author Administrator
*
*/
public class AudioService extends Service implements MediaPlayer.OnCompletionListener{
MediaPlayer player;
private final IBinder binder = new AudioBinder();
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return binder;
}
/**
* 当Audio播放完的时候触发该动作
*/
@Override
public void onCompletion(MediaPlayer player) {
// TODO Auto-generated method stub
stopSelf();//结束了,则结束Service
}
//在这里我们需要实例化MediaPlayer对象
public void onCreate(){
super.onCreate();
//我们从raw文件夹中获取一个应用自带的mp3文件
player = MediaPlayer.create(this, R.raw.tt);
player.setOnCompletionListener(this);
}
/**
* 该方法在SDK2.0才开始有的,替代原来的onStart方法
*/
public int onStartCommand(Intent intent, int flags, int startId){
if(!player.isPlaying()){
player.start();
}
return START_STICKY;
}
public void onDestroy(){
//super.onDestroy();
if(player.isPlaying()){
player.stop();
}
player.release();
}
//为了和Activity交互,我们需要定义一个Binder对象
class AudioBinder extends Binder{
//返回Service对象
AudioService getService(){
return AudioService.this;
}
}
//后退播放进度
public void haveFun(){
if(player.isPlaying() && player.getCurrentPosition()>2500){
player.seekTo(player.getCurrentPosition()-2500);
}
}
}
package demo.camera;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.widget.MediaController.MediaPlayerControl;
/**
* 为了可以使得在后台播放音乐,我们需要Service
* Service就是用来在后台完成一些不需要和用户交互的动作
* @author Administrator
*
*/
public class AudioService extends Service implements MediaPlayer.OnCompletionListener{
MediaPlayer player;
private final IBinder binder = new AudioBinder();
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return binder;
}
/**
* 当Audio播放完的时候触发该动作
*/
@Override
public void onCompletion(MediaPlayer player) {
// TODO Auto-generated method stub
stopSelf();//结束了,则结束Service
}
//在这里我们需要实例化MediaPlayer对象
public void onCreate(){
super.onCreate();
//我们从raw文件夹中获取一个应用自带的mp3文件
player = MediaPlayer.create(this, R.raw.tt);
player.setOnCompletionListener(this);
}
/**
* 该方法在SDK2.0才开始有的,替代原来的onStart方法
*/
public int onStartCommand(Intent intent, int flags, int startId){
if(!player.isPlaying()){
player.start();
}
return START_STICKY;
}
public void onDestroy(){
//super.onDestroy();
if(player.isPlaying()){
player.stop();
}
player.release();
}
//为了和Activity交互,我们需要定义一个Binder对象
class AudioBinder extends Binder{
//返回Service对象
AudioService getService(){
return AudioService.this;
}
}
//后退播放进度
public void haveFun(){
if(player.isPlaying() && player.getCurrentPosition()>2500){
player.seekTo(player.getCurrentPosition()-2500);
}
}
}
在清单文件AndroidManifest.xml中配置Service
<service
android:name=".AudioService" />