当前位置: 网学 > 编程文档 > Android > 正文

android例子精华版

来源:Http://myeducs.cn 联系QQ:点击这里给我发消息 作者: myeducs.cn 发布时间: 13/03/17

【网学网提醒】:网学会员为大家收集整理了android例子精华版提供大家参考,希望对大家有所帮助!


    Android提高第一篇之MediaPlayer
    本文介绍MediaPlayer的使用。MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView比MediaPlayer简单易用,但定制性不如用MediaPlayer,要视情况选择了。MediaPlayer播放音频比较简单,但是要播放视频就需要SurfaceView。SurfaceView比普通的自定义View更有绘图上的优势,它支持完全的OpenGLES库。
        android:layout_width="fill_parent"android:layout_height="fill_parent"
    xmlns:android="schemas.android/apk/res/android"
    android:orientation="vertical">
        android:layout_width="fill_parent">
        android:layout_width="wrap_content"android:layout_height="wrap_content">
        android:layout_height="wrap_content"android:text="播放音频">
        android:layout_height="wrap_content"android:text="停止播放">
    
        android:layout_width="fill_parent">
        android:layout_width="fill_parent"android:layout_height="250px">
        android:layout_width="wrap_content"android:layout_height="wrap_content">
        android:layout_height="wrap_content"android:id="@+id/Button03"
    android:text="播放视频">
        android:layout_height="wrap_content"android:text="停止播放"android:id="@+id/Button04">
    packagecom.testMedia;
    importjava.io.IOException;
    importjava.util.Timer;
    importjava.util.TimerTask;
    importandroid.app.Activity;
    importandroid.media.AudioManager;
    importandroid.media.MediaPlayer;
    importandroid.os.Bundle;
    importandroid.view.SurfaceHolder;
    importandroid.view.SurfaceView;
    importandroid.view.View;
    importandroid.widget.Button;
    importandroid.widget.SeekBar;
    importandroid.widget.Toast;
    publicclasstestMediaextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    privateSeekBarskb_audio=null;
    privateButtonbtn_start_audio=null;
    privateButtonbtn_stop_audio=null;
    privateSeekBarskb_video=null;
    privateButtonbtn_start_video=null;
    privateButtonbtn_stop_video=null;
    privateSurfaceViewsurfaceView;
    
    privateSurfaceHoldersurfaceHolder;
    
    privateMediaPlayerm=null;
    privateTimermTimer;
    privateTimerTaskmTimerTask;
    
    privatebooleanisChanging=false;//互斥变量,防止定时器与SeekBar拖动时进度冲突
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    //----------Media控件设置---------//
    m=newMediaPlayer();
    
    //播放结束之后弹出提示
    m.setOnCompletionListener(newMediaPlayer.OnCompletionListener(){
    @Override
    publicvoidonCompletion(MediaPlayerarg0){
    Toast.makeText(testMedia.this,"结束",1000).show();
    m.release();
    }
    });
    
    //----------定时器记录播放进度---------//
    mTimer=newTimer();
    mTimerTask=newTimerTask(){
    @Override
    publicvoidrun(){
    if(isChanging==true)
    return;
    
    if(m.getVideoHeight()==0)
    skb_audio.setProgress(m.getCurrentPosition());
    else
    skb_video.setProgress(m.getCurrentPosition());
    }
    };
    mTimer.schedule(mTimerTask,0,10);
    
    btn_start_audio=(Button)this.findViewById(R.id.Button01);
    btn_stop_audio=(Button)this.findViewById(R.id.Button02);
    btn_start_audio.setOnClickListener(newClickEvent());
    btn_stop_audio.setOnClickListener(newClickEvent());
    skb_audio=(SeekBar)this.findViewById(R.id.SeekBar01);
    skb_audio.setOnSeekBarChangeListener(newSeekBarChangeEvent());
    
    btn_start_video=(Button)this.findViewById(R.id.Button03);
    btn_stop_video=(Button)this.findViewById(R.id.Button04);
    btn_start_video.setOnClickListener(newClickEvent());
    btn_stop_video.setOnClickListener(newClickEvent());
    skb_video=(SeekBar)this.findViewById(R.id.SeekBar02);
    skb_video.setOnSeekBarChangeListener(newSeekBarChangeEvent());
    surfaceView=(SurfaceView)findViewById(R.id.SurfaceView01);
    surfaceHolder=surfaceView.getHolder();
    surfaceHolder.setFixedSize(100,100);
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
    
    /*
    *按键事件处理
    */
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btn_start_audio)
    {
    m.reset();//恢复到未初始化的状态
    m=MediaPlayer.create(testMedia.this,R.raw.big);//读取音频
    
    skb_audio.setMax(m.getDuration());//设置SeekBar的长度
    try{
    m.prepare();//准备
    }catch(IllegalStateExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IOExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    m.start();//播放
    }
    elseif(v==btn_stop_audio||v==btn_stop_video)
    {
    m.stop();
    }
    elseif(v==btn_start_video)
    {
    m.reset();//恢复到未初始化的状态
    m=MediaPlayer.create(testMedia.this,R.raw.test);//读取视频
    skb_video.setMax(m.getDuration());//设置SeekBar的长度
    m.setAudioStreamType(AudioManager.STREAM_MUSIC);
    m.setDisplay(surfaceHolder);//设置屏幕
    
    try{
    m.prepare();
    
    }catch(IllegalArgumentExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IllegalStateExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IOExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    m.start();
    }
    }
    }
    
    /*
    *SeekBar进度改变事件
    */
    classSeekBarChangeEventimplementsSeekBar.OnSeekBarChangeListener{
    @Override
    publicvoidonProgressChanged(SeekBarseekBar,intprogress,
    booleanfromUser){
    //TODOAuto-generatedmethodstub
    
    }
    @Override
    publicvoidonStartTrackingTouch(SeekBarseekBar){
    isChanging=true;
    }
    @Override
    publicvoidonStopTrackingTouch(SeekBarseekBar){
    m.seekTo(seekBar.getProgress());
    isChanging=false;
    }
    
    }
    }
    Android提高第二篇之SurfaceView的基本使用
    SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此
    是个非常重要的绘图容器,这次我就用两篇文章来介绍SurfaceView的用法。网上介绍SurfaceView的用法有很多,写法也层出不同,例如继承SurfaceView类,或者继承SurfaceHolder.Callback类等,这个可以根据功能实际需要自己选择,我这里就直接在普通的用户界面调用SurfaceHolder的lockCanvas和unlockCanvasAndPost。
    右图用.lockCanvas(null),而左图用.lockCanvas(newRect(oldX,0,oldX+length,
    getWindowManager().getDefaultDisplay().getHeight())),对比一下两个效果,由于左图是按指定Rect绘画,所以效率会比右图的全控件绘画高些,并且在清屏之后(canvas.drawColor(Color.BLACK))不会留有上次绘画的残留。
         android:layout_width="fill_parent"android:layout_height="fill_parent"
    android:orientation="vertical">
        android:layout_width="wrap_content"android:layout_height="wrap_content">
        android:layout_height="wrap_content"android:text="简单绘画">
        android:layout_height="wrap_content"android:text="定时器绘画">
    
        android:layout_width="fill_parent"android:layout_height="fill_parent">
     packagecom.testSurfaceView;
    importjava.util.Timer;
    importjava.util.TimerTask;
    importandroid.app.Activity;
    importandroid.graphics.Canvas;
    importandroid.graphics.Color;
    importandroid.graphics.Paint;
    importandroid.graphics.Rect;
    importandroid.os.Bundle;
    importandroid.util.Log;
    importandroid.view.SurfaceHolder;
    importandroid.view.SurfaceView;
    importandroid.view.View;
    importandroid.widget.Button;
    publicclasstestSurfaceViewextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnSimpleDraw,btnTimerDraw;
    SurfaceViewsfv;
    SurfaceHoldersfh;
    privateTimermTimer;
    privateMyTimerTaskmTimerTask;
    intY_axis[],//保存正弦波的Y轴上的点
    centerY,//中心线
    oldX,oldY,//上一个XY点
    currentX;//当前绘制到的X轴上的点
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnSimpleDraw=(Button)this.findViewById(R.id.Button01);
    btnTimerDraw=(Button)this.findViewById(R.id.Button02);
    btnSimpleDraw.setOnClickListener(newClickEvent());
    btnTimerDraw.setOnClickListener(newClickEvent());
    sfv=(SurfaceView)this.f
    indViewById(R.id.SurfaceView01);
    sfh=sfv.getHolder();
    //动态绘制正弦波的定时器
    mTimer=newTimer();
    mTimerTask=newMyTimerTask();
    //初始化y轴数据
    centerY=(getWindowManager().getDefaultDisplay().getHeight()-sfv
    .getTop())/2;
    Y_axis=newint[getWindowManager().getDefaultDisplay().getWidth()];
    for(inti=1;i    Y_axis[i-1]=centerY
    -(int)(100*Math.sin(i*2*Math.PI/180));
    }
    }
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnSimpleDraw){
    SimpleDraw(Y_axis.length-1);//直接绘制正弦波
    
    }elseif(v==btnTimerDraw){
    oldY=centerY;
    mTimer.schedule(mTimerTask,0,5);//动态绘制正弦波
    }
    }
    }
    classMyTimerTaskextendsTimerTask{
    @Override
    publicvoidrun(){
    SimpleDraw(currentX);
    currentX++;//往前进
    if(currentX==Y_axis.length-1){//如果到了终点,则清屏重来
    ClearDraw();
    currentX=0;
    oldY=centerY;
    }
    }
    }
    
    /*
    *绘制指定区域
    */
    voidSimpleDraw(intlength){
    if(length==0)
    oldX=0;
    Canvascanvas=sfh.lockCanvas(newRect(oldX,0,oldX+length,
    getWindowManager().getDefaultDisplay().getHeight()));//关键:获取画布
    Log.i("Canvas:",
    String.valueOf(oldX)+","+String.valueOf(oldX+length));
    PaintmPaint=newPaint();
    mPaint.setColor(Color.GREEN);//画笔为绿色
    mPaint.setStrokeWidth(2);//设置画笔粗细
    inty;
    for(inti=oldX+1;i    y=Y_axis[i-1];
    canvas.drawLine(oldX,oldY,i,y,mPaint);
    oldX=i;
    oldY=y;
    }
    sfh.unlockCanvasAndPost(canvas);//解锁画布,提交画好的图像
    }
    voidClearDraw(){
    Canvascanvas=sfh.lockCanvas(null);
    canvas.drawColor(Color.BLACK);/
    /清除画布
    sfh.unlockCanvasAndPost(canvas);
    }
    }
    注意一下for(inti=oldX+1;i    Android提高第三篇之SurfaceView与多线程的混搭
    SurfaceView与多线程混搭,是为了防止动画闪烁而实现的一种多线程应用。android的多线程用法与JAVA的多线程用法完全一样,本文不做多线程方面的介绍了。直接讲解SurfaceView与多线程的混合使用,即开一条线程专门读取图片,另外一条线程专门绘图。
    本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:
    对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都“边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高动画播放的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。
        android:layout_width="fill_parent"android:layout_height="fill_parent"
    android:orientation="vertical">
        android:layout_width="wrap_content"android:layout_height="wrap_content">
        android:layout_height="wrap_content"android:text="单个独立线程">
        android:layout_height="wrap_content"android:text="两个独立线程">
    
        android:layout_width="fill_parent"android:layout_height="fill_parent">
    packagecom.testSurfaceView;
    importjava.lang.reflect.Field;
    importjava.util.ArrayList;
    importandroid.app.Activity;
    importandroid.graphics.Bitmap;
    importandroid.graphics.BitmapFactory;
    importandroid.graphics.Canvas;
    importandroid.graphics.Paint;
    importandroid.graphics.Rect;
    importandroid.os.Bundle;
    importandroid.util.Log;
    importandroid.view.SurfaceHolder;
    importandroid.view.SurfaceView;
    importandroid.view.View;
    importandroid.widget.Button;
    publicclasstestSurfaceViewextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnSingleThread,btnDoubleThread;
    SurfaceViewsfv;
    SurfaceHoldersfh;
    ArrayListimgList=newArrayList();
    intimgWidth,imgHeight;
    Bitmapbitmap;//独立线程读取,独立线程绘图
    @Override
    publicvoidonCreate(Bundle
    savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnSingleThread=(Button)this.findViewById(R.id.Button01);
    btnDoubleThread=(Button)this.findViewById(R.id.Button02);
    btnSingleThread.setOnClickListener(newClickEvent());
    btnDoubleThread.setOnClickListener(newClickEvent());
    sfv=(SurfaceView)this.findViewById(R.id.SurfaceView01);
    sfh=sfv.getHolder();
    sfh.addCallback(newMyCallBack());//自动运行surfaceCreated以及surfaceChanged
    }
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnSingleThread){
    newLoad_DrawImage(0,0).start();//开一条线程读取并绘图
    }elseif(v==btnDoubleThread){
    newLoadImage().start();//开一条线程读取
    newDrawImage(imgWidth+10,0).start();//开一条线程绘图
    }
    }
    }
    classMyCallBackimplementsSurfaceHolder.Callback{
    @Override
    publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,
    intheight){
    Log.i("Surface:","Change");
    }
    @Override
    publicvoidsurfaceCreated(SurfaceHolderholder){
    Log.i("Surface:","Create");
    //用反射机制来获取资源中的图片ID和尺寸
    Field[]fields=R.drawable.class.getDeclaredFields();
    for(Fieldfield:fields){
    if(!"icon".equals(field.getName()))//除了icon之外的图片
    {
    intindex=0;
    try{
    index=field.getInt(R.drawable.class);
    }catch(IllegalArgumentExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IllegalAccessExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    //保存图片ID
    imgList.add(index);
    }
    }
    //取得图像大小
    
    BitmapbmImg=BitmapFactory.decodeResource(getResources(),
    imgList.get(0));
    imgWidth=bmImg.getWidth();
    imgHeight=bmImg.getHeight();
    }
    @Override
    publicvoidsurfaceDestroyed(SurfaceHolderholder){
    Log.i("Surface:","Destroy");
    }
    }
    /*
    *读取并显示图片的线程
    */
    classLoad_DrawImageextendsThread{
    intx,y;
    intimgIndex=0;
    publicLoad_DrawImage(intx,inty){
    this.x=x;
    this.y=y;
    }
    publicvoidrun(){
    while(true){
    Canvasc=sfh.lockCanvas(newRect(this.x,this.y,this.x
    +imgWidth,this.y+imgHeight));
    BitmapbmImg=BitmapFactory.decodeResource(getResources(),
    imgList.get(imgIndex));
    c.drawBitmap(bmImg,this.x,this.y,newPaint());
    imgIndex++;
    if(imgIndex==imgList.size())
    imgIndex=0;
    sfh.unlockCanvasAndPost(c);//更新屏幕显示内容
    }
    }
    };
    /*
    *只负责绘图的线程
    */
    classDrawImageextendsThread{
    intx,y;
    publicDrawImage(intx,inty){
    this.x=x;
    this.y=y;
    }
    publicvoidrun(){
    while(true){
    if(bitmap!=null){//如果图像有效
    Canvasc=sfh.lockCanvas(newRect(this.x,this.y,this.x
    +imgWidth,this.y+imgHeight));
    c.drawBitmap(bitmap,this.x,this.y,newPaint());
    sfh.unlockCanvasAndPost(c);//更新屏幕显示内容
    }
    }
    }
    };
    /*
    *只负责读取图片的线程
    */
    classLoadImageextendsThread{
    intimgIndex=0;
    publicvoidrun(){
    while(true){
    bitmap=BitmapFactory.decodeResource(getResources(),
    imgList.get(imgIndex));
    imgIndex++;
    if(imgIndex==imgList.size())//如果到尽
    头则重新读取
    imgIndex=0;
    }
    }
    };
    }
    在一个LayoutXML与一个Activity捆绑的情况下可以视为一个Form,多个LayoutXML与一个Activity捆绑的话那就是个Application本身了。Intent可以分为显式Intent和隐式Intent:显式Intent用于启动明确的目标组件(前面所说的三大组件),同一个Application内的多个Activity调用也是显式Intent;隐式Intent就是调用没有明确的目标组件,可以是系统也可以是第三方程序。隐式Intent一般用于调用系统组件功能,相关例程都是网络上很容易找到的(调用某些系统组件的时候要申请权限)。
    Android有三个基础组件Activity,Service和BroadcastReceiver,他们都是依赖Intent来启动。本文介绍的是Activity的生命周期以及针对Activity的Intent使用
     //有些外部调用需要开启权限
    Uriuri=Uri.parse("google");
    Intentit=newIntent(Intent.ACTION_VIEW,uri);
    startActivity(it);
    Android提高第五篇之Service
    如果把Activity比喻为前台程序,那么Service就是后台程序,Service的整个生命周期都只会在后台执行。Service跟Activity一样也由Intent调用。在工程里想要添加一个Service,先新建继承Service的类,然后到AndroidManifest.xml->Application->ApplicationNodes中的Service标签中添加。
    Service要由Activity通过startService或者bindService来启动,Intent负责传递参数。
    startService与bindService都可以启动Service,那么它们之间有什么区别呢?它们两者的区别就是使Service的周期改变。由startService启动的Service必须要有stopService来结束Service,不调用stopService则会造成Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在Activity结束之后(onDestroy)自动结束。
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_height="wrap_content"android:id="@+id/btnStartMyService"
    android:text="StartMyService">
        android:layout_height="wrap_content"android:id="@+id/btnStopMyService"
    android:text="StopMyService">
        android:layout_height="wrap_content"android:id="@+id/btnBindMyService"
    android:text="BindMyService">
        android:layout_height="wrap_content"android:id="@+id/btnUnbind
    MyService"
    android:text="UnbindMyService">
        android:layout_height="wrap_content"android:id="@+id/btnExit"
    android:text="退出程序">
    packagecom.testService;
    importandroid.app.Activity;
    importandroid.app.Service;
    importandroid.content.ComponentName;
    importandroid.content.Intent;
    importandroid.content.ServiceConnection;
    importandroid.os.Bundle;
    importandroid.os.IBinder;
    importandroid.util.Log;
    importandroid.view.View;
    importandroid.widget.Button;
    publicclasstestServiceextendsActivity{
    ButtonbtnStartMyService,btnStopMyService,btnBindMyService,btnUnbindMyService,btnExit;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnStartMyService=(Button)this.findViewById(R.id.btnStartMyService);
    btnStartMyService.setOnClickListener(newClickEvent());
    
    btnStopMyService=(Button)this.findViewById(R.id.btnStopMyService);
    btnStopMyService.setOnClickListener(newClickEvent());
    
    btnBindMyService=(Button)this.findViewById(R.id.btnBindMyService);
    btnBindMyService.setOnClickListener(newClickEvent());
    
    btnUnbindMyService=(Button)this.findViewById(R.id.btnUnbindMyService);
    btnUnbindMyService.setOnClickListener(newClickEvent());
    
    btnExit=(Button)this.findViewById(R.id.btnExit);
    btnExit.setOnClickListener(newClickEvent());
    }
    @Override
    publicvoidonDestroy()
    {
    super.onDestroy();
    Log.e("Activity","onDestroy");
    }
    
    privateServiceConnection_connection=newServiceConnection(){
    @Override
    publicvoidonServiceConnected(ComponentNamearg0,IBinderarg1){
    //TODOAuto-generatedmethodstub
    }
    @Override
    publicvoidonServiceDisconnected(ComponentNamename){
    //TODOAuto-generatedmethodstub
    }
    };
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    Intentintent=newIntent(testService.this,MyService.class);
    if(v==btnStartMyService){
    testService.this.startService(intent);
    }
    elseif(v==btnStopMyService){
    testService.this.stopService(intent);
    }
    elseif(v==btnBindMyService){
    testService.this.bindService(intent,_connection,Service.BIND_AUTO_CREATE);
    }
    elseif(v==btnUnbindMyService){
    
    if(MyService.ServiceState=="onBind")//Service绑定了之后才能解绑
    testService.this.unbindService(_connection);
    }
    elseif(v==btnExit)
    {
    testService.this.finish();
    }
    
    }
    
    }
    }
    packagecom.testService;
    importandroid.app.Service;
    importandroid.content.Intent;
    importandroid.os.IBinder;
    importandroid.util.Log;
    publicclassMyServiceextendsService{
    staticpublicStringServiceState="";
    @Override
    publicIBinderonBind(Intentarg0){
    Log.e("Service","onBind");
    ServiceState="onBind";
    returnnull;
    }
    @Override
    publicbooleanonUnbind(Intentintent){
    super.onUnbind(intent);
    Log.e("Service","onUnbind");
    ServiceState="onUnbind";
    returnfalse;
    
    }
    @Override
    publicvoidonCreate(){
    super.onCreate();
    Log.e("Service","onCreate");
    ServiceState="onCreate";
    }
    @Override
    publicvoidonDestroy(){
    super.onDestroy();
    Log.e("Service","onDestroy");
    ServiceState="onDestroy";
    }
    @Override
    publicvoidonStart(Intentintent,intstartid){
    super.onStart(intent,startid);
    Log.e("Service","onStart");
    ServiceState="onStart";
    }
    }
    在Android里面可以使用SAX和DOM,DOM需要把整个XML文件读入内存再解析,比较消耗内存,而SAX基于事件驱动的处理方式,可以在各节点触发回调函数,不过SAX适合节点结构简单的XML文档,复杂的XML文档在后期的节点深度处理会有点麻烦。
    
    
    
    
    hellogv
    blog.csdn.net/hellogv
    
    

    使用SAX解析,需要定义SAXParserFactory(使应用程序能够配置和获取基于SAX的解析器以解析XML文档),SAXParser(从各种输入源解析XML),XMLReader(使用回调函数读取XML文档),其中XMLReader是个关键。XMLReader可以为解析XML定义各种回调函数,“条件符合”的时候触发这些回调函数。
    SAXParserFactoryfactory=SAXParserFactory.newInstance();
    SAXParserparser=factory.newSAXParser();
    XMLReaderreader=parser.getXMLReader();
    reader.setContentHandler(handler);
    reader.parse(newInputSource(testSAX.this.getResources()
    
    .openRawResource(R.raw.test)));
    在这段代码里,XMLReader就调用继承DefaultHandler的SAXHandler。DefaultHandler已实现ContentHandler,DTDHandler,EntityResolver,ErrorHandler等接口,包含常见读取XML的操作,具体请看下面的SAXHandler.java源码。生成XML的结果如下
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_width="fill_parent"android:id="@+id/btnSAX"
    android:text="使用SAX解析XML">
        android:layout_width="fill_parent"android:text="生成XML"android:id="@+id/btnOutput">
        android:layout_width="fill_parent"android:layout_height="fill_parent">
    packagecom.testSAX;
    importjava.io.StringWriter;
    importjavax.xml.parsers.SAXParser;
    importjavax.xml.parsers.SAXParserFactory;
    importorg.xml.sax.InputSource;
    importorg.xml.sax.XMLReader;
    importorg.xmlpull.v1.XmlSerializer;
    importandroid.app.Activity;
    importandroid.os.Bundle;
    importandroid.util.Xml;
    importandroid.view.View;
    importandroid.widget.Button;
    importandroid.widget.EditText;
    publicclasstestSAXextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnSAX,btnOutput;
    EditTextmemo;
    SAXHandlerhandler=newSAXHandler();
    
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnSAX=(Button)this.findViewById(R.id.btnSAX);
    btnSAX.setOnClickListener(newClickEvent());
    btnOutput=(Button)this.findViewById(R.id.btnOutput);
    btnOutput.setOnClickListener(newClickEvent());
    memo=(EditText)this.findViewById(R.id.EditText01);
    }
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnSAX){//解析XML,并保存标记,属性等值
    try{
    SAXParserFactoryfactory=SAXParserFactory.newInstance();
    SAXParserparser=factory.newSAXParser();
    XMLReaderreader=parser.getXMLReader();
    reader.setContentHandler(handler);
    reader.parse(newInputSource(testSAX.this.getResources()
    .openRa
    wResource(R.raw.test)));
    }catch(Exceptionee){}
    }
    elseif(v==btnOutput){//生成XML
    try{
    XmlSerializerserializer=Xml.newSerializer();
    StringWriterwriter=newStringWriter();
    try{
    serializer.setOutput(writer);
    serializer.startDocument("UTF-8",true);
    
    for(inti=0;i    {
    if(handler.GetKeys().get(i).equals("startTag"))
    {
    serializer.startTag("",(String)handler.GetValues().get(i));
    }
    elseif(handler.GetKeys().get(i).equals("Attr")){
    String[]str=(String[])handler.GetValues().get(i);
    serializer.attribute("",str[0],str[1]);
    }
    elseif(handler.GetKeys().get(i).equals("text"))
    serializer.text((String)handler.GetValues().get(i));
    elseif(handler.GetKeys().get(i).equals("endTag"))
    {
    serializer.endTag("",(String)handler.GetValues().get(i));
    }
    }
    serializer.endDocument();
    Stringtext=writer.toString();
    text=text.replace("><",">/r/n<");
    memo.setText(text);//输出到文本框
    }catch(Exceptione){
    thrownewRuntimeException(e);
    }
    }catch(Exceptione){}
    }
    }
    }
    }
    Android提高第八篇之SQLite分页读取
    Android包含了常用于嵌入式系统的SQLite,免去了开发者自己移植安装的功夫。SQLite支持多数SQL92标准,很多常用的SQL命
    令都能在SQLite上面使用,除此之外Android还提供了一系列自定义的方法去简化对SQLite数据库的操作。不过有跨平台需求的程序就建议使用标准的SQL语句,毕竟这样容易在多个平台之间移植。
    本文主要讲解了SQLite的基本用法,如:创建数据库,使用SQL命令查询数据表、插入数据,关闭数据库,以及使用GridView实现了一个分页栏(关于GridView的用法),用于把数据分页显示。
    
        android:layout_height="wrap_content"android:paddingBottom="4dip"
    android:layout_width="fill_parent">
        android:layout_below="@+id/ItemImage"android:layout_height="wrap_content"
    android:text="TextView01"android:layout_centerHorizontal="true"
    android:id="@+id/ItemText">
    
    
    
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_width="fill_parent"android:id="@+id/btnCreateDB"
    android:text="创建数据库">
        android:layout_width="fill_parent"android:text="插入一串实验数据"android:id="@+id/btnInsertRec">
        android:text="关闭数据库"android:layout_width="fill_parent">
        android:layout_width="fill_parent"android:layout_height="256dip">
        android:layout_height="32dip"android:numColumns="auto_fit"
    android:columnWidth="40dip">
    
    packagecom.testSQLite;
    
    importjava.util.ArrayList;
    importjava.util.HashMap;
    importandroid.app.Activity;
    importandroid.database.Cursor;
    importandroid.database.SQLException;
    importandroid.database.sqlite.SQLiteDatabase;
    importandroid.os.Bundle;
    importandroid.util.Log;
    importandroid.view.View;
    importandroid.widget.AdapterView;
    importandroid.widget.AdapterView.OnItemClickListener;
    importandroid.widget.Button;
    importandroid.widget.EditText;
    importandroid.widget.GridView;
    importandroid.widget.SimpleAdapter;
    
    publicclasstestSQLiteextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnCreateDB,btnInsert,btnClose;
    EditTextedtSQL;//显示分页
    数据
    SQLiteDatabasedb;
    intid;//添加记录时的id累加标记,必须全局
    staticfinalintPageSize=10;//分页时,每页的数据总数
    privatestaticfinalStringTABLE_NAME="stu";
    privatestaticfinalStringID="id";
    privatestaticfinalStringNAME="name";
    
    SimpleAdaptersaPageID;//分页栏适配器
    ArrayList>lstPageID;//分页栏的数据源,与PageSize和数据总数相关
    
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnCreateDB=(Button)this.findViewById(R.id.btnCreateDB);
    btnCreateDB.setOnClickListener(newClickEvent());
    
    btnInsert=(Button)this.findViewById(R.id.btnInsertRec);
    btnInsert.setOnClickListener(newClickEvent());
    
    btnClose=(Button)this.findViewById(R.id.btnClose);
    btnClose.setOnClickListener(newClickEvent());
    
    edtSQL=(EditText)this.findViewById(R.id.EditText01);
    
    GridViewgridview=(GridView)findViewById(R.id.gridview);//分页栏控件
    //生成动态数组,并且转入数据
    lstPageID=newArrayList>();
    
    //生成适配器的ImageItem<====>动态数组的元素,两者一一对应
    saPageID=newSimpleAdapter(testSQLite.this,//没什么解释
    lstPageID,//数据来源
    R.layout.pagebuttons,//XML实现
    newString[]{"ItemText"},
    newint[]{R.id.ItemText});
    
    //添加并且显示
    gridview.setAdapter(saPageID);
    //添加消息处理
    gridview.setOnItemClickListener(newOnItemClickListener(){
    
    @Override
    publicvoidonItemClick(AdapterViewarg0,Viewarg1,intarg2,
    longarg3){
    LoadPage(arg2);//根据所选分页读取对应的数据
    }
    });
    
    }
    
    
    classClickEventimplementsView.OnClickListener{
    
    @Override
    publicvoidonClick(Viewv){
    if(v==btnCreateDB){
    CreateDB();
    }elseif(v==btnInsert){
    InsertRecord(16);//插入16条记录
    RefreshPage();
    }elseif(v==btnClose){
    db.close();
    }
    }
    
    }
    
    
    /*
    *读取指定ID的分页数据
    *SQL:Select*FromTABLE_NAMELimit9Offset10;
    *表示从TABLE_NAME表获取数据,跳过10行,取9行
    */
    voidLoadPage(intpageID)
    {
    Stringsql="select*from"+TABLE_NAME+
    "Limit"+String.valueOf(PageSize)+"Offset"+String.valueOf(pageID*PageSize)
    ;
    Cursorrec=db.rawQuery(sql,null);
    
    setTitle("当前分页的数据总数:"+String.valueOf(rec.getCount()));
    
    //取得字段名称
    Stringtitle="";
    intcolCount=rec.getColumnCount();
    for(inti=0;i    title=title+rec.getColumnN, ame(i)+"";
    
    
    //列举出所有数据
    Stringcontent="";
    intrecCount=rec.getCount();
    for(inti=0;i    rec.moveToPosition(i);
    for(intii=0;ii    {
    content=content+rec.getString(ii)+"";
    }
    content=content+"/r/n";
    }
    
    edtSQL.setText(title+"/r/n"+content);//显示出来
    rec.close();
    }
    
    /*
    *在内存创建数据库和数据表
    */
    voidCreateDB(){
    //在内存创建数据库
    db=SQLiteDatabase.create(null);
    Log.e("DBPath",db.getPath());
    Stringamount=String.valueOf(databaseList().length);
    Log.e("DBamount",amount);
    //创建数据表
    Stringsql="CREATETABLE"+TABLE_NAME+"("+ID
    +"textnotnull,"+NAME+"textnotnull"+");";
    try{
    db.execSQL("DROPTABLEIFEXISTS"+TABLE_NAME);
    db.execSQL(sql);
    }catch(SQLExceptione){}
    }
    
    /*
    *插入N条数据
    */
    voidInsertRecord(intn){
    inttotal=id+n;
    for(;id    Stringsql="insertinto"+TABLE_NAME+"("+ID+","+NAME
    +")values('"+String.valueOf(id)+"','test');";
    try{
    db.execSQL(sql);
    }catch(SQLExceptione){
    }
    }
    }
    
    /*
    *插入之后刷新分页
    */
    voidRefreshPage()
    {
    Stringsql="selectcount(*)from"+TABLE_NAME;
    Cursorrec=db.rawQuery(sql,null);
    rec.moveToLast();
    longrecSize=rec.getLong(0);//取得总数
    rec.close();
    intpageNum=(int)(recSize/PageSize)+1;//取得分页数
    
    lstPageID.clear();
    for(inti=0;i    HashMapmap=newHashMap();
    map.put("ItemText","No."+String.valueOf(i));
    
    lstPageID.add(map);
    }
    saPageID.notifyDataSetChanged();
    }
    }
    Android提高第九篇之SQLite分页表格
    实现并封装一个SQL分页表格控件,不仅支持分页还是以表格的形式展示数据
    这个SQL分页表格控件主要分为“表格区”和“分页栏”这两
    部分,这两部分都是基于GridView实现的。网上介绍Android上实现表格的DEMO一般都用ListView。ListView与GridView对比,ListView最大的优势是格单元的大小可以自定义,可以某单元长某单元短,但是难于实现自适应数据表的结构;而GridView最大的优势就是自适应数据表的结构,但是格单元统一大小。。。对于数据表结构多变的情况,建议使用GridView实现表格。
    1.自适应数据表结构,但是格单元统一大小;
    2.支持分页;
    3.“表格区”有按键事件回调处理,“分页栏”有分页切换事件回调处理。
    packagecom.testSQLite;
    importandroid.app.Activity;
    importandroid.database.Cursor;
    importandroid.database.SQLException;
    importandroid.database.sqlite.SQLiteDatabase;
    importandroid.os.Bundle;
    importandroid.util.Log;
    importandroid.view.View;
    importandroid.widget.Button;
    importandroid.widget.LinearLayout;
    importandroid.widget.Toast;
    publicclasstestSQLiteextendsActivity{
    GVTabletable;
    ButtonbtnCreateDB,btnInsert,btnClose;
    SQLiteDatabasedb;
    intid;//添加记录时的id累加标记,必须全局
    privatestaticfinalStringTABLE_NAME="stu";
    privatestaticfinalStringID="id";
    privatestaticfinalStringNAME="name";
    privatestaticfinalStringPHONE="phone";
    privatestaticfinalStringADDRESS="address";
    privatestaticfinalStringAGE="age";
    
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnCreateDB=(Button)this.findViewById(R.id.btnCreateDB);
    btnCreateDB.setOnClickListener(newClickEvent());
    btnInsert=(Button)this.findViewById(R.id.btnInsertRec);
    btnInsert.setOnClickListener(newClickEvent());
    btnClose=(Button)this.findViewById(R.id.btnClose);
    btnClose.setOnClickListener(newClickEvent());
    table=newGVTable(this);
    table.gvSetTableRowCount(8);//设置每个分页的ROW总数
    LinearLayoutly=(LinearLayout)findViewById(R.id.MainLinearLayout);
    table.setTableOnClickListener(newGVTable.OnTableClickListener(){
    @Override
    publicvoidonTableClickListener(intx,inty,Cursorc){
    c.moveToPosition(y);
    Stringstr=c.getString(x)+"位置:("+String.valueOf(x)+","+String.valueOf(y)+")";
    Toast.makeText(testSQLite.this,str,1000).show();
    }
    });
    table.setOnPageSwitchListener(newGVTable.OnPageSwitchListener(){
    
    @Override
    
    publicvoidonPageSwitchListener(intpageID,intpageCount){
    Stringstr="共有"+String.valueOf(pageCount)+
    "当前第"+String.valueOf(pageID)+"页";
    Toast.makeText(testSQLite.this,str,1000).show();
    }
    });
    
    ly.addView(table);
    }
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnCreateDB){
    CreateDB();
    }elseif(v==btnInsert){
    InsertRecord(16);//插入16条记录
    table.gvUpdatePageBar("selectcount(*)from"+TABLE_NAME,db);
    table.gvReadyTable("select*from"+TABLE_NAME,db);
    }elseif(v==btnClose){
    table.gvRemoveAll();
    db.close();
    
    }
    }
    }
    
    /**
    *在内存创建数据库和数据表
    */
    voidCreateDB(){
    //在内存创建数据库
    db=SQLiteDatabase.create(null);
    Log.e("DBPath",db.getPath());
    Stringamount=String.valueOf(databaseList().length);
    Log.e("DBamount",amount);
    //创建数据表
    Stringsql="CREATETABLE"+TABLE_NAME+"("+
    ID+"textnotnull,"+NAME+"textnotnull,"+
    ADDRESS+"textnotnull,"+PHONE+"textnotnull,"+
    AGE+"textnotnull"+");";
    try{
    db.execSQL("DROPTABLEIFEXISTS"+TABLE_NAME);
    db.execSQL(sql);
    }catch(SQLExceptione){}
    }
    /**
    *插入N条数据
    */
    voidInsertRecord(intn){
    inttotal=id+n;
    for(;id    Stringsql="insertinto"+TABLE_NAME+"("+
    ID+","+NAME+","+ADDRESS+","+PHONE+","+AGE
    +")values('"+String.valueOf(id)+"','man','address','123456789','18');";
    try{
    db.execSQL(sql);
    }catch(SQLExceptione){
    }
    }
    }
    
    
    }
    packagecom.testSQLite;
    importjava.util.ArrayList;
    importjava.util.HashMap;
    importandroid.content.Context;
    importandroid.database.Cursor;
    importandroid.database.sqlite.SQLiteDatabase;
    importandroid.view.View;
    importandroid.widget.AdapterView;
    importandroid.widget.GridView;
    importandroid.widget.LinearLayout;
    importandroid.widget.SimpleAdapter;
    importandroid.widget.AdapterView.OnItemClickListener;
    publicclassGVTableextendsLinearLayout{
    protectedGridViewgvTable,gvPage;
    protectedSimpleAdaptersaPageID,saTable;//适配器
    protectedArrayList>srcPageID,srcTable;//数据源
    
    protectedintTableRowCount=10;//分页时,每页的Row总数
    protectedintTableColCount=0;//每页col的数量
    protectedSQLiteDatabasedb;
    protectedStringrawSQL="";
    protectedCursorcurTable;//分页时使用的Cursor
    protectedOnTableClickListenerclickListener;//整个分页控件被点击时的回调函数
    protectedOnPageSwitchListenerswitchListener;//分页切换时的回调函数
    
    publicGVTable(Contextcontext){
    super(context);
    this.setOrientation(VERTICAL);//垂直
    //----------------------------------------
    gvTable=newGridView(context);
    addView(gvTable,newLinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
    LayoutParams.WRAP_CONTENT));//宽长式样
    
    srcTable=newArrayList>();
    saTable=newSimpleAdapter(context,
    srcTable,//数据来源
    R.layout.items,//XML实现
    newString[]{"ItemText"},//动态数组与ImageItem对应的子项
    newint[]{R.id.ItemText});
    //添加并且显示
    gvTable.setAdapter(saTable);
    gvTable.setOnItemClickListener(newOnItemClickListener(){
    @Override
    publicvoidonItemClick(AdapterViewarg0,Viewarg1,intarg2,
    longarg3){
    inty=arg2/curTable.getColumnCount()-1;//标题栏的不算
    intx=arg2%curTable.getColumnCount();
    if(clickListener!=null//分页数据被点击
    &;&;y!=-1){//点中的不是标题栏时
    clickListener.onTableClickListener(x,y,curTable);
    }
    }
    });
    
    //----------------------------------------
    gvPage=newGridView(context);
    gvPage.setColumnWidth(40);//设置每个分页按钮的宽度
    gvPage.setNumColumns(GridView.AUTO_FIT);//分页按钮数量自动设置
    addView(gvPage,newLinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
    Layou
    tParams.WRAP_CONTENT));//宽长式样
    srcPageID=newArrayList>();
    saPageID=newSimpleAdapter(context,
    srcPageID,//数据来源
    R.layout.items,//XML实现
    newString[]{"ItemText"},//动态数组与ImageItem对应的子项
    newint[]{R.id.ItemText});
    //添加并且显示
    gvPage.setAdapter(saPageID);
    //添加消息处理
    gvPage.setOnItemClickListener(newOnItemClickListener(){
    @Override
    publicvoidonItemClick(AdapterViewarg0,Viewarg1,intarg2,
    longarg3){
    LoadTable(arg2);//根据所选分页读取对应的数据
    if(switchListener!=null){//分页切换时
    switchListener.onPageSwitchListener(arg2,srcPageID.size());
    }
    }
    });
    }
    /**
    *清除所有数据
    */
    publicvoidgvRemoveAll()
    {
    if(this.curTable!=null)
    curTable.close();
    srcTable.clear();
    saTable.notifyDataSetChanged();
    
    srcPageID.clear();
    saPageID.notifyDataSetChanged();
    
    }
    /**
    *读取指定ID的分页数据,返回当前页的总数据
    *SQL:Select*FromTABLE_NAMELimit9Offset10;
    *表示从TABLE_NAME表获取数据,跳过10行,取9行
    *@parampageID指定的分页ID
    */
    protectedvoidLoadTable(intpageID)
    {
    if(curTable!=null)//释放上次的数据
    curTable.close();
    
    Stringsql=rawSQL+"Limit"+String.valueOf(TableRowCount)+"Offset"+String.valueOf(pageID*TableRowCount);
    curTable=db.rawQuery(sql,null);
    
    gvTable.setNumColumns(curTable.getColumnCount());//表现为表格的关键点!
    TableColCount=curTable.getColumnCount();
    srcTable.clear();
    //取得字段名称
    intcolCount=curTable.getColumnCount();
    for(inti=0;i    HashMapmap=newHashMap();
    map.put("ItemText",curTable.getColumnName(i));
    srcTable.add(map);
    }
    
    //列举出所有数据
    intrecCount=curTable.getCount();
    for(inti=0;i    curTable.moveToPosition(i);
    
    for(intii=0;ii    {
    HashMapmap=newHashMap();
    map.put("ItemText",curTable.getString(ii));
    srcTable.add(map);
    }
    }
    
    saTable.notifyDataSetChanged();
    }
    /**
    *设置表格的最多显示的行数
    *@paramrow表格的行数
    */
    publicvoidgvSetTableRowCount(introw)
    {
    TableRowCount=row;
    }
    
    /**
    *取得表格的最大行数
    *@return行数
    */
    publicintgvGetTableRowCount()
    {
    returnTableRowCount;
    }
    
    /**
    *取得当前分页的Cursor
    *@return当前分页的Cursor
    */
    publicCursorgvGetCurrentTable()
    {
    returncurTable;
    }
    
    /**
    *准备分页显示数据
    *@paramrawSQLsql语句
    *@paramdb数据库
    */
    publicvoidgvReadyTable(StringrawSQL,SQLiteDatabasedb)
    {
    this.rawSQL=rawSQL;
    this.db=db;
    }
    
    /**
    *刷新分页栏,更新按钮数量
    *@paramsqlSQL语句
    *@paramdb数据库
    */
    publicvoidgvUpdatePageBar(Stringsql,SQLiteDatabasedb)
    {
    Cursorrec=db.rawQuery(sql,null);
    rec.moveToLast();
    longrecSize=rec.getLong(0);//取得总数
    rec.close();
    intpageNum=(int)(recSize/TableRowCount)+1;//取得分页数
    
    srcPageID.clear();
    for(inti=0;i    HashMapmap=newHashMap();
    map.put("ItemText","No."+String.valueOf(i));//添加图像资源的ID
    srcPageID.add(map);
    }
    saPageID.notifyDataSetChanged();
    }
    //---------------------------------------------------------
    /**
    *表格被点击时的回调函数
    */
    publicvoidsetTableOnClickListener(OnTableClickListenerclick){
    this.clickListener=click;
    }
    
    publicinterfaceOnTableClickListener{
    publicvoidonTableClickListener(intx,inty,Cursorc);
    }
    //---------------------------------------------------------
    /**
    *分页栏被点击时的回调函数
    */
    publicvoidsetOnPageSwitchListener(OnPageSwitchListenerpageSwitch){
    this.switchListener=p
    ageSwitch;
    }
    publicinterfaceOnPageSwitchListener{
    publicvoidonPageSwitchListener(intpageID,intpageCount);
    }
    }
    Android提高第十篇之AudioRecord实现"助听器"
    Android可以通过MediaRecorder和AudioRecord这两个工具来实现录音,MediaRecorder直接把麦克风的数据存到文件,并且能够直接进行编码(如AMR,MP3等),而AudioRecord则是读取麦克风的音频流。本文使用AudioRecord读取音频流,使用AudioTrack播放音频流,通过“边读边播放”以及增大音量的方式来实现一个简单的助听器程序
    PS:由于目前的Android模拟器还不支持AudioRecord,因此本程序需要编译之后放到真机运行。
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_width="fill_parent"android:text="开始边录边放">
        android:layout_width="fill_parent"android:text="停止"android:id="@+id/btnStop">
        android:layout_width="fill_parent"android:text="退出">
        android:text="程序音量调节"android:layout_width="fill_parent">
        android:layout_width="fill_parent">
    packagecom.testRecord;
    importandroid.app.Activity;
    importandroid.media.AudioFormat;
    importandroid.media.AudioManager;
    importandroid.media.AudioRecord;
    importandroid.media.AudioTrack;
    importandroid.media.MediaRecorder;
    importandroid.os.Bundle;
    importandroid.view.View;
    importandroid.widget.Button;
    importandroid.widget.SeekBar;
    importandroid.widget.Toast;
    publicclasstestRecordextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnRecord,btnStop,btnExit;
    SeekBarskbVolume;//调节音量
    booleanisRecording=false;//是否录放的标记
    staticfinalintfrequency=44100;
    staticfinalintchannelConfiguration=AudioFormat.CHANNEL_CONFIGURATION_MONO;
    staticfinalintaudioEncoding=AudioFormat.ENCODING_PCM_16BIT;
    intrecBufSize,playBufSize;
    AudioRecordaudioRecord;
    AudioTrackaudioTrack;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    setTitle("助听器");
    recBufSize=AudioRecord.getMinBufferSize(frequency,
    
    channelConfiguration,audioEncoding);
    playBufSize=AudioTrack.getMinBufferSize(frequency,
    channelConfiguration,audioEncoding);
    //-----------------------------------------
    audioRecord=newAudioRecord(MediaRecorder.AudioSource.MIC,frequency,
    channelConfiguration,audioEncoding,recBufSize);
    audioTrack=newAudioTrack(AudioManager.STREAM_MUSIC,frequency,
    channelConfiguration,audioEncoding,
    playBufSize,AudioTrack.MODE_STREAM);
    //------------------------------------------
    btnRecord=(Button)this.findViewById(R.id.btnRecord);
    btnRecord.setOnClickListener(newClickEvent());
    btnStop=(Button)this.findViewById(R.id.btnStop);
    btnStop.setOnClickListener(newClickEvent());
    btnExit=(Button)this.findViewById(R.id.btnExit);
    btnExit.setOnClickListener(newClickEvent());
    skbVolume=(SeekBar)this.findViewById(R.id.skbVolume);
    skbVolume.setMax(100);//音量调节的极限
    skbVolume.setProgress(70);//设置seekbar的位置值
    audioTrack.setStereoVolume(0.7f,0.7f);//设置当前音量大小
    skbVolume.setOnSeekBarChangeListener(newSeekBar.OnSeekBarChangeListener(){
    
    @Override
    publicvoidonStopTrackingTouch(SeekBarseekBar){
    floatvol=(float)(seekBar.getProgress())/(float)(seekBar.getMax());
    audioTrack.setStereoVolume(vol,vol);//设置音量
    }
    
    @Override
    publicvoidonStartTrackingTouch(SeekBarseekBar){
    //TODOAuto-generatedmethodstub
    }
    
    @Override
    publicvoidonProgressChanged(SeekBarseekBar,intprogress,
    booleanfromUser){
    //TODOAuto-generatedmethodstub
    }
    });
    }
    @Override
    protectedvoidonDestroy(){
    super.onDestroy();
    android.os.Process.killProcess(android.os.Process.myPid());
    }
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnRecord){
    isRecording=true;
    newRecordPlayThread().start();//开一条线程边录边放
    }elseif(v==btnStop){
    
    isRecording=false;
    }elseif(v==btnExit){
    isRecording=false;
    testRecord.this.finish();
    }
    }
    }
    classRecordPlayThreadextendsThread{
    publicvoidrun(){
    try{
    byte[]buffer=newbyte[recBufSize];
    audioRecord.startRecording();//开始录制
    audioTrack.play();//开始播放
    
    while(isRecording){
    //从MIC保存数据到缓冲区
    intbufferReadResult=audioRecord.read(buffer,0,
    recBufSize);
    byte[]tmpBuf=newbyte[bufferReadResult];
    System.arraycopy(buffer,0,tmpBuf,0,bufferReadResult);
    //写入数据即播放
    audioTrack.write(tmpBuf,0,tmpBuf.length);
    }
    audioTrack.stop();
    audioRecord.stop();
    }catch(Throwablet){
    Toast.makeText(testRecord.this,t.getMessage(),1000);
    }
    }
    };
    }
    Android提高第十一篇之模拟信号示波器
    结合SurfaceView实现一个Android版的手机模拟信号示波器。最近物联网炒得很火,作为手机软件开发者,如何在不修改手机硬件电路的前提下实现与第三方传感器结合呢?麦克风就是一个很好的ADC接口,通过麦克风与第三方传感器结合,再在软件里对模拟信号做相应的处理,就可以提供更丰富的传感化应用。
    本文程序使用8000hz的采样率,对X轴方向绘图的实时性要求较高,如果不降低X轴的分辨率,程序的实时性较差,因此程序对X轴数据缩小区间为8倍~16倍。由于采用16位采样,因此Y轴数据的高度相对于手机屏幕来说也偏大,程序也对Y轴数据做缩小,区间为1倍~10倍。在SurfaceView的OnTouchListener方法里加入了波形基线的位置调节,直接在SurfaceView控件上触摸即可控制整体波形偏上或偏下显示。
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_height="wrap_content"android:layout_width="fill_parent"
    android:orientation="horizontal">
        android:text="开始"android:layout_width="80dip">
        android:id="@+id/btnExit"android:layout_width="80dip">
        android:layout_height="wrap_content"android:id="@+id/zctlX">
        android:layout_height="wrap_content"android:id="@+id/zctlY">
    
        android:layout_height="fill_parent"android:layout_width="fill_parent">
    ClsOscilloscope.java是实现示波器的类库,包含AudioRecord操作线程和SurfaceView绘图线程的实现,两个线程同步操作,
    packagecom.testOscilloscope;
    importjava.util.ArrayList;
    importandroid.graphics.Canvas;
    importandroid.graphics.Color;
    importandroid.graphics.Paint;
    importandroid.graphics.Rect;
    importandroid.media.AudioRecord;
    importandroid.view.SurfaceView;
    publicclassClsOscilloscope{
    privateArrayListinBuf=newArrayList();
    privatebooleanisRecording=false;//线程控制标记
    /**
    *X轴缩小的比例
    */
    publicintrateX=4;
    /**
    *Y轴缩小的比例
    */
    publicintrateY=4;
    /**
    *Y轴基线
    */
    publicintbaseLine=0;
    /**
    *初始化
    */
    publicvoidinitOscilloscope(intrateX,intrateY,intbaseLine){
    this.rateX=rateX;
    this.rateY=rateY;
    this.baseLine=baseLine;
    }
    /**
    *开始
    *
    *@paramrecBufSize
    *AudioRecord的MinBufferSize
    */
    publicvoidStart(AudioRecordaudioRecord,intrecBufSize,SurfaceViewsfv,
    PaintmPaint){
    isRecording=true;
    newRecordThread(audioRecord,recBufSize).start();//开始录制线程
    newDrawThread(sfv,mPaint).start();//开始绘制线程
    }
    /**
    *停止
    */
    publicvoidStop(){
    isRecording=false;
    inBuf.clear();//清除
    }
    /**
    *负责从MIC保存数据到inBuf
    *
    *@authorGV
    *
    */
    classRecordThreadextendsThread{
    privateintrecBufSize;
    privateAudioRecordaudioRecord;
    publicRecordThread(AudioRecordaudioRecord,intrecBufSize){
    this.audioRecord=audioRecord;
    this.recBufSize=recBufSize;
    }
    publicvoidrun(){
    try{
    
    short[]buffer=newshort[recBufSize];
    audioRecord.startRecording();//开始录制
    while(isRecording){
    //从MIC保存数据到缓冲区
    intbufferReadResult=audioRecord.read(buffer,0,
    recBufSize);
    short[]tmpBuf=newshort[bufferReadResult/rateX];
    for(inti=0,ii=0;i    *rateX){
    tmpBuf[i]=buffer[ii];
    }
    synchronized(inBuf){//
    inBuf.add(tmpBuf);//添加数据
    }
    }
    audioRecord.stop();
    }catch(Throwablet){
    }
    }
    };
    /**
    *负责绘制inBuf中的数据
    *
    *@authorGV
    *
    */
    classDrawThreadextendsThread{
    privateintoldX=0;//上次绘制的X坐标
    privateintoldY=0;//上次绘制的Y坐标
    privateSurfaceViewsfv;//画板
    privateintX_index=0;//当前画图所在屏幕X轴的坐标
    privatePaintmPaint;//画笔
    publicDrawThread(SurfaceViewsfv,PaintmPaint){
    this.sfv=sfv;
    this.mPaint=mPaint;
    }
    publicvoidrun(){
    while(isRecording){
    ArrayListbuf=newArrayList();
    synchronized(inBuf){
    if(inBuf.size()==0)
    continue;
    buf=(ArrayList)inBuf.clone();//保存
    inBuf.clear();//清除
    }
    for(inti=0;i    short[]tmpBuf=buf.get(i);
    SimpleDraw(X_index,tmpBuf,rateY,baseLine);//把缓冲区数据画出来
    X_index=X_index+tmpBuf.length;
    if(X_index>sfv.getWidth()){
    X_index=0;
    }
    }
    }
    }
    /**
    *绘制指定区域
    *
    *@paramstart
    *X轴开始的位置(全屏)
    *@parambuffer
    *缓冲区
    *@paramrate
    *Y轴数据缩小的比例
    *@parambaseLine
    *Y轴基线
    */
    voidSimpleDraw(intstart,short[]buffer,intrate,intbaseLine){
    if(start==0)
    oldX=0;
    Canvascanvas=sfv.getHolder().lockCanvas(
    newRect(start,0,start+buffer.length,sfv.getHeight()));//关键:获取画布
    canvas.drawColor(Color.BLACK);//清除背景
    inty;
    for(inti=0;i    intx=i+start;
    y=buffer[i]/rate+baseLine;//调节缩小比例,调节基准线
    canvas.drawLine(oldX,oldY,x,y,mPaint);
    oldX=x;
    oldY=y;
    }
    sfv.getHolder().unlockCanvasAndPost(canvas);//解锁画布,提交画好的图像
    }
    }
    }
    packagecom.testOscilloscope;
    importandroid.app.Activity;
    importandroid.graphics.Color;
    importandroid.graphics.Paint;
    importandroid.media.AudioFormat;
    importandroid.media.AudioRecord;
    importandroid.media.MediaRecorder;
    importandroid.os.Bundle;
    importandroid.view.MotionEvent;
    importandroid.view.SurfaceView;
    importandroid.view.View;
    importandroid.view.View.OnTouchListener;
    importandroid.widget.Button;
    importandroid.widget.ZoomControls;
    publicclasstestOscilloscopeextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnStart,btnExit;
    SurfaceViewsfv;
    ZoomControlszctlX,zctlY;
    
    ClsOscilloscopeclsOscilloscope=newClsOscilloscope();
    
    staticfinalintfrequency=8000;//分辨率
    staticfinalintchannelConfiguration=AudioFormat.CHANNEL_CONFIGURATION_MONO;
    staticfinalintaudioEncoding=AudioFormat.ENCODING_PCM_16BIT;
    staticfinalintxMax=16;//X轴缩小比例最大值,X轴数据量巨大,容易产生刷新延时
    staticfinalintxMin=8;//X轴缩小比例最小值
    staticfinalintyMax=10;//Y轴缩小比例最大值
    staticfinalintyMin=1;//Y轴缩小比例最小值
    
    intrecBufSize;//录音最小buffer大小
    AudioRecordaudioRecord;
    PaintmPaint;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    //录音组件
    recBufSize=Aud
    ioRecord.getMinBufferSize(frequency,
    channelConfiguration,audioEncoding);
    audioRecord=newAudioRecord(MediaRecorder.AudioSource.MIC,frequency,
    channelConfiguration,audioEncoding,recBufSize);
    //按键
    btnStart=(Button)this.findViewById(R.id.btnStart);
    btnStart.setOnClickListener(newClickEvent());
    btnExit=(Button)this.findViewById(R.id.btnExit);
    btnExit.setOnClickListener(newClickEvent());
    //画板和画笔
    sfv=(SurfaceView)this.findViewById(R.id.SurfaceView01);
    sfv.setOnTouchListener(newTouchEvent());
    mPaint=newPaint();
    mPaint.setColor(Color.GREEN);//画笔为绿色
    mPaint.setStrokeWidth(1);//设置画笔粗细
    //示波器类库
    clsOscilloscope.initOscilloscope(xMax/2,yMax/2,sfv.getHeight()/2);
    
    //缩放控件,X轴的数据缩小的比率高些
    zctlX=(ZoomControls)this.findViewById(R.id.zctlX);
    zctlX.setOnZoomInClickListener(newView.OnClickListener(){
    @Override
    publicvoidonClick(Viewv){
    if(clsOscilloscope.rateX>xMin)
    clsOscilloscope.rateX--;
    setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
    +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
    }
    });
    zctlX.setOnZoomOutClickListener(newView.OnClickListener(){
    @Override
    publicvoidonClick(Viewv){
    if(clsOscilloscope.rateX    clsOscilloscope.rateX++;
    setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
    +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
    }
    });
    zctlY=(ZoomControls)this.findViewById(R.id.zctlY);
    zctlY.setOnZoomInClickListener(newView.OnClickListener(){
    @Override
    publicvoidonClick(Viewv){
    if(clsOscilloscope.rateY>yMin)
    clsOscilloscope.rateY--;
    setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
    +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
    }
    });
    
    zctlY.setOnZoomOutClickListener(newView.OnClickListener(){
    
    @Override
    publicvoidonClick(Viewv){
    if(clsOscilloscope.rateY    clsOscilloscope.rateY++;
    setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
    +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
    }
    });
    }
    @Override
    protectedvoidonDestroy(){
    super.onDestroy();
    android.os.Process.killProcess(android.os.Process.myPid());
    }
    
    /**
    *按键事件处理
    *@authorGV
    *
    */
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnStart){
    clsOscilloscope.baseLine=sfv.getHeight()/2;
    clsOscilloscope.Start(audioRecord,recBufSize,sfv,mPaint);
    }elseif(v==btnExit){
    clsOscilloscope.Stop();
    }
    }
    }
    /**
    *触摸屏动态设置波形图基线
    *@authorGV
    *
    */
    classTouchEventimplementsOnTouchListener{
    @Override
    publicbooleanonTouch(Viewv,MotionEventevent){
    clsOscilloscope.baseLine=(int)event.getY();
    returntrue;
    }
    }
    }
    Android提高第十二篇之蓝牙传感应用
    如果传感器本身需要包含控制电路(例如采集血氧信号需要红外和红外线交替发射),那么传感器本身就需要带一片主控IC,片内采集并输出数字信号了。Android手机如何在不改硬件电路的前提下与这类数字传感器交互呢?可选的通信方式就有USB和蓝牙,两种方式各有好处:USB方式可以给传感器供电,蓝牙方式要自备电源;USB接口标准不一,蓝牙普遍支持SPP协议。本文选择蓝牙方式做介绍,介绍Android的蓝牙API以及蓝牙客户端的用法。
    在Android2.0,官方终于发布了蓝牙API(2.0以下系统的非官方的蓝牙API可以参考这里:code.google/p/android-bluetooth/)。Android手机一般以客户端的角色主动连接SPP协议设备(接上蓝牙模块的数字传感器),连接流程是:
    1.使用registerReceiver注册BroadcastReceiver来获取蓝牙状态、搜索设备等消息;
    2.使用BlueAdatper的搜索;
    3.在BroadcastReceiver的onReceive()里取得搜索所得的蓝牙设备信息(如名称,MAC,RSSI);
    4.通过设备的MAC地址来建立一个BluetoothDevice对象;
    5.由BluetoothDevice衍生出BluetoothSocket,准备SOCKET来读写设备;
    6.通过Blue
    toothSocket的createRfcommSocketToServiceRecord()方法来选择连接的协议/服务,这里用的是SPP(UUID:00001101-0000-1000-8000-00805F9B34FB);
    7.Connect之后(如果还没配对则系统自动提示),使用BluetoothSocket的getInputStream()和getOutputStream()来读写蓝牙设备。
    Stringaction=intent.getAction();
    Bundleb=intent.getExtras();
    Object[]lstName=b.keySet().toArray();
    //显示所有收到的消息及其细节
    for(inti=0;i    StringkeyName=lstName[i].toString();
    Log.e(keyName,String.valueOf(b.get(keyName)));
    }
    Android提高第十三篇之探秘蓝牙隐藏API
    。用过Android系统设置(Setting)的人都知道蓝牙搜索之后可以建立配对和解除配对,但是这两项功能的函数没有在SDK中给出,那么如何去使用这两项功能呢?本文利用JAVA的反射机制去调用这两项功能对应的函数:createBond和removeBond,具体的发掘和实现步骤如下:
    1.使用Git工具下载platform/packages/apps/Settings.git,在Setting源码中查找关于建立配对和解除配对的API,知道这两个API的宿主(BluetoothDevice);
    2.使用反射机制对BluetoothDevice枚举其所有方法和常量,看看是否存在:
    staticpublicvoidprintAllInform(ClassclsShow){
    try{
    //取得所有方法
    Method[]hideMethod=clsShow.getMethods();
    inti=0;
    for(;i    Log.e("methodname",hideMethod[i].getName());
    }
    //取得所有常量
    Field[]allFields=clsShow.getFields();
    for(i=0;i    Log.e("Fieldname",allFields[i].getName());
    }
    }catch(SecurityExceptione){
    //thrownewRuntimeException(e.getMessage());
    e.printStackTrace();
    }catch(IllegalArgumentExceptione){
    //thrownewRuntimeException(e.getMessage());
    e.printStackTrace();
    }catch(Exceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    }
    /**
    *与设备配对参考源码:platform/packages/apps/Settings.git
    */Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
    */
    staticpublicbooleancreateBond(ClassbtClass,BluetoothDevicebtDevice)throwsException{
    MethodcreateBondMethod=btClass.getMethod("createBond"
    );
    BooleanreturnValue=(Boolean)createBondMethod.invoke(btDevice);
    returnreturnValue.booleanValue();
    }
    /**
    *与设备解除配对参考源码:platform/packages/apps/Settings.git
    */Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
    */
    staticpublicbooleanremoveBond(ClassbtClass,BluetoothDevicebtDevice)throwsException{
    MethodremoveBondMethod=btClass.getMethod("removeBond");
    BooleanreturnValue=(Boolean)removeBondMethod.invoke(btDevice);
    returnreturnValue.booleanValue();
    }
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_height="wrap_content"android:layout_width="fill_parent">
        android:text="Search"android:layout_width="160dip">
        android:layout_width="160dip"android:text="Show"android:id="@+id/btnShow">
    
        android:layout_width="wrap_content"android:layout_height="wrap_content">
,         android:layout_height="fill_parent">
    packagecom.testReflect;
    importjava.lang.reflect.Field;
    importjava.lang.reflect.Method;
    importandroid.bluetooth.BluetoothDevice;
    importandroid.util.Log;
    publicclassClsUtils{
    /**
    *与设备配对参考源码:platform/packages/apps/Settings.git
    */Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
    */
    staticpublicbooleancreateBond(ClassbtClass,BluetoothDevicebtDevice)throwsException{
    MethodcreateBondMethod=btClass.getMethod("createBond");
    BooleanreturnValue=(Boolean)createBondMethod.invoke(btDevice);
    returnreturnValue.booleanValue();
    }
    /**
    *与设备解除配对参考源码:platform/packages/apps/Settings.git
    */Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java
    */
    staticpublicbooleanremoveBond(ClassbtClass,BluetoothDevicebtDevice)throwsException{
    MethodremoveBondMethod=btClass.getMethod("removeBond");
    BooleanreturnValue=(Boolean)removeBondMethod.invoke(btDevice);
    returnreturnValue.booleanValue();
    }
    /**
    *
    *@paramclsShow
    */
    staticpublicvoidprintAllInform(ClassclsShow)
    {
    try{
    //取得所有方法
    Method[]hideMethod=clsShow.getMethods();
    inti=0;
    for(;i    Log.e("methodname",hideMethod[i].getName());
    }
    //取得所有常量
    Field[]allFields=clsShow.getFields();
    for(i=0;i    Log.e("Fieldname",allFields[i].getName());
    }
    }catch(SecurityExceptione){
    //thrownewRuntimeException(e.getMessage());
    e.printStackTrace();
    }catch(IllegalArgumentExceptione){
    //thrownewRuntimeException(e.getMessage());
    e.printStackTrace();
    }catch(Exceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    }
    }
    packagecom.testReflect;
    importjava.util.ArrayList;
    importjava.util.List;
    importandroid.app.Activity;
    importandroid.bluetooth.BluetoothAdapter;
    importandroid.bluetooth.BluetoothDevice;
    importandroid.content.BroadcastReceiver;
    importandroid.content.Context;
    importandroid.content.Intent;
    importandroid.content.IntentFilter;
    importandroid.os.Bundle;
    importandroid.util.Log;
    importandroid.view.View;
    importandroid.widget.AdapterView;
    importandroid.widget.ArrayAdapter;
    importandroid.widget.Button;
    importandroid.widget.ListView;
    importandroid.widget.Toast;
    publicclasstestReflectextendsActivity{
    ButtonbtnSearch,btnShow;
    ListViewlvBTDevices;
    ArrayAdapteradtDevices;
    ListlstDevices=newArrayList();
    BluetoothDevicebtDevice;
    BluetoothAdapterbtAdapt;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    btnSearch=(Button)this.findViewById(R.id.btnSearch);
    btnSearch.setOnClickListener(newClickEvent());
    btnShow=(Button)this.findViewById(R.id.btnShow);
    btnShow.setOnClickListener(newClickEvent());
    lvBTDevices=(ListView)this.findViewById(R.id.ListView01);
    adtDevices=newArrayAdapter(testReflect.this,
    android.R.layout.simple_list_item_1,lstDevices);
    lvBTDevices.setAdapter(adtDevices);
    lvBTDevices.setOnItemClickListener(newItemClickEvent());
    btAdapt=BluetoothAdapter.getDefaultAdapter();//初始化本机蓝牙功能
    if(btAdapt.getState()==BluetoothAdapter.STATE_OFF)//开蓝牙
    btAdapt.enable();
    //注册Receiver来获取蓝牙设备相关的结果
    IntentFilterintent=newIntentFilter();
    intent.addAction(BluetoothDevice.ACTION_FOUND);
    intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
    registerReceiver(searchDevices,intent);
    }
    
    privateBroadcastReceiversearchDevices=newBroadcastReceiver(){
    publicvoidonReceive(Contextcontext,Intentintent){
    Stringaction=intent.getAction();
    Bundleb=intent.getExtras();
    Object[]lstName=b.keySet().toArray();
    //显示所有收到的消息及其细节
    for(inti=0;i    StringkeyName=lstName[i].toString();
    Log.e(keyName,String.valueOf(b.get(keyName)));
    }
    //搜索设备时,取得设备的MAC地址
    if(BluetoothDevice.ACTION_FOUND.equals(action)){
    BluetoothDevicedevice=intent
    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
    if(device.getBondState()==BluetoothDevice.BOND_NONE){
    Stringstr="未配对|"+device.getName()+"|"+device.getAddress();
    lstDevices.add(str);//获取设备名称和mac地址
    adtDevices.notifyDataSetChanged();
    }
    }
    }
    };
    classItemClickEventimplementsAdapterView.OnItemClickListener{
    @Override
    publicvoidonItemClick(AdapterViewarg0,Viewarg1,intarg2,
    longarg3){
    btAdapt.cancelDiscovery();
    Stringstr=lstDevices.get(arg2);
    String[]values=str.split("//|");
    Stringaddress=values[2];
    btDevice=btAdapt.getRemoteDevice(address);
    try{
    if(values[0].equals("未配对"))
    {
    Toast.makeText(testReflect.this,"由未配对转为已配对",500).show();
    ClsUtils.createBond(btDevice.getClass(),btDevice);
    }
    elseif(values[0].equals("已配对"))
    {
    Toast.makeText(testReflect.this,"由已配对转为未配对",500).show();
    
    ClsUtils.removeBond(btDevice.getClass(),btDevice);
    }
    }catch(Exceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    }
    
    }
    
    /**
    *按键处理
    *@authorGV
    *
    */
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnSearch){//搜索附近的蓝牙设备
    lstDevices.clear();
    
    Object[]lstDevice=btAdapt.getBondedDevices().toArray();
    for(inti=0;i    BluetoothDevicedevice=(BluetoothDevice)lstDevice[i];
    Stringstr="已配对|"+device.getName()+"|"+device.getAddress();
    lstDevices.add(str);//获取设备名称和mac地址
    adtDevices.notifyDataSetChanged();
    }
    //开始搜索
    setTitle("本机蓝牙地址:"+btAdapt.getAddress());
    btAdapt.startDiscovery();
    }
    elseif(v==btnShow){//显示BluetoothDevice的所有方法和常量,包括隐藏API
    ClsUtils.printAllInform(btDevice.getClass());
    }
    }
    }
    }
    本文程序演示了以下功能:
    1.所有来电自动接听;
    2.所有来电自动挂断;
    3.开启/关闭Radio;
    4.开启/关闭数据连接(WAPorNET的连接)。
    调用TelephonyManager的隐藏API是先参考Framework的/base/telephony/java/com/android/internal/telephony/ITelephony.aidl,然后自己实现一个ITelephony.aidl,最后在TelephonyManager中通过反射机制实例化自定义的ITelephony,实例化之后就可以调用ITelephony里面的函数了。
    本文程序需要在AndroidManifest.xml添加以下两行代码,以获得权限:
    
    
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_width="fill_parent"android:id="@+id/rGrpSelect">
        android:layout_width="fill_parent"andro
    id:id="@+id/rbtnAutoAccept"
    android:text="所有来电自动接听">
        android:layout_width="fill_parent"android:id="@+id/rbtnAutoReject"
    android:text="所有来电自动挂断">
    
        android:layout_width="fill_parent"android:id="@+id/tbtnRadioSwitch"
    android:textOn="Radio已经启动"android:textOff="Radio已经关闭"
    android:textSize="24dip"android:textStyle="normal">
        android:layout_width="fill_parent"android:id="@+id/tbtnDataConn"
    android:textSize="24dip"android:textStyle="normal"android:textOn="允许数据连接"
    android:textOff="禁止数据连接">
    packagecom.testTelephony;
    importjava.lang.reflect.Field;
    importjava.lang.reflect.Method;
    importcom.android.internal.telephony.ITelephony;
    importandroid.telephony.TelephonyManager;
    importandroid.util.Log;
    publicclassPhoneUtils{
    /**
    *从TelephonyManager中实例化ITelephony,并返回
    */
    staticpublicITelephonygetITelephony(TelephonyManagertelMgr)throwsException{
    MethodgetITelephonyMethod=telMgr.getClass().getDeclaredMethod("getITelephony");
    getITelephonyMethod.setAccessible(true);//私有化函数也能使用
    return(ITelephony)getITelephonyMethod.invoke(telMgr);
    }
    
    staticpublicvoidprintAllInform(ClassclsShow){
    try{
    //取得所有方法
    Method[]hideMethod=clsShow.getDeclaredMethods();
    inti=0;
    for(;i    Log.e("methodname",hideMethod[i].getName());
    }
    //取得所有常量
    Field[]allFields=clsShow.getFields();
    for(i=0;i    Log.e("Fieldname",allFields[i].getName());
    }
    }catch(SecurityExceptione){
    //thrownewRuntimeException(e.getMessage());
    e.printStackTrace();
    }catch(IllegalArgumentExceptione){
    //thrownewRuntimeException(e.getMessage());
    e.printStackTrace();
    }catch(Exceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    }
    }
    packagecom.testTelephony;
    importandroid.app.Activity;
    importandroid.os.Bundle;
    importandroid.telephony.PhoneStateListener;
    importandroid.telephony.TelephonyManager;
    importandroid.util.Log;
    importandroid.view.View;
    importandroid.wi
    dget.RadioGroup;
    importandroid.widget.ToggleButton;
    publicclasstestTelephonyextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    RadioGrouprg;//来电操作单选框
    ToggleButtontbtnRadioSwitch;//Radio开关
    ToggleButtontbtnDataConn;//数据连接的开关
    TelephonyManagertelMgr;
    CallStateListenerstateListner;
    intcheckedId=0;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    telMgr=(TelephonyManager)getSystemService(TELEPHONY_SERVICE);
    telMgr.listen(newCallStateListener(),CallStateListener.LISTEN_CALL_STATE);
    
    PhoneUtils.printAllInform(TelephonyManager.class);
    
    rg=(RadioGroup)findViewById(R.id.rGrpSelect);
    rg.setOnCheckedChangeListener(newCheckEvent());
    tbtnRadioSwitch=(ToggleButton)this.findViewById(R.id.tbtnRadioSwitch);
    tbtnRadioSwitch.setOnClickListener(newClickEvent());
    try{
    tbtnRadioSwitch.setChecked(PhoneUtils.getITelephony(telMgr).isRadioOn());
    }catch(Exceptione){
    Log.e("error",e.getMessage());
    }
    tbtnDataConn=(ToggleButton)this.findViewById(R.id.tbtnDataConn);
    tbtnDataConn.setOnClickListener(newClickEvent());
    try{
    tbtnDataConn.setChecked(PhoneUtils.getITelephony(telMgr).isDataConnectivityPossible());
    }catch(Exceptione){
    Log.e("error",e.getMessage());
    }
    }
    
    /**
    *来电时的操作
    *@authorGV
    *
    */
    publicclassCheckEventimplementsRadioGroup.OnCheckedChangeListener{
    @Override
    publicvoidonCheckedChanged(RadioGroupgroup,intcheckedId){
    testTelephony.this.checkedId=checkedId;
    }
    }
    
    /**
    *Radio和数据连接的开关
    *@authorGV
    *
    */
    publicclassClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==tbtnRadioSwitch){
    try{
    PhoneUtils.getITelephony(telMgr).setRadio(tbtnRadioSwitch.isChecked());
    }catch(Exceptione){
    Log.e("error",e.getMessage());
    }
    }
    elseif(v==tbtnDataConn){
    try{
    if(
    tbtnDataConn.isChecked())
    PhoneUtils.getITelephony(telMgr).enableDataConnectivity();
    elseif(!tbtnDataConn.isChecked())
    PhoneUtils.getITelephony(telMgr).disableDataConnectivity();
    }catch(Exceptione){
    Log.e("error",e.getMessage());
    }
    }
    }
    }
    
    /**
    *监视电话状态
    *@authorGV
    *
    */
    publicclassCallStateListenerextendsPhoneStateListener{
    @Override
    publicvoidonCallStateChanged(intstate,StringincomingNumber){
    if(state==TelephonyManager.CALL_STATE_IDLE)//挂断
    {
    Log.e("IDLE",incomingNumber);
    }
    elseif(state==TelephonyManager.CALL_STATE_OFFHOOK)//接听
    {
    Log.e("OFFHOOK",incomingNumber);
    }
    elseif(state==TelephonyManager.CALL_STATE_RINGING)//来电
    {
    if(testTelephony.this.checkedId==R.id.rbtnAutoAccept)
    {
    try{
    //需要
    PhoneUtils.getITelephony(telMgr).silenceRinger();//静铃
    PhoneUtils.getITelephony(telMgr).answerRingingCall();//自动接听
    
    }catch(Exceptione){
    Log.e("error",e.getMessage());
    }
    }
    elseif(testTelephony.this.checkedId==R.id.rbtnAutoReject)
    {
    try{
    PhoneUtils.getITelephony(telMgr).endCall();//挂断
    PhoneUtils.getITelephony(telMgr).cancelMissedCallsNotification();//取消未接显示
    }catch(Exceptione){
    Log.e("error",e.getMessage());
    }
    }
    }
    super.onCallStateChanged(state,incomingNumber);
    }
    }
    }
    本帖最后由aishu于2012-3-1021:21编辑
    说说如何用ListView实现自适应的表格。GridView比ListView更容易实现自适应的表
    格,但是GridView每个格单元的大小固定,而ListView实现的表格可以自定义每个格单元的大小,但因此实现自适应表格也会复杂些(格单元大小不一)。另外,GridView实现的表格可以定位在具体某个格单元,而ListView实现的表格则只能定位在表格行。因此还是那句老话:根据具体的使用环境而选择GridView或者ListView实现表格
    本文实现的ListView表格,可以每个格单元大小不一,文本(TextView)或图片(ImageView)做格单元的数据,不需要预先定义XML实现样式(自适应的根本目标)。由于ListView置于HorizontalScrollView中,因此对于列比较多/列数据比较长的数据表也能很好地适应其宽度。main.xml源码如下
    
        android:orientation="vertical"android:layout_width="fill_parent"
    android:layout_height="fill_parent">
        android:layout_height="fill_parent"android:layout_width="fill_parent">
        android:layout_width="wrap_content">
    
    
    packagecom.testMyListView;
    importjava.util.ArrayList;
    importcom.testMyListView.TableAdapter.TableCell;
    importcom.testMyListView.TableAdapter.TableRow;
    importandroid.app.Activity;
    importandroid.os.Bundle;
    importandroid.view.View;
    importandroid.widget.AdapterView;
    importandroid.widget.ListView;
    importandroid.widget.LinearLayout.LayoutParams;
    importandroid.widget.Toast;
    /**
    *@authorhellogv
    */
    publicclasstestMyListViewextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ListViewlv;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    this.setTitle("ListView自适应实现表格---hellogv");
    lv=(ListView)this.findViewById(R.id.ListView01);
    ArrayList[table]
    table=newArrayList[table]
    ();
    TableCell[]titles=newTableCell[5];//每行5个单元
    intwidth=this.getWindowManager().getDefaultDisplay().getWidth()/titles.length;
    //定义标题
    for(inti=0;i    titles[i]=newTableCell("标题"+String.valueOf(i),
    width+8*i,
    LayoutParams.FILL_PARENT,
    TableCell.STRING);
    }
    table.add(newTableRow(titles));
    
    //每行的数据
    TableCell[]cells=newTableCell[5];//每行5个单元
    for(inti=0;i    cells[i]=newTableCell("No."+String.valueOf(i),
    titles[i].width,
    LayoutParams.FILL_PARENT,
    TableCell.STRING);
    }
    cells[cells.length-1]=newTableCell(R.drawable.icon,
    titles[cells.length-1].width,
    LayoutParams.WRAP_CONTENT,
    TableCell.IMAGE);
    //把表格的行添加到表格
    for(inti=0;i<12;i++)
    table.add(newTableRow(cells));
    TableAdaptertableAdapter=newTableAdapter(this,table);
    lv.setAdapter(tableAdapter);
    lv.setOnItemClickListener(newItemClickEvent());
    }
    classItemClickEventimplementsAdapterView.OnItemClickListener{
    @Override
    publicvoidonItemClick(AdapterViewarg0,Viewarg1,intarg2,
    longarg3){
    Toast.makeText(testMyListView.this,"选中第"+String.valueOf(arg2)+"行",500).show();
    }
    }
    }
    ListView自适应实现Table的类TableAdapter.java代码如下:PS:TableCell是格单元的类,TableRow是表格行的类,TableRowView是实现表格行的组件。实现步骤:TableCell-->TableRow(TableRowView)-->ListView
    packagecom.testMyListView;
    importjava.util.List;
    importandroid.content.Context;
    importandroid.graphics.Color;
    importandroid.view.Gravity;
    importandroid.view.View;
    importandroid.view.ViewGroup;
    importandroid.widget.BaseAdapter;
    importandroid.widget.ImageView;
    importandroid.widget.LinearLayout;
    importandroid.widget.TextView;
    publicclassTableAdapterextendsBaseAdapter{
    privateContextcontext;
    privateList[table]
    table;
    publicTableAdapter(Contextcontext,List[table]
    table){
    this.context=context;
    this.table=table;
    }
    @Override
    publicintgetCount(){
    returntable.size();
    }
    @Override
    publiclonggetItemId(intposition){
    returnposition;
    }
    publicTableRowgetItem(intposition){
    returntable.get(position);
    }
    publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
    Tabl
    eRowtableRow=table.get(position);
    returnnewTableRowView(this.context,tableRow);
    }
    /**
    *TableRowView实现表格行的样式
    *@authorhellogv
    */
    classTableRowViewextendsLinearLayout{
    publicTableRowView(Contextcontext,TableRowtableRow){
    super(context);
    
    this.setOrientation(LinearLayout.HORIZONTAL);
    for(inti=0;i    TableCelltableCell=tableRow.getCellValue(i);
    LinearLayout.LayoutParamslayoutParams=newLinearLayout.LayoutParams(
    tableCell.width,tableCell.height);//按照格单元指定的大小设置空间
    layoutParams.setMargins(0,0,1,1);//预留空隙制造边框
    if(tableCell.type==TableCell.STRING){//如果格单元是文本内容
    TextViewtextCell=newTextView(context);
    textCell.setLines(1);
    textCell.setGravity(Gravity.CENTER);
    textCell.setBackgroundColor(Color.BLACK);//背景黑色
    textCell.setText(String.valueOf(tableCell.value));
    addView(textCell,layoutParams);
    }elseif(tableCell.type==TableCell.IMAGE){//如果格单元是图像内容
    ImageViewimgCell=newImageView(context);
    imgCell.setBackgroundColor(Color.BLACK);//背景黑色
    imgCell.setImageResource((Integer)tableCell.value);
    addView(imgCell,layoutParams);
    }
    }
    this.setBackgroundColor(Color.WHITE);//背景白色,利用空隙来实现边框
    }
    }
    /**
    *TableRow实现表格的行
    *@authorhellogv
    */
    staticpublicclassTableRow{
    privateTableCell[]cell;
    publicTableRow(TableCell[]cell){
    this.cell=cell;
    }
    publicintgetSize(){
    returncell.length;
    }
    publicTableCellgetCellValue(intindex){
    if(index>=cell.length)
    returnnull;
    returncell[index];
    }
    }
    /**
    *TableCell实现表格的格单元
    *@authorhellogv
    */
    staticpublic
    classTableCell{
    staticpublicfinalintSTRING=0;
    staticpublicfinalintIMAGE=1;
    publicObjectvalue;
    publicintwidth;
    publicintheight;
    privateinttype;
    publicTableCell(Objectvalue,intwidth,intheight,inttype){
    this.value=value;
    this.width=width;
    this.height=height;
    this.type=type;
    }
    }
    }
    Android提高十六篇之使用NDK把彩图转换灰度图
    在Android上使用JAVA实现彩图转换为灰度图,跟J2ME上的实现类似,不过遇到频繁地转换或者是大图转换时,就必须使用NDK来提高速度了。本文主要通过JAVA和NDK这两种方式来分别实现彩图转换为灰度图,并给出速度的对比。
    先来简单地介绍一下Android的NDK使用步骤:
    以NDKr4为例,或许以后新版的NDK的使用方法略有不同。
    1、下载支持C++的android-ndk-r4-crystax,支持C++的话可玩性更强......
    2、下载cygwin,选择ftp://mirrors.kernel.org这个镜像,搜索DevelInstall安装gcc和make等工具;
    在搜索框里分别搜索gcc和make,必须是DevelInstall栏的。
    3、Cygwin安装目录下,找到home/username的目录下的.bash_profile文件,打开文件在最后加上:
    NDK=/cygdrive/d:cygwin/android-ndk-r4-crystax
    exportNDK
    PS:假设安装在D:/cygwin/android-ndk-r4-crystax。
    4、运行cygwin,通过cd命令去到NDK/samples/例子目录/,运行$NDK/ndk-build来编译该目录下的Android.mk
    以下是个人习惯.......
    5、安装Eclipse的CDT,官方下载cdt安装包,解压缩后把plugins和feagures复制覆盖到eclipse文件夹下即可
    6、去到系统属性->环境变量->Path添加"D:/cygwin/bin"(假设cygwin安装在D:下)和"D:/cygwin/android-ndk-r4-crystax",重启计算机,然后就可以在Eclipse里面建立基于cygwin的C/C++工程了,先通过这一步来验证NDK的程序能够编译成功,然后再通过第4步来生成SO文件。
    
    -
    
    
    
    
    packagecom.testToGray;
    importandroid.app.Activity;
    importandroid.graphics.Bitmap;
    importandroid.graphics.Bitmap.Config;
    importandroid.graphics.d
    rawable.BitmapDrawable;
    importandroid.os.Bundle;
    importandroid.view.View;
    importandroid.widget.Button;
    importandroid.widget.ImageView;
    publicclasstestToGrayextendsActivity{
    /**Calledwhentheactivityisfirstcreated.*/
    ButtonbtnJAVA,btnNDK;
    ImageViewimgView;
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    this.setTitle("使用NDK转换灰度图---hellogv");
    btnJAVA=(Button)this.findViewById(R.id.btnJAVA);
    btnJAVA.setOnClickListener(newClickEvent());
    
    btnNDK=(Button)this.findViewById(R.id.btnNDK);
    btnNDK.setOnClickListener(newClickEvent());
    imgView=(ImageView)this.findViewById(R.id.ImageView01);
    }
    classClickEventimplementsView.OnClickListener{
    @Override
    publicvoidonClick(Viewv){
    if(v==btnJAVA)
    {
    longcurrent=System.currentTimeMillis();
    Bitmapimg=ConvertGrayImg(R.drawable.cat);
    longperformance=System.currentTimeMillis()-current;
    //显示灰度图
    imgView.setImageBitmap(img);
    testToGray.this.setTitle("w:"+String.valueOf(img.getWidth())+",h:"+String.valueOf(img.getHeight())
    +"JAVA耗时"+String.valueOf(performance)+"毫秒");
    }
    elseif(v==btnNDK)
    {
    longcurrent=System.currentTimeMillis();
    
    //先打开图像并读取像素
    Bitmapimg1=((BitmapDrawable)getResources().getDrawable(R.drawable.cat)).getBitmap();
    intw=img1.getWidth(),h=img1.getHeight();
    int[]pix=newint[w*h];
    img1.getPixels(pix,0,w,0,0,w,h);
    //通过ImgToGray.so把彩色像素转为灰度像素
    int[]resultInt=LibFuns.ImgToGray(pix,w,h);
    BitmapresultImg=Bitmap.createBitmap(w,h,Config.RGB_565);
    resultImg.setPixels(resultInt,0,w,0,0,w,h);
    longperformance=System.currentTimeMillis()-current;
    //显示灰度图
    imgView.setImageBitmap(resultImg);
    testToGray.this.setTitle("w:"+String.valueOf(img1.getWidth())+",h:"+String.valueOf(img1.getHeight())
    +"NDK耗时"+String.valueOf(performance)+"毫秒");
    }
    }
    }
    
    /**
    
    *把资源图片转为灰度图
    *@paramresID资源ID
    *@return
    */
    publicBitmapConvertGrayImg(intresID)
    {
    Bitmapimg1=((BitmapDrawable)getResources().getDrawable(resID)).getBitmap();
    
    intw=img1.getWidth(),h=img1.getHeight();
    int[]pix=newint[w*h];
    img1.getPixels(pix,0,w,0,0,w,h);
    
    intalpha=0xFF<<24;
    for(inti=0;i    for(intj=0;j    //获得像素的颜色
    intcolor=pix[w*i+j];
    intred=((color&;0x00FF0000)>>16);
    intgreen=((color&;0x0000FF00)>>8);
    intblue=color&;0x000000FF;
    color=(red+green+blue)/3;
    color=alpha|(color<<16)|(color<<8)|color;
    pix[w*i+j]=color;
    }
    }
    Bitmapresult=Bitmap.createBitmap(w,h,Config.RGB_565);
    result.setPixels(pix,0,w,0,0,w,h);
    returnresult;
    }
    }
    封装NDK函数的JAVA类LibFuns.java的源码如下:
    packagecom.testToGray;
    publicclassLibFuns{
    static{
    System.loadLibrary("ImgToGray");
    }
    /**
    *@paramwidththecurrentviewwidth
    *@paramheightthecurrentviewheight
    */
    
    publicstaticnativeint[]ImgToGray(int[]buf,intw,inth);
    }
    彩图转换为灰度图的ImgToGray.cpp源码:
    #include
    #include
    #include
    extern"C"{
    JNIEXPORTjintArrayJNICALLJava_com_testToGray_LibFuns_ImgToGray(
    JNIEnv*env,jobjectobj,jintArraybuf,intw,inth);
    }
    ;
    JNIEXPORTjintArrayJNICALLJava_com_testToGray_LibFuns_ImgToGray(
    JNIEnv*env,jobjectobj,jintArraybuf,intw,inth){
    jint*cbuf;
    cbuf=env->GetIntArrayElements(buf,false);
    if(cbuf==NULL){
    return0;/*exceptionoccurred*/
    }
    intalpha=0xFF<<24;
    for(inti=0;i    for(intj=0;j    //获得像素的颜色
    intcolor=cbuf[w*i+j];
    intred=((color&;0x00FF0000)>>16);
    intgreen=((color&;0x0000FF00)>>8);
    intblue=color&;0x000000FF;
    color=(red+green+blue)/3;
    color=alpha|(color<<16)|(color<<8)|color;
    cbuf[w*i+j]=color;
    }
    }
    intsize=w*h;
    jintArrayresult=env->NewIntArray(size);
    env->SetIntArrayRegion(result,0,size,cbuf);
    env->ReleaseIntArrayElements(buf,cbuf,0);
    returnresult;
    }
    Android.mk的源码:
    LOCAL_PATH:=$(callmy-dir)
    include$(CLEAR_VARS)
    LOCAL_MODULE:=ImgToGray
    LOCAL_SRC_FILES:=ImgToGray.cpp
    include$(
    BUILD_SHARED_LIBRARY)
    Android提高第二十篇之MediaPlayer播放网络音频
    本文主要实现MediaPlayer在线播放音频的功能,由于在线视频播放比在线音频播放复杂,因此先介绍在线音频播放的实现,这样可以帮助大家逐步深入了解MediaPlayer的在线播放功能。
        android:layout_height="fill_parent"android:layout_width="fill_parent">
        android:layout_width="fill_parent"android:orientation="vertical"
    android:layout_gravity="top">
        android:layout_gravity="center_horizontal"android:layout_marginTop="4.0dip"
    android:layout_height="wrap_content"android:layout_width="wrap_content">
        android:layout_height="wrap_content"android:id="@+id/btnPlayUrl"
    android:text="播放网络音频">
        android:text="暂停"android:layout_width="80dip">
        android:layout_width="80dip"android:text="停止"android:id="@+id/btnStop">
    
        android:layout_width="fill_parent"android:layout_height="wrap_content"
    android:layout_marginBottom="20dip">
        android:paddingLeft="10dip"android:layout_weight="1.0"
    android:layout_height="wrap_content"android:layout_width="wrap_content"
    android:id="@+id/skbProgress"android:max="100">
    
    Player.java是本文的核心,Player.java实现了“进度条更新”、“数据缓冲”等功能,虽然不是很复杂的功能,但却是非常有用的功能。Player.java源码如下:
    packagecom.musicplayer;
    importjava.io.IOException;
    importjava.util.Timer;
    importjava.util.TimerTask;
    importandroid.media.AudioManager;
    importandroid.media.MediaPlayer;
    importandroid.media.MediaPlayer.OnBufferingUpdateListener;
    importandroid.media.MediaPlayer.OnCompletionListener;
    importandroid.os.Handler;
    importandroid.os.Message;
    importandroid.util.Log;
    importandroid.widget.SeekBar;
    publicclassPlayerimplementsOnBufferingUpdateListener,
    OnCompletionListener,MediaPlayer.OnPreparedListener{
    publicMediaPlayermediaPlayer;
    privateSeekBarskbP
    rogress;
    privateTimermTimer=newTimer();
    publicPlayer(SeekBarskbProgress)
    {
    this.skbProgress=skbProgress;
    
    try{
    mediaPlayer=newMediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setOnBufferingUpdateListener(this);
    mediaPlayer.setOnPreparedListener(this);
    }catch(Exceptione){
    Log.e("mediaPlayer","error",e);
    }
    
    mTimer.schedule(mTimerTask,0,1000);
    }
    
    /*******************************************************
    *通过定时器和Handler来更新进度条
    ******************************************************/
    TimerTaskmTimerTask=newTimerTask(){
    @Override
    publicvoidrun(){
    if(mediaPlayer==null)
    return;
    if(mediaPlayer.isPlaying()&;&;skbProgress.isPressed()==false){
    handleProgress.sendEmptyMessage(0);
    }
    }
    };
    
    HandlerhandleProgress=newHandler(){
    publicvoidhandleMessage(Messagemsg){
    intposition=mediaPlayer.getCurrentPosition();
    intduration=mediaPlayer.getDuration();
    
    if(duration>0){
    longpos=skbProgress.getMax()*position/duration;
    skbProgress.setProgress((int)pos);
    }
    };
    };
    //*****************************************************
    
    publicvoidplay()
    {
    mediaPlayer.start();
    }
    
    publicvoidplayUrl(StringvideoUrl)
    {
    try{
    mediaPlayer.reset();
    mediaPlayer.setDataSource(videoUrl);
    mediaPlayer.prepare();//prepare之后自动播放
    //mediaPlayer.start();
    }catch(IllegalArgumentExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IllegalStateExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IOExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    }
    
    publicvoidpause()
    {
    mediaPlayer.pause();
    }
    
    publicvoidstop()
    {
    if
    (mediaPlayer!=null){
    mediaPlayer.stop();
    mediaPlayer.release();
    mediaPlayer=null;
    }
    }
    @Override
    /**
    *通过onPrepared播放
    */
    publicvoidonPrepared(MediaPlayerarg0){
    arg0.start();
    Log.e("mediaPlayer","onPrepared");
    }
    @Override
    publicvoidonCompletion(MediaPlayerarg0){
    Log.e("mediaPlayer","onCompletion");
    }
    @Override
    publicvoidonBufferingUpdate(MediaPlayerarg0,intbufferingPro, gress){
    skbProgress.setSecondaryProgress(bufferingProgress);
    intcurrentProgress=skbProgress.getMax()*mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration();
    Log.e(currentProgress+"%play",bufferingProgress+"%buffer");
    }
    }
    test_musicplayer.java是主程序,负责调用Player类,其中关键部分是SeekBarChangeEvent这个SeekBar拖动的事件:SeekBar的Progress是0~SeekBar.getMax()之内的数,而MediaPlayer.seekTo()的参数是0~MediaPlayer.getDuration()之内数,所以MediaPlayer.seekTo()的参数是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()。test_musicplayer.java源码如下:
    packagecom.musicplayer;
    importandroid.app.Activity;
    importandroid.os.Bundle;
    importandroid.view.View;
    importandroid.view.View.OnClickListener;
    importandroid.widget.Button;
    importandroid.widget.SeekBar;
    publicclasstest_musicplayerextendsActivity{
    privateButtonbtnPause,btnPlayUrl,btnStop;
    privateSeekBarskbProgress;
    privatePlayerplayer;
    /**Calledwhentheactivityisfirstcreated.*/
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    this.setTitle("在线音乐播放---hellogv编写");
    btnPlayUrl=(Button)this.findViewById(R.id.btnPlayUrl);
    btnPlayUrl.setOnClickListener(newClickEvent());
    btnPause=(Button)this.findViewById(R.id.btnPause);
    btnPause.setOnClickListener(newClickEvent());
    btnStop=(Button)this.findViewById(R.id.btnStop);
    btnStop.setOnClickListener(newClickEvent());
    skbProgress=(SeekBar)this.findViewById(R.id.skbProgress);
    skbProgress.setOnSeekBarChangeListener(newSeekBarChangeEvent());
    player=newPlayer(skbProgress);
    }
    classClickEventimplementsOnClickListener{
    @Override
    publicvoidonClick(Viewarg0){
    if(arg0==btnPause){
    player.pause();
    }elseif(arg0==btnPlayUrl){
    /
    /在百度MP3里随便搜索到的,大家可以试试别的链接
    Stringurl="219.138.125.22/myweb/mp3/CMP3/JH19.MP3";
    player.playUrl(url);
    }elseif(arg0==btnStop){
    player.stop();
    }
    }
    }
    classSeekBarChangeEventimplementsSeekBar.OnSeekBarChangeListener{
    intprogress;
    @Override
    publicvoidonProgressChanged(SeekBarseekBar,intprogress,
    booleanfromUser){
    //原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()
    this.progress=progress*player.mediaPlayer.getDuration()
    /seekBar.getMax();
    }
    @Override
    publicvoidonStartTrackingTouch(SeekBarseekBar){
    }
    @Override
    publicvoidonStopTrackingTouch(SeekBarseekBar){
    //seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字
    player.mediaPlayer.seekTo(progress);
    }
    }
    }
    播放网络视频比播放网络音频多需要一个SurfaceView而已,已经熟悉MediaPlayer播放网络音频之后,相信大家对播放网络视频也能很快地掌握。
        android:layout_height="fill_parent"android:layout_width="fill_parent">
        android:layout_height="fill_parent"android:layout_width="fill_parent">
        android:layout_width="fill_parent"android:layout_gravity="bottom"
    android:orientation="vertical">
        android:layout_gravity="center_horizontal"android:layout_marginTop="4.0dip"
    android:layout_height="wrap_content"android:layout_width="wrap_content">
        android:layout_height="wrap_content"android:id="@+id/btnPlayUrl"
    android:text="播放网络视频">
        android:text="暂停"android:layout_width="80dip">
        android:layout_width="80dip"android:text="停止"android:id="@+id/btnStop">
    
        andro
    id:layout_width="fill_parent"android:layout_height="wrap_content"
    android:layout_marginBottom="20dip">
        android:paddingLeft="10dip"android:layout_weight="1.0"
    android:layout_height="wrap_content"android:layout_width="wrap_content"
    android:id="@+id/skbProgress"android:max="100">
    
    Player.java是本文的核心,Player.java实现了“进度条更新”、“数据缓冲”、“SurfaceHolder生命周期”等功能,其中“SurfaceHolder生命周期”是视频与音频播放的最大区别,通过surfaceCreated()、surfaceDestroyed()、surfaceChanged()可以创建/释放某些资源。下面这个地方需要注意一下:
    videoWidth=mediaPlayer.getVideoWidth();
    videoHeight=mediaPlayer.getVideoHeight();
    if(videoHeight!=0&;&;videoWidth!=0){
    arg0.start();
    }
    有些视频是android播放器不能播放的,不能播放时videoHeight=0,videoWidth=0,以此来判断是否播放视频。Player.java源码如下
    packagecom.videoplayer;
    importjava.io.IOException;
    importjava.util.Timer;
    importjava.util.TimerTask;
    importandroid.media.AudioManager;
    importandroid.media.MediaPlayer;
    importandroid.media.MediaPlayer.OnBufferingUpdateListener;
    importandroid.media.MediaPlayer.OnCompletionListener;
    importandroid.os.Handler;
    importandroid.os.Message;
    importandroid.util.Log;
    importandroid.view.SurfaceHolder;
    importandroid.view.SurfaceView;
    importandroid.widget.SeekBar;
    publicclassPlayerimplementsOnBufferingUpdateListener,
    OnCompletionListener,MediaPlayer.OnPreparedListener,
    SurfaceHolder.Callback{
    privateintvideoWidth;
    privateintvideoHeight;
    publicMediaPlayermediaPlayer;
    privateSurfaceHoldersurfaceHolder;
    privateSeekBarskbProgress;
    privateTimermTimer=newTimer();
    publicPlayer(SurfaceViewsurfaceView,SeekBarskbProgress)
    {
    this.skbProgress=skbProgress;
    surfaceHolder=surfaceView.getHolder();
    surfaceHolder.addCallback(this);
    surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mTimer.schedule(mTimerTask,0,1000);
    }
    
    /*******************************************************
    *通过定时器和Handler来更新进度条
    ******************************************************/
    TimerTaskmTimerTask=newTimerTask(){
    @Override
    publicvoidrun(){
    if(mediaPlayer==null)
    return;
    if(mediaPlayer.isPlaying()&;&;
    skbProgress.isPressed()==false){
    handleProgress.sendEmptyMessage(0);
    }
    }
    };
    
    HandlerhandleProgress=newHandler(){
    publicvoidhandleMessage(Messagemsg){
    intposition=mediaPlayer.getCurrentPosition();
    intduration=mediaPlayer.getDuration();
    
    if(duration>0){
    longpos=skbProgress.getMax()*position/duration;
    skbProgress.setProgress((int)pos);
    }
    };
    };
    //*****************************************************
    
    publicvoidplay()
    {
    mediaPlayer.start();
    }
    
    publicvoidplayUrl(StringvideoUrl)
    {
    try{
    mediaPlayer.reset();
    mediaPlayer.setDataSource(videoUrl);
    mediaPlayer.prepare();//prepare之后自动播放
    //mediaPlayer.start();
    }catch(IllegalArgumentExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IllegalStateExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }catch(IOExceptione){
    //TODOAuto-generatedcatchblock
    e.printStackTrace();
    }
    }
    
    publicvoidpause()
    {
    mediaPlayer.pause();
    }
    
    publicvoidstop()
    {
    if(mediaPlayer!=null){
    mediaPlayer.stop();
    mediaPlayer.release();
    mediaPlayer=null;
    }
    }
    
    @Override
    publicvoidsurfaceChanged(SurfaceHolderarg0,intarg1,intarg2,intarg3){
    Log.e("mediaPlayer","surfacechanged");
    }
    @Override
    publicvoidsurfaceCreated(SurfaceHolderarg0){
    try{
    mediaPlayer=newMediaPlayer();
    mediaPlayer.setDisplay(surfaceHolder);
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setOnBufferingUpdateListener(this);
    mediaPlayer.setOnPreparedListener(this);
    }catch(Exceptione){
    Log.e("mediaPlayer","error",e);
    }
    Log.e("mediaPlayer","surfacecreated");
    }
    @Override
    publicvoidsurfaceDestroyed(SurfaceHolderarg0){
    Log.e("mediaPlayer","surfacedestroyed");
    
    }
    
    @Override
    /**
    *通过onPrepared播放
    */
    publicvoidonPrepared(MediaPlayerarg0){
    videoWidth=mediaPlayer.getVideoWidth();
    videoHeight=mediaPlayer.getVideoHeight();
    if(videoHeight!=0&;&;videoWidth!=0){
    arg0.start();
    }
    Log.e("mediaPlayer","onPrepared");
    }
    @Override
    publicvoidonCompletion(MediaPlayerarg0){
    //TODOAuto-generatedmethodstub
    
    }
    @Override
    publicvoidonBufferingUpdate(MediaPlayerarg0,intbufferingProgress){
    skbProgress.setSecondaryProgress(bufferingProgress);
    intcurrentProgress=skbProgress.getMax()*mediaPlayer.getCurrentPosition()/mediaPlayer.getDuration();
    Log.e(currentProgress+"%play",bufferingProgress+"%buffer");
    
    }
    }
    test_videoplayer.java是主程序,负责调用Player类,其中关键部分是SeekBarChangeEvent这个SeekBar拖动的事件:SeekBar的Progress是0~SeekBar.getMax()之内的数,而MediaPlayer.seekTo()的参数是0~MediaPlayer.getDuration()之内数,所以MediaPlayer.seekTo()的参数是(progress/seekBar.getMax())*MediaPlayer.getDuration()。test_videoplayer.java源码如下:
    packagecom.videoplayer;
    importandroid.app.Activity;
    importandroid.content.pm.ActivityInfo;
    importandroid.net.Uri;
    importandroid.os.Bundle;
    importandroid.util.Log;
    importandroid.view.SurfaceView;
    importandroid.view.View;
    importandroid.view.View.OnClickListener;
    importandroid.widget.Button;
    importandroid.widget.SeekBar;
    publicclasstest_videoplayerextendsActivity{
    privateSurfaceViewsurfaceView;
    privateButtonbtnPause,btnPlayUrl,btnStop;
    privateSeekBarskbProgress;
    privatePlayerplayer;
    /**Calledwhentheactivityisfirstcreated.*/
    @Override
    publicvoidonCreate(BundlesavedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
    surfaceView=(SurfaceView)this.findViewById(R.id.surfaceView1);
    btnPlayUrl=(Button)this.findViewById(R.id.btnPlayUrl);
    btnPlayUrl.setOnClickListener(newClickEvent());
    btnPause=(Button)this.findViewById(R.id.btnPause);
    btnPause.setOnClickListener(newClickEvent());
    btnStop=(Button)this.findViewById(R.id.btnStop);
    btnStop.setOnClickListener(newClickEvent());
    skbProgress=(SeekBar)this.findViewById(R.id.skbProgress);
    skbProgress.setOnSeekBarChangeListener(newSeekBarChangeEvent());
    player=newPlayer(surfaceView,s
    kbProgress);
    }
    classClickEventimplementsOnClickListener{
    @Override
    publicvoidonClick(Viewarg0){
    if(arg0==btnPause){
    player.pause();
    }elseif(arg0==btnPlayUrl){
    Stringurl="daily3gp/vids/family_guy_penis_car.3gp";
    player.playUrl(url);
    }elseif(arg0==btnStop){
    player.stop();
    }
    }
    }
    classSeekBarChangeEventimplementsSeekBar.OnSeekBarChangeListener{
    intprogress;
    @Override
    publicvoidonProgressChanged(SeekBarseekBar,intprogress,
    booleanfromUser){
    //原本是(progress/seekBar.getMax())*player.mediaPlayer.getDuration()
    this.progress=progress*player.mediaPlayer.getDuration()
    /seekBar.getMax();
    }
    @Override
    publicvoidonStartTrackingTouch(SeekBarseekBar){
    }
    @Override
    publicvoidonStopTrackingTouch(SeekBarseekBar){
    //seekTo()的参数是相对与影片时间的数字,而不是与seekBar.getMax()相对的数字
    player.mediaPlayer.seekTo(progress);
    }
    }
    }
    
    
  • 上一篇资讯: Android入门扫盲之一
  • 网学推荐

    免费论文

    原创论文

    浏览:
    设为首页 | 加入收藏 | 论文首页 | 论文专题 | 设计下载 | 网学软件 | 论文模板 | 论文资源 | 程序设计 | 关于网学 | 站内搜索 | 网学留言 | 友情链接 | 资料中心
    版权所有 QQ:3710167 邮箱:3710167@qq.com 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2015 myeducs.Cn www.myeducs.Cn All Rights Reserved
    湘ICP备09003080号