【Android提高篇】一个朋友的学习笔记(已更新至第十三篇之探秘蓝牙隐藏API)

soso   2010-11-18 10:33 楼主

Android提高第一篇之MediaPlayer

本文来自http://blog.csdn.net/hellogv/          

 

前面写了十四篇关于界面的入门文章,大家都看完和跟着练习之后,对于常用的Layout和View都会有一定的了解了,接下来的文章就不再强调介绍界面了,而是针对具体的常见功能而展开。         

本文介绍MediaPlayer的使用。MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoView 比MediaPlayer简单易用,但定制性不如用MediaPlayer,要视情况选择了。MediaPlayer播放音频比较简单,但是要播放视频就需要SurfaceView。SurfaceView比普通的自定义View更有绘图上的优势,它支持完全的OpenGL ES库。         

 

先贴出本文程序运行结果的截图,上面是播放/停止音频,可用SeekBar来调进度,下面是播放/停止视频,也是用SeekBar来调进度:   0_1288409460hFp8.gif.jpg main.xml的源码:

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout android:id="@+id/LinearLayout01"  
  3.     android:layout_width="fill_parent" android:layout_height="fill_parent"  
  4.     xmlns:android="http://schemas.android.com/apk/res/android"  
  5.     android:orientation="vertical">  
  6.     <SeekBar android:id="@+id/SeekBar01" android:layout_height="wrap_content"  
  7.         android:layout_width="fill_parent"></SeekBar>  
  8.     <LinearLayout android:id="@+id/LinearLayout02"  
  9.         android:layout_width="wrap_content" android:layout_height="wrap_content">  
  10.         <Button android:id="@+id/Button01" android:layout_width="wrap_content"  
  11.             android:layout_height="wrap_content" android:text="播放音频"></Button>  
  12.         <Button android:id="@+id/Button02" android:layout_width="wrap_content"  
  13.             android:layout_height="wrap_content" android:text="停止播放"></Button>  
  14.     </LinearLayout>  
  15.     <SeekBar android:id="@+id/SeekBar02" android:layout_height="wrap_content"  
  16.         android:layout_width="fill_parent"></SeekBar>  
  17.   
  18.     <SurfaceView android:id="@+id/SurfaceView01"  
  19.         android:layout_width="fill_parent" android:layout_height="250px"></SurfaceView>  
  20.     <LinearLayout android:id="@+id/LinearLayout02"  
  21.         android:layout_width="wrap_content" android:layout_height="wrap_content">  
  22.         <Button android:layout_width="wrap_content"  
  23.             android:layout_height="wrap_content" android:id="@+id/Button03"  
  24.             android:text="播放视频"></Button>  
  25.         <Button android:layout_width="wrap_content"  
  26.             android:layout_height="wrap_content" android:text="停止播放" android:id="@+id/Button04"></Button>  
  27.     </LinearLayout>  
  28. </LinearLayout>  

本文程序的源码,有点长:

  1. package com.testMedia;  
  2.   
  3. import java.io.IOException;    
  4. import java.util.Timer;  
  5. import java.util.TimerTask;  
  6. import android.app.Activity;    
  7. import android.media.AudioManager;  
  8. import android.media.MediaPlayer;  
  9. import android.os.Bundle;    
  10. import android.view.SurfaceHolder;  
  11. import android.view.SurfaceView;  
  12. import android.view.View;    
  13. import android.widget.Button;    
  14. import android.widget.SeekBar;  
  15. import android.widget.Toast;    
  16.   
  17.   
  18. public class testMedia extends Activity {  
  19.       /** Called when the activity is first created. */   
  20.   
  21.     private SeekBar skb_audio=null;  
  22.     private Button btn_start_audio = null;    
  23.     private Button btn_stop_audio = null;  
  24.   
  25.     private SeekBar skb_video=null;  
  26.     private Button btn_start_video = null;    
  27.     private Button btn_stop_video = null;  
  28.     private SurfaceView surfaceView;   
  29.     private SurfaceHolder surfaceHolder;   
  30.       
  31.     private MediaPlayer m = null;    
  32.     private Timer mTimer;  
  33.     private TimerTask mTimerTask;  
  34.       
  35.     private boolean isChanging=false;//互斥变量,防止定时器与SeekBar拖动时进度冲突  
  36.      @Override    
  37.     public void onCreate(Bundle savedInstanceState) {    
  38.         super.onCreate(savedInstanceState);    
  39.         setContentView(R.layout.main);    
  40.           
  41.         //----------Media控件设置---------//  
  42.         m=new MediaPlayer();  
  43.           
  44.         //播放结束之后弹出提示  
  45.         m.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){  
  46.             @Override  
  47.             public void onCompletion(MediaPlayer arg0) {  
  48.                 Toast.makeText(testMedia.this"结束"1000).show();  
  49.                 m.release();  
  50.             }  
  51.         });  
  52.           
  53.       //----------定时器记录播放进度---------//  
  54.         mTimer = new Timer();  
  55.         mTimerTask = new TimerTask() {  
  56.             @Override  
  57.             public void run() {   
  58.                 if(isChanging==true)  
  59.                     return;  
  60.                   
  61.                 if(m.getVideoHeight()==0)  
  62.                     skb_audio.setProgress(m.getCurrentPosition());  
  63.                 else   
  64.                     skb_video.setProgress(m.getCurrentPosition());  
  65.             }  
  66.         };  
  67.   
  68.         mTimer.schedule(mTimerTask, 010);  
  69.           
  70.         btn_start_audio = (Button) this.findViewById(R.id.Button01);    
  71.         btn_stop_audio = (Button) this.findViewById(R.id.Button02);    
  72.         btn_start_audio.setOnClickListener(new ClickEvent());  
  73.         btn_stop_audio.setOnClickListener(new ClickEvent());  
  74.         skb_audio=(SeekBar)this.findViewById(R.id.SeekBar01);  
  75.         skb_audio.setOnSeekBarChangeListener(new SeekBarChangeEvent());  
  76.           
  77.         btn_start_video = (Button) this.findViewById(R.id.Button03);    
  78.         btn_stop_video = (Button) this.findViewById(R.id.Button04);    
  79.         btn_start_video.setOnClickListener(new ClickEvent());  
  80.         btn_stop_video.setOnClickListener(new ClickEvent());  
  81.         skb_video=(SeekBar)this.findViewById(R.id.SeekBar02);  
  82.         skb_video.setOnSeekBarChangeListener(new SeekBarChangeEvent());  
  83.         surfaceView = (SurfaceView) findViewById(R.id.SurfaceView01);  
  84.         surfaceHolder = surfaceView.getHolder();  
  85.         surfaceHolder.setFixedSize(100100);  
  86.         surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  87.     }    
  88.        
  89.   /* 
  90.    * 按键事件处理 
  91.    */  
  92.   class ClickEvent implements View.OnClickListener{  
  93.     @Override  
  94.     public void onClick(View v) {  
  95.         if(v==btn_start_audio)  
  96.         {  
  97.             m.reset();//恢复到未初始化的状态  
  98.             m=MediaPlayer.create(testMedia.this, R.raw.big);//读取音频  
  99.             skb_audio.setMax(m.getDuration());//设置SeekBar的长度  
  100.             try {                     
  101.                 m.prepare();    //准备  
  102.             } catch (IllegalStateException e) {           
  103.                 // TODO Auto-generated catch block                
  104.                 e.printStackTrace();                  
  105.             } catch (IOException e) {             
  106.                 // TODO Auto-generated catch block                
  107.                 e.printStackTrace();                  
  108.             }         
  109.             m.start();  //播放  
  110.         }  
  111.         else if(v==btn_stop_audio || v==btn_stop_video)  
  112.         {  
  113.             m.stop();  
  114.         }  
  115.         else if(v==btn_start_video)  
  116.         {  
  117.             m.reset();//恢复到未初始化的状态  
  118.             m=MediaPlayer.create(testMedia.this, R.raw.test);//读取视频  
  119.             skb_video.setMax(m.getDuration());//设置SeekBar的长度  
  120.             m.setAudioStreamType(AudioManager.STREAM_MUSIC);  
  121.             m.setDisplay(surfaceHolder);//设置屏幕  
  122.               
  123.             try {  
  124.                 m.prepare();  
  125.                   
  126.             } catch (IllegalArgumentException e) {  
  127.                 // TODO Auto-generated catch block  
  128.                 e.printStackTrace();  
  129.             } catch (IllegalStateException e) {  
  130.                 // TODO Auto-generated catch block  
  131.                 e.printStackTrace();  
  132.             } catch (IOException e) {  
  133.                 // TODO Auto-generated catch block  
  134.                 e.printStackTrace();  
  135.             }  
  136.             m.start();  
  137.         }  
  138.     }  
  139.   }  
  140.     
  141.   /* 
  142.    * SeekBar进度改变事件 
  143.    */  
  144.   class SeekBarChangeEvent implements SeekBar.OnSeekBarChangeListener{  
  145.   
  146.     @Override  
  147.     public void onProgressChanged(SeekBar seekBar, int progress,  
  148.             boolean fromUser) {  
  149.         // TODO Auto-generated method stub  
  150.           
  151.     }  
  152.   
  153.     @Override  
  154.     public void onStartTrackingTouch(SeekBar seekBar) {  
  155.         isChanging=true;  
  156.     }  
  157.   
  158.     @Override  
  159.     public void onStopTrackingTouch(SeekBar seekBar) {  
  160.         m.seekTo(seekBar.getProgress());  
  161.         isChanging=false;     
  162.     }  
  163.         
  164.   }  
  165.   
  166. }  
加油!在电子行业默默贡献自己的力量!:)

回复评论 (22)

Android提高第二篇之SurfaceView(上)

上次介绍MediaPlayer的时候稍微介绍了SurfaceView,SurfaceView由于可以直接从内存或者DMA等硬件接口取得图像数据,因此是个非常重要的绘图容器,这次我就用两篇文章来介绍SurfaceView的用法。网上介绍SurfaceView的用法有很多,写法也层出不同,例如继承SurfaceView类,或者继承SurfaceHolder.Callback类等,这个可以根据功能实际需要自己选择,我这里就直接在普通的用户界面调用 SurfaceHolder的lockCanvas和unlockCanvasAndPost。

        先来看看程序运行的截图:

1.jpg

截图1主要演示了直接把正弦波绘画在SurfaceView上

2.gif 3.gif

 

对比上面的左右两图,右图用.lockCanvas(null),而左图用.lockCanvas(new Rect(oldX, 0, oldX + length,
    getWindowManager().getDefaultDisplay().getHeight())),对比一下两个效果,由于左图是按指定Rect绘画,所以效率会比右图的全控件绘画高些,并且在清屏之后 (canvas.drawColor(Color.BLACK))不会留有上次绘画的残留。

 

接下来贴出main.xml的源码:

 

  • ?xml version="1.0" encoding="utf-8"?>  
  • <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  •     android:layout_width="fill_parent" android:layout_height="fill_parent"  
  •     android:orientation="vertical">  
  •   
  •     <LinearLayout android:id="@+id/LinearLayout01"  
  •         android:layout_width="wrap_content" android:layout_height="wrap_content">  
  •         <Button android:id="@+id/Button01" android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content" android:text="简单绘画"></Button>  
  •         <Button android:id="@+id/Button02" android:layout_width="wrap_content"  
  •             android:layout_height="wrap_content" android:text="定时器绘画"></Button>  
  •     </LinearLayout>  
  •     <SurfaceView android:id="@+id/SurfaceView01"  
  •         android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView>  
  • </LinearLayout>  

     

    接下来贴出程序源码:

    1. package com.testSurfaceView;  
    2.   
    3. import java.util.Timer;  
    4. import java.util.TimerTask;  
    5.   
    6. import android.app.Activity;  
    7. import android.graphics.Canvas;  
    8. import android.graphics.Color;  
    9. import android.graphics.Paint;  
    10. import android.graphics.Rect;  
    11. import android.os.Bundle;  
    12. import android.util.Log;  
    13. import android.view.SurfaceHolder;  
    14. import android.view.SurfaceView;  
    15. import android.view.View;  
    16. import android.widget.Button;  
    17.   
    18. public class testSurfaceView extends Activity {  
    19.     /** Called when the activity is first created. */  
    20.     Button btnSimpleDraw, btnTimerDraw;  
    21.     SurfaceView sfv;  
    22.     SurfaceHolder sfh;  
    23.   
    24.     private Timer mTimer;  
    25.     private MyTimerTask mTimerTask;  
    26.     int Y_axis[],//保存正弦波的Y轴上的点  
    27.     centerY,//中心线  
    28.     oldX,oldY,//上一个XY点   
    29.     currentX;//当前绘制到的X轴上的点  
    30.   
    31.     @Override  
    32.     public void onCreate(Bundle savedInstanceState) {  
    33.         super.onCreate(savedInstanceState);  
    34.         setContentView(R.layout.main);  
    35.   
    36.         btnSimpleDraw = (Button) this.findViewById(R.id.Button01);  
    37.         btnTimerDraw = (Button) this.findViewById(R.id.Button02);  
    38.         btnSimpleDraw.setOnClickListener(new ClickEvent());  
    39.         btnTimerDraw.setOnClickListener(new ClickEvent());  
    40.         sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);  
    41.         sfh = sfv.getHolder();  
    42.   
    43.         //动态绘制正弦波的定时器  
    44.         mTimer = new Timer();  
    45.         mTimerTask = new MyTimerTask();  
    46.   
    47.         // 初始化y轴数据  
    48.         centerY = (getWindowManager().getDefaultDisplay().getHeight() - sfv  
    49.                 .getTop()) / 2;  
    50.         Y_axis = new int[getWindowManager().getDefaultDisplay().getWidth()];  
    51.         for (int i = 1; i < Y_axis.length; i++) {// 计算正弦波  
    52.             Y_axis[i - 1] = centerY  
    53.                     - (int) (100 * Math.sin(i * 2 * Math.PI / 180));  
    54.         }  
    55.     }  
    56.   
    57.     class ClickEvent implements View.OnClickListener {  
    58.   
    59.         @Override  
    60.         public void onClick(View v) {  
    61.   
    62.             if (v == btnSimpleDraw) {  
    63.                 SimpleDraw(Y_axis.length-1);//直接绘制正弦波  
    64.               
    65.             } else if (v == btnTimerDraw) {  
    66.                 oldY = centerY;  
    67.                 mTimer.schedule(mTimerTask, 05);//动态绘制正弦波  
    68.             }  
    69.   
    70.         }  
    71.   
    72.     }  
    73.   
    74.     class MyTimerTask extends TimerTask {  
    75.         @Override  
    76.         public void run() {  
    77.   
    78.             SimpleDraw(currentX);  
    79.             currentX++;//往前进  
    80.             if (currentX == Y_axis.length - 1) {//如果到了终点,则清屏重来  
    81.                 ClearDraw();  
    82.                 currentX = 0;  
    83.                 oldY = centerY;  
    84.             }  
    85.         }  
    86.   
    87.     }  
    88.       
    89.     /* 
    90.      * 绘制指定区域 
    91.      */  
    92.     void SimpleDraw(int length) {  
    93.         if (length == 0)  
    94.             oldX = 0;  
    95.         Canvas canvas = sfh.lockCanvas(new Rect(oldX, 0, oldX + length,  
    96.                 getWindowManager().getDefaultDisplay().getHeight()));// 关键:获取画布  
    97.         Log.i("Canvas:",  
    98.                 String.valueOf(oldX) + "," + String.valueOf(oldX + length));  
    99.   
    100.         Paint mPaint = new Paint();  
    101.         mPaint.setColor(Color.GREEN);// 画笔为绿色  
    102.         mPaint.setStrokeWidth(2);// 设置画笔粗细  
    103.   
    104.         int y;  
    105.         for (int i = oldX + 1; i < length; i++) {// 绘画正弦波  
    106.             y = Y_axis[i - 1];  
    107.             canvas.drawLine(oldX, oldY, i, y, mPaint);  
    108.             oldX = i;  
    109.             oldY = y;  
    110.         }  
    111.         sfh.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像  
    112.     }  
    113.   
    114.     void ClearDraw() {  
    115.         Canvas canvas = sfh.lockCanvas(null);  
    116.         canvas.drawColor(Color.BLACK);// 清除画布  
    117.         sfh.unlockCanvasAndPost(canvas);  
    118.   
    119.     }  
    120. }  

    注意一下 for (int i = oldX + 1; i < length; i++) {// 绘画正弦波 这句,在.lockCanvas()指定Rect内减少循环画线的次数,可以提高绘图效率。

     

  • 加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 10:41

    Android提高第三篇之SurfaceView(下)

      上一篇简单介绍了SurfaceView的使用,这次就介绍SurfaceView的双缓冲使用。双缓冲是为了防止动画闪烁而实现的一种多线程应用,基于 SurfaceView的双缓冲实现很简单,开一条线程并在其中绘图即可。本文介绍基于SurfaceView的双缓冲实现,以及介绍类似的更高效的实现方法。

            本文程序运行截图如下,左边是开单个线程读取并绘图,右边是开两个线程,一个专门读取图片,一个专门绘图:

    2.gif

    对比一下,右边动画的帧速明显比左边的快,左右两者都没使用Thread.sleep()。为什么要开两个线程一个读一个画,而不去开两个线程像左边那样都 “边读边画”呢?因为SurfaceView每次绘图都会锁定Canvas,也就是说同一片区域这次没画完下次就不能画,因此要提高双缓冲的效率,就得开一条线程专门画图,开另外一条线程做预处理的工作。

    main.xml的源码:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="fill_parent" android:layout_height="fill_parent"  
    4.     android:orientation="vertical">  
    5.   
    6.     <LinearLayout android:id="@+id/LinearLayout01"  
    7.         android:layout_width="wrap_content" android:layout_height="wrap_content">  
    8.         <Button android:id="@+id/Button01" android:layout_width="wrap_content"  
    9.             android:layout_height="wrap_content" android:text="单个独立线程"></Button>  
    10.         <Button android:id="@+id/Button02" android:layout_width="wrap_content"  
    11.             android:layout_height="wrap_content" android:text="两个独立线程"></Button>  
    12.     </LinearLayout>  
    13.     <SurfaceView android:id="@+id/SurfaceView01"  
    14.         android:layout_width="fill_parent" android:layout_height="fill_parent"></SurfaceView>  
    15. </LinearLayout>  

    本文程序的源码:

    1. package com.testSurfaceView;  
    2.   
    3. import java.lang.reflect.Field;  
    4. import java.util.ArrayList;  
    5. import android.app.Activity;  
    6. import android.graphics.Bitmap;  
    7. import android.graphics.BitmapFactory;  
    8. import android.graphics.Canvas;  
    9. import android.graphics.Paint;  
    10. import android.graphics.Rect;  
    11. import android.os.Bundle;  
    12. import android.util.Log;  
    13. import android.view.SurfaceHolder;  
    14. import android.view.SurfaceView;  
    15. import android.view.View;  
    16. import android.widget.Button;  
    17.   
    18. public class testSurfaceView extends Activity {  
    19.     /** Called when the activity is first created. */  
    20.     Button btnSingleThread, btnDoubleThread;  
    21.     SurfaceView sfv;  
    22.     SurfaceHolder sfh;  
    23.     ArrayList<Integer> imgList = new ArrayList<Integer>();  
    24.     int imgWidth, imgHeight;  
    25.     Bitmap bitmap;//独立线程读取,独立线程绘图  
    26.   
    27.     @Override  
    28.     public void onCreate(Bundle savedInstanceState) {  
    29.         super.onCreate(savedInstanceState);  
    30.         setContentView(R.layout.main);  
    31.   
    32.         btnSingleThread = (Button) this.findViewById(R.id.Button01);  
    33.         btnDoubleThread = (Button) this.findViewById(R.id.Button02);  
    34.         btnSingleThread.setOnClickListener(new ClickEvent());  
    35.         btnDoubleThread.setOnClickListener(new ClickEvent());  
    36.         sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);  
    37.         sfh = sfv.getHolder();  
    38.         sfh.addCallback(new MyCallBack());// 自动运行surfaceCreated以及surfaceChanged  
    39.     }  
    40.   
    41.     class ClickEvent implements View.OnClickListener {  
    42.   
    43.         @Override  
    44.         public void onClick(View v) {  
    45.   
    46.             if (v == btnSingleThread) {  
    47.                 new Load_DrawImage(00).start();//开一条线程读取并绘图  
    48.             } else if (v == btnDoubleThread) {  
    49.                 new LoadImage().start();//开一条线程读取  
    50.                 new DrawImage(imgWidth + 100).start();//开一条线程绘图  
    51.             }  
    52.   
    53.         }  
    54.   
    55.     }  
    56.   
    57.     class MyCallBack implements SurfaceHolder.Callback {  
    58.   
    59.         @Override  
    60.         public void surfaceChanged(SurfaceHolder holder, int format, int width,  
    61.                 int height) {  
    62.             Log.i("Surface:""Change");  
    63.   
    64.         }  
    65.   
    66.         @Override  
    67.         public void surfaceCreated(SurfaceHolder holder) {  
    68.             Log.i("Surface:""Create");  
    69.   
    70.             // 用反射机制来获取资源中的图片ID和尺寸  
    71.             Field[] fields = R.drawable.class.getDeclaredFields();  
    72.             for (Field field : fields) {  
    73.                 if (!"icon".equals(field.getName()))// 除了icon之外的图片  
    74.                 {  
    75.                     int index = 0;  
    76.                     try {  
    77.                         index = field.getInt(R.drawable.class);  
    78.                     } catch (IllegalArgumentException e) {  
    79.                         // TODO Auto-generated catch block  
    80.                         e.printStackTrace();  
    81.                     } catch (IllegalAccessException e) {  
    82.                         // TODO Auto-generated catch block  
    83.                         e.printStackTrace();  
    84.                     }  
    85.                     // 保存图片ID  
    86.                     imgList.add(index);  
    87.                 }  
    88.             }  
    89.             // 取得图像大小  
    90.             Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
    91.                     imgList.get(0));  
    92.             imgWidth = bmImg.getWidth();  
    93.             imgHeight = bmImg.getHeight();  
    94.         }  
    95.   
    96.         @Override  
    97.         public void surfaceDestroyed(SurfaceHolder holder) {  
    98.             Log.i("Surface:""Destroy");  
    99.   
    100.         }  
    101.   
    102.     }  
    103.   
    104.     /* 
    105.      * 读取并显示图片的线程 
    106.      */  
    107.     class Load_DrawImage extends Thread {  
    108.         int x, y;  
    109.         int imgIndex = 0;  
    110.   
    111.         public Load_DrawImage(int x, int y) {  
    112.             this.x = x;  
    113.             this.y = y;  
    114.         }  
    115.   
    116.         public void run() {  
    117.             while (true) {  
    118.                 Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  
    119.                         + imgWidth, this.y + imgHeight));  
    120.                 Bitmap bmImg = BitmapFactory.decodeResource(getResources(),  
    121.                         imgList.get(imgIndex));  
    122.                 c.drawBitmap(bmImg, this.x, this.y, new Paint());  
    123.                 imgIndex++;  
    124.                 if (imgIndex == imgList.size())  
    125.                     imgIndex = 0;  
    126.   
    127.                 sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  
    128.             }  
    129.         }  
    130.     };  
    131.   
    132.     /* 
    133.      * 只负责绘图的线程 
    134.      */  
    135.     class DrawImage extends Thread {  
    136.         int x, y;  
    137.   
    138.         public DrawImage(int x, int y) {  
    139.             this.x = x;  
    140.             this.y = y;  
    141.         }  
    142.   
    143.         public void run() {  
    144.             while (true) {  
    145.                 if (bitmap != null) {//如果图像有效  
    146.                     Canvas c = sfh.lockCanvas(new Rect(this.x, this.y, this.x  
    147.                             + imgWidth, this.y + imgHeight));  
    148.   
    149.                     c.drawBitmap(bitmap, this.x, this.y, new Paint());  
    150.   
    151.                     sfh.unlockCanvasAndPost(c);// 更新屏幕显示内容  
    152.                 }  
    153.             }  
    154.         }  
    155.     };  
    156.   
    157.     /* 
    158.      * 只负责读取图片的线程 
    159.      */  
    160.     class LoadImage extends Thread {  
    161.         int imgIndex = 0;  
    162.   
    163.         public void run() {  
    164.             while (true) {  
    165.                 bitmap = BitmapFactory.decodeResource(getResources(),  
    166.                         imgList.get(imgIndex));  
    167.                 imgIndex++;  
    168.                 if (imgIndex == imgList.size())//如果到尽头则重新读取  
    169.                     imgIndex = 0;  
    170.             }  
    171.         }  
    172.     };  
    173. }  
    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 10:44

    Android提高第四篇之Activity+Intent

    Android有三个基础组件Activity,Service和BroadcastReceiver,他们都是依赖Intent来启动。本文介绍的是Activity的生命周期以及针对Activity的Intent使用。

            之前的例子一直都是使用Activity,在一个Layout XML与一个Activity捆绑的情况下可以视为一个Form,多个Layout XML与一个Activity捆绑的话那就是个Application本身了。Intent可以分为显式Intent和隐式Intent:显式 Intent用于启动明确的目标组件(前面所说的三大组件),同一个Application内的多个Activity调用也是显式Intent;隐式 Intent就是调用没有明确的目标组件,可以是系统也可以是第三方程序。隐式Intent一般用于调用系统组件功能,相关例程都是网络上很容易找到的(调用某些系统组件的时候要申请权限)。

            Acitivity的运行状况分为:onCreate、onDestroy、onStart、onStop、onRestart、onResume、 onPause,onCreate对应onDestroy,onStart对应onStop,onResume对应onPause。

    先贴出本文运行截图:

    1.gif

    2.jpg

    这个是从Acitivity1转到Activity2的时候,Acitivity1的状态变化,使用了finish()会触发onDestroy()。

    3.jpg

    这个是从Activity2转到Activity1的时候,Acitivity2的状态变化。从两次Activity的启动可以看出,流程是 onCreate()->onStart()->onResume()三个方法,销毁是 onPause()->onStop()->onDestroy()。另外,要往工程添加第二个Activity,需要到AndroidManifest.xml->Application那里添加Activity2。

    main1.xml的源码:

     

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.     <Button android:layout_width="wrap_content"  
    6.         android:layout_height="wrap_content" android:id="@+id/main1.Button01"  
    7.         android:text="跳转到Activity2"></Button>  
    8.     <EditText android:text="@+id/EditText01" android:id="@+id/EditText01"  
    9.         android:layout_width="wrap_content" android:layout_height="wrap_content"></EditText>  
    10.     <Button android:layout_width="wrap_content"  
    11.         android:layout_height="wrap_content" android:id="@+id/main1.Button02"  
    12.         android:text="跳转到外部Activity"></Button>  
    13. </LinearLayout>  

    main2.xml的源码:

    1. <?xml version="1.0" encoding="UTF-8"?>  
    2. <LinearLayout android:id="@+id/LinearLayout01"  
    3.     android:layout_width="fill_parent" android:layout_height="fill_parent"  
    4.     xmlns:android="http://schemas.android.com/apk/res/android">  
    5.     <Button android:layout_width="wrap_content"  
    6.         android:layout_height="wrap_content" android:id="@+id/main2.Button01"  
    7.         android:text="返回Activity1"></Button>  
    8. </LinearLayout>  

    Activity1的源码:

       1. package com.testActivityIntent; 
       2. import android.app.Activity; 
       3. import android.content.Intent; 
       4. import android.content.SharedPreferences; 
       5. import android.net.Uri; 
       6. import android.os.Bundle; 
       7. import android.util.Log; 
       8. import android.view.View; 
       9. import android.widget.Button; 
      10. import android.widget.EditText; 
      11. public class testActivityIntent extends Activity { 
      12.     /** Called when the activity is first created. */ 
      13.     Button btnToInternalActivity; 
      14.     Button btnToExternalActivity; 
      15.     EditText tbBundle; 
      16.     @Override 
      17.     public void onCreate(Bundle savedInstanceState) { 
      18.         super.onCreate(savedInstanceState); 
      19.         Log.e("Activity1", "onCreate");//显示当前状态,onCreate与onDestroy对应 
      20.         setContentView(R.layout.main1); 
      21.          
      22.         btnToInternalActivity=(Button)this.findViewById(R.id.main1_Button01); 
      23.         btnToExternalActivity=(Button)this.findViewById(R.id.main1_Button02); 
      24.         btnToInternalActivity.setOnClickListener(new ClickEvent()); 
      25.         btnToExternalActivity.setOnClickListener(new ClickEvent()); 
      26.         tbBundle=(EditText)this.findViewById(R.id.EditText01);         
      27.     } 
      28.     public void onDestroy() 
      29.     { 
      30.         super.onDestroy(); 
      31.         Log.e("Activity1", "onDestroy");//显示当前状态,onCreate与onDestroy对应 
      32.     } 
      33.     @Override 
      34.     public void onStart() 
      35.     { 
      36.         super.onStart(); 
      37.         Log.e("Activity1", "onStart");//显示当前状态,onStart与onStop对应  
      38.     } 
      39.     @Override 
      40.     public void onStop() 
      41.     { 
      42.         super.onStop(); 
      43.         Log.e("Activity1", "onStop");//显示当前状态,onStart与onStop对应   
      44.     } 
      45.     @Override 
      46.     public void onRestart() 
      47.     { 
      48.         super.onRestart(); 
      49.         Log.e("Activity1", "onRestart"); 
      50.     } 
      51.     @Override 
      52.     public void onResume() 
      53.     { 
      54.         super.onResume(); 
      55.         Log.e("Activity1", "onResume");//显示当前状态,onPause与onResume对应   
      56.         SharedPreferences prefs = getPreferences(0); //SharedPreferences 用于存储数据 
      57.         String restoredText = prefs.getString("editText01", null); 
      58.         if (restoredText != null) { 
      59.             this.tbBundle.setText(restoredText); 
      60.         } 
      61.     } 
      62.     @Override 
      63.     public void onPause() 
      64.     { 
      65.         super.onResume(); 
      66.         Log.e("Activity1", "onPause");//显示当前状态,onPause与onResume对应    
      67.         //保存文本框的内容,使得重回本Acitivity的时候可以恢复 
      68.         SharedPreferences.Editor editor = getPreferences(0).edit();//SharedPreferences 用于存储数据 
      69.         editor.putString("editText01", this.tbBundle.getText().toString()); 
      70.         editor.commit(); 
      71.     } 
      72.      
      73.     class ClickEvent implements View.OnClickListener{ 
      74.         @Override 
      75.         public void onClick(View v) { 
      76.             if(v==btnToInternalActivity) 
      77.             { 
      78.                 Intent intent = new Intent(); 
      79.                 intent.setClass(testActivityIntent.this,Activity2.class); 
      80.                  
      81.                 //new一个Bundle对象,并将要传递的数据传入 
      82.                 Bundle bundle = new Bundle(); 
      83.                 bundle.putString("Text",tbBundle.getText().toString()); 
      84.                
      85.                 //将Bundle对象assign给Intent 
      86.                 intent.putExtras(bundle); 
      87.                
      88.                 //调用Activity2 
      89.                 startActivity(intent); 
      90.                  
      91.                 testActivityIntent.this.finish();//会触发onDestroy(); 
      92.             } 
      93.             else if(v==btnToExternalActivity) 
      94.             { 
      95.                 //有些外部调用需要开启权限 
      96.                 Uri uri = Uri.parse("http://google.com");    
      97.                 Intent it = new Intent(Intent.ACTION_VIEW, uri);    
      98.                 startActivity(it);  
      99.             } 
     100.              
     101.         } 
     102.          
     103.     } 
     104.      
     105. } 

     

    Activity2的源码:

       1. package com.testActivityIntent; 
       2. import android.app.Activity; 
       3. import android.content.Intent; 
       4. import android.os.Bundle; 
       5. import android.util.Log; 
       6. import android.view.View; 
       7. import android.widget.Button; 
       8. public class Activity2  extends Activity { 
       9.     Button btnBackMain1; 
      10.     public void onCreate(Bundle savedInstanceState) 
      11.       { 
      12.         super.onCreate(savedInstanceState); 
      13.         Log.e("Activity2", "onCreate");//显示当前状态,onCreate与onDestroy对应 
      14.          
      15.         //加载activity2.xml 
      16.         setContentView(R.layout.main2); 
      17.          
      18.         //得Intent中的Bundle对象 
      19.         Bundle bunde = this.getIntent().getExtras(); 
      20.         //取得Bundle对象中的数据  
      21.         Log.i("In_Text", bunde.getString("Text")); 
      22.         btnBackMain1=(Button)this.findViewById(R.id.main2_Button01); 
      23.         btnBackMain1.setOnClickListener(new ClickEvent()); 
      24.       } 
      25.      
      26.     public void onDestroy() 
      27.     { 
      28.         super.onDestroy(); 
      29.         Log.e("Activity2", "onDestroy");//显示当前状态,onCreate与onDestroy对应 
      30.     } 
      31.     @Override 
      32.     public void onStart() 
      33.     { 
      34.         super.onStart(); 
      35.         Log.e("Activity2", "onStart");//显示当前状态,onStart与onStop对应  
      36.     } 
      37.     @Override 
      38.     public void onStop() 
      39.     { 
      40.         super.onStop(); 
      41.         Log.e("Activity2", "onStop");//显示当前状态,onStart与onStop对应   
      42.     } 
      43.     @Override 
      44.     public void onRestart() 
      45.     { 
      46.         super.onRestart(); 
      47.         Log.e("Activity2", "onRestart");     
      48.     } 
      49.     @Override 
      50.     public void onResume() 
      51.     { 
      52.         super.onResume(); 
      53.         Log.e("Activity2", "onResume");//显示当前状态,onPause与onResume对应       
      54.     } 
      55.     @Override 
      56.     public void onPause() 
      57.     { 
      58.         super.onResume(); 
      59.         Log.e("Activity2", "onPause");//显示当前状态,onPause与onResume对应    
      60.     } 
      61.      
      62.     class ClickEvent implements View.OnClickListener{ 
      63.         @Override 
      64.         public void onClick(View v) { 
      65.             if(v==btnBackMain1) 
      66.             { 
      67.                  
      68.                 Intent intent = new Intent(); 
      69.                 intent.setClass(Activity2.this,testActivityIntent.class); 
      70.                  
      71.                 //调用Activity1 
      72.                 startActivity(intent); 
      73.                  
      74.                 Activity2.this.finish();//会触发onDestroy(); 
      75.             } 
      76.              
      77.         } 
      78.          
      79.     } 
      80. } 

     

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 10:47

    Android提高第五篇之Service

    上次介绍了Activity以及Intent的使用,这次就介绍Service,如果把Activity比喻为前台程序,那么Service就是后台程序,Service的整个生命周期都只会在后台执行。 Service跟Activity一样也由Intent调用。在工程里想要添加一个Service,先新建继承Service的类,然后到 AndroidManifest.xml -> Application ->Application Nodes中的Service标签中添加。

             Service要由Activity通过startService 或者 bindService来启动,Intent负责传递参数。先贴出本文程序运行截图:

     

    1.jpg

    本文主要讲解Service的调用,以及其生命周期。

    2.jpg

    上图是startService之后再stopService的Service状态变化。

    3.jpg

    上图是bindService之后再unbindService的Service状态变化。

           startService与bindService都可以启动Service,那么它们之间有什么区别呢?它们两者的区别就是使Service的周期改变。由 startService启动的Service必须要有stopService来结束Service,不调用stopService则会造成 Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在 Activity结束之后(onDestroy)自动结束。

    4.jpg

     上图是startService之后再Activity.finish()的Service状态变化,Service还在跑着。

    5.jpg

    上图是bindService之后再Activity.finish()的Service状态变化,Service最后自动unbindService。

    main.xml代码:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.     <Button android:layout_width="wrap_content"  
    6.         android:layout_height="wrap_content" android:id="@+id/btnStartMyService"  
    7.         android:text="StartMyService"></Button>  
    8.     <Button android:layout_width="wrap_content"  
    9.         android:layout_height="wrap_content" android:id="@+id/btnStopMyService"  
    10.         android:text="StopMyService"></Button>  
    11.     <Button android:layout_width="wrap_content"  
    12.         android:layout_height="wrap_content" android:id="@+id/btnBindMyService"  
    13.         android:text="BindMyService"></Button>  
    14.     <Button android:layout_width="wrap_content"  
    15.         android:layout_height="wrap_content" android:id="@+id/btnUnbindMyService"  
    16.         android:text="UnbindMyService"></Button>  
    17.     <Button android:layout_width="wrap_content"  
    18.         android:layout_height="wrap_content" android:id="@+id/btnExit"  
    19.         android:text="退出程序"></Button>  
    20. </LinearLayout>  

    testService.java的源码:

    1. package com.testService;  
    2.   
    3. import android.app.Activity;  
    4. import android.app.Service;  
    5. import android.content.ComponentName;  
    6. import android.content.Intent;  
    7. import android.content.ServiceConnection;  
    8. import android.os.Bundle;  
    9. import android.os.IBinder;  
    10. import android.util.Log;  
    11. import android.view.View;  
    12. import android.widget.Button;  
    13.   
    14. public class testService extends Activity {  
    15.     Button btnStartMyService,btnStopMyService,btnBindMyService,btnUnbindMyService,btnExit;  
    16.     @Override  
    17.     public void onCreate(Bundle savedInstanceState) {  
    18.         super.onCreate(savedInstanceState);  
    19.         setContentView(R.layout.main);  
    20.         btnStartMyService=(Button)this.findViewById(R.id.btnStartMyService);  
    21.         btnStartMyService.setOnClickListener(new ClickEvent());  
    22.           
    23.         btnStopMyService=(Button)this.findViewById(R.id.btnStopMyService);  
    24.         btnStopMyService.setOnClickListener(new ClickEvent());  
    25.           
    26.         btnBindMyService=(Button)this.findViewById(R.id.btnBindMyService);  
    27.         btnBindMyService.setOnClickListener(new ClickEvent());  
    28.           
    29.         btnUnbindMyService=(Button)this.findViewById(R.id.btnUnbindMyService);  
    30.         btnUnbindMyService.setOnClickListener(new ClickEvent());   
    31.           
    32.         btnExit=(Button)this.findViewById(R.id.btnExit);  
    33.         btnExit.setOnClickListener(new ClickEvent());  
    34.     }  
    35.     @Override  
    36.     public void onDestroy()  
    37.     {  
    38.         super.onDestroy();  
    39.         Log.e("Activity","onDestroy");  
    40.     }  
    41.       
    42.     private ServiceConnection _connection = new ServiceConnection() {    
    43.         @Override  
    44.         public void onServiceConnected(ComponentName arg0, IBinder arg1) {  
    45.             // TODO Auto-generated method stub  
    46.         }  
    47.   
    48.         @Override  
    49.         public void onServiceDisconnected(ComponentName name) {  
    50.             // TODO Auto-generated method stub  
    51.         }    
    52.     };    
    53.     class ClickEvent implements View.OnClickListener{  
    54.   
    55.         @Override  
    56.         public void onClick(View v) {  
    57.             Intent intent=new Intent(testService.this,MyService.class);  
    58.             if(v==btnStartMyService){  
    59.                 testService.this.startService(intent);  
    60.             }  
    61.             else if(v==btnStopMyService){  
    62.                 testService.this.stopService(intent);  
    63.             }  
    64.             else if(v==btnBindMyService){  
    65.                 testService.this.bindService(intent, _connection, Service.BIND_AUTO_CREATE);  
    66.             }  
    67.             else if(v==btnUnbindMyService){  
    68.                 if(MyService.ServiceState=="onBind")//Service绑定了之后才能解绑  
    69.                     testService.this.unbindService(_connection);  
    70.             }  
    71.             else if(v==btnExit)  
    72.             {  
    73.                 testService.this.finish();  
    74.             }  
    75.               
    76.         }  
    77.           
    78.     }  
    79. }  

    MyService.java的源码:

    1. package com.testService;  
    2.   
    3. import android.app.Service;  
    4. import android.content.Intent;  
    5. import android.os.IBinder;  
    6. import android.util.Log;  
    7.   
    8. public class MyService extends Service {  
    9.     static public String ServiceState="";  
    10.     @Override  
    11.     public IBinder onBind(Intent arg0) {  
    12.         Log.e("Service""onBind");  
    13.         ServiceState="onBind";  
    14.         return null;  
    15.     }  
    16.     @Override  
    17.     public boolean onUnbind(Intent intent){  
    18.         super.onUnbind(intent);  
    19.         Log.e("Service""onUnbind");  
    20.         ServiceState="onUnbind";  
    21.         return false;  
    22.           
    23.     }  
    24.     @Override  
    25.     public void onCreate(){  
    26.         super.onCreate();  
    27.         Log.e("Service""onCreate");  
    28.         ServiceState="onCreate";  
    29.     }  
    30.     @Override  
    31.     public void onDestroy(){  
    32.         super.onDestroy();  
    33.         Log.e("Service""onDestroy");  
    34.         ServiceState="onDestroy";  
    35.     }  
    36.     @Override  
    37.     public void onStart(Intent intent,int startid){  
    38.         super.onStart(intent, startid);  
    39.         Log.e("Service""onStart");  
    40.         ServiceState="onStart";  
    41.     }  
    42.   
    43. }  

     

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 10:57

    Android提高第六篇之BroadcastReceiver

    前面分别讨论了Activity和Service,这次就轮到BroastcastReceiver,Broastcast是应用程序间通信的手段。BroastcastReceiver也是跟 Intent紧密相连的,动态/静态注册了BroastcastReceiver之后,使用sendBroadcast把Intent发送之后,系统会自动把符合条件的BroastcastReceiver启动,跟嵌入式系统的中断类似。

            本文主要演示了如何静态/动态注册BroastcastReceiver,向系统索取电量信息,以及枚举信息的字段。本文运行截图如下:

    1.jpg

     

    2.jpg

    上图是发送Intent至内部动态注册的BroadcastReceiver,接收到之后显示消息名称。动态注册BroadcastReceiver用到registerReceiver()。

    3.jpg 上图是发送Intent至内部静态注册的BroadcastReceiver,接收到之后显示消息名称。静态注册比动态注册麻烦点,先新建一个类继承BroadcastReceiver,然后到AndroidManifest.xml 添加

    1. <receiver android:name="clsReceiver2">  
    2.     <intent-filter>  
    3.         <action  
    4.             android:name="com.testBroadcastReceiver.Internal_2"/>  
    5.     </intent-filter>  
    6. </receiver>  

    第一个name是类名,第二个是action的名称。

    4.jpg

    上图是枚举Intent消息的字段,这个功能比较适合懒人,把收到的Intent消息的字段全部分解了,再看看哪个需要的,懒得记住。实现这部分的代码如下:

    1. //当未知Intent包含的内容,则需要通过以下方法来列举  
    2.                 Bundle b=intent.getExtras();  
    3.                 Object[] lstName=b.keySet().toArray();  
    4.   
    5.                 for(int i=0;i<lstName.length;i++)  
    6.                 {  
    7.                     String keyName=lstName.toString();  
    8.                     Log.e(keyName,String.valueOf(b.get(keyName)));  
    9.                 }  

    main.xml的代码如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.   
    6.     <Button android:id="@+id/Button01" android:layout_width="wrap_content"  
    7.         android:layout_height="wrap_content" android:text="发送至内部动态注册的BroadcastReceiver"></Button>  
    8.     <Button android:id="@+id/Button02" android:layout_width="wrap_content"  
    9.         android:layout_height="wrap_content" android:text="发送至内部静态注册BroadcastReceiver"></Button>  
    10.     <Button android:id="@+id/Button03" android:layout_width="wrap_content"  
    11.         android:layout_height="wrap_content" android:text="发送至系统BroadcastReceiver"></Button>  
    12. </LinearLayout>  

    testBroadcastReceiver.java的代码如下:

    1. package com.testBroadcastReceiver;  
    2.   
    3. import android.app.Activity;  
    4. import android.content.BroadcastReceiver;  
    5. import android.content.Context;  
    6. import android.content.Intent;  
    7. import android.content.IntentFilter;  
    8. import android.os.Bundle;  
    9. import android.util.Log;  
    10. import android.view.View;  
    11. import android.widget.Button;  
    12. import android.widget.Toast;  
    13.   
    14. public class testBroadcastReceiver extends Activity {  
    15.     Button btnInternal1,btnInternal2,btnSystem;  
    16.     static final String INTENAL_ACTION_1 = "com.testBroadcastReceiver.Internal_1";  
    17.     static final String INTENAL_ACTION_2 = "com.testBroadcastReceiver.Internal_2";  
    18.     static final String INTENAL_ACTION_3 = "com.testBroadcastReceiver.Internal_3";  
    19.     @Override  
    20.     public void onCreate(Bundle savedInstanceState) {  
    21.         super.onCreate(savedInstanceState);  
    22.         setContentView(R.layout.main);  
    23.         btnInternal1=(Button)this.findViewById(R.id.Button01);  
    24.         btnInternal1.setOnClickListener(new ClickEvent());  
    25.         btnInternal2=(Button)this.findViewById(R.id.Button02);  
    26.         btnInternal2.setOnClickListener(new ClickEvent());  
    27.         btnSystem=(Button)this.findViewById(R.id.Button03);  
    28.         btnSystem.setOnClickListener(new ClickEvent());  
    29.         //动态注册广播消息  
    30.         registerReceiver(bcrIntenal1, new IntentFilter(INTENAL_ACTION_1));  
    31.     }  
    32.     class ClickEvent implements View.OnClickListener{  
    33.   
    34.         @Override  
    35.         public void onClick(View v) {  
    36.             if(v==btnInternal1)//给动态注册的BroadcastReceiver发送数据  
    37.             {  
    38.                 Intent intent = new Intent(INTENAL_ACTION_1);  
    39.                 sendBroadcast(intent);  
    40.             }  
    41.             else if(v==btnInternal2)//给静态注册的BroadcastReceiver发送数据  
    42.             {  
    43.                 Intent intent = new Intent(INTENAL_ACTION_2);  
    44.                 sendBroadcast(intent);  
    45.             }  
    46.             else if(v==btnSystem)//动态注册 接收2组信息的BroadcastReceiver  
    47.             {  
    48.                 IntentFilter filter = new IntentFilter();//  
    49.                 filter.addAction(Intent.ACTION_BATTERY_CHANGED);//系统电量检测信息  
    50.                 filter.addAction(INTENAL_ACTION_3);//第三组自定义消息  
    51.                 registerReceiver(batInfoReceiver, filter);  
    52.                   
    53.                 Intent intent = new Intent(INTENAL_ACTION_3);  
    54.                 intent.putExtra("Name""hellogv");  
    55.                 intent.putExtra("Blog""http://blog.csdn.net/hellogv");  
    56.                 sendBroadcast(intent);//传递过去  
    57.             }  
    58.         }  
    59.           
    60.     }  
    61.       
    62.     /* 
    63.      * 接收动态注册广播的BroadcastReceiver 
    64.      */  
    65.     private BroadcastReceiver bcrIntenal1 = new BroadcastReceiver() {  
    66.           
    67.         public void onReceive(Context context, Intent intent) {  
    68.             String action = intent.getAction();  
    69.             Toast.makeText(context, "动态:"+action, 1000).show();  
    70.         }  
    71.     };  
    72.       
    73.   
    74.     private BroadcastReceiver batInfoReceiver = new BroadcastReceiver() {  
    75.           
    76.         public void onReceive(Context context, Intent intent) {  
    77.             String action = intent.getAction();  
    78.             //如果捕捉到的action是ACTION_BATTERY_CHANGED  
    79.             if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {  
    80.                 //当未知Intent包含的内容,则需要通过以下方法来列举  
    81.                 Bundle b=intent.getExtras();  
    82.                 Object[] lstName=b.keySet().toArray();  
    83.   
    84.                 for(int i=0;i<lstName.length;i++)  
    85.                 {  
    86.                     String keyName=lstName.toString();  
    87.                     Log.e(keyName,String.valueOf(b.get(keyName)));  
    88.                 }  
    89.             }  
    90.             //如果捕捉到的action是INTENAL_ACTION_3  
    91.             if (INTENAL_ACTION_3.equals(action)) {  
    92.                 //当未知Intent包含的内容,则需要通过以下方法来列举  
    93.                 Bundle b=intent.getExtras();  
    94.                 Object[] lstName=b.keySet().toArray();  
    95.   
    96.                 for(int i=0;i<lstName.length;i++)  
    97.                 {  
    98.                     String keyName=lstName.toString();  
    99.                     Log.e(keyName,b.getString(keyName));  
    100.                 }  
    101.             }  
    102.         }  
    103.     };  
    104.   
    105.   
    106. }  

    clsReceiver2.java的代码如下:

    1. package com.testBroadcastReceiver;  
    2.   
    3. import android.content.BroadcastReceiver;  
    4. import android.content.Context;  
    5. import android.content.Intent;  
    6. import android.widget.Toast;  
    7.   
    8. /* 
    9.  * 接收静态注册广播的BroadcastReceiver, 
    10.  * step1:要到AndroidManifest.xml这里注册消息 
    11.  *      <receiver android:name="clsReceiver2"> 
    12.             <intent-filter> 
    13.                 <action 
    14.                     android:name="com.testBroadcastReceiver.Internal_2"/> 
    15.             </intent-filter> 
    16.         </receiver> 
    17.     step2:定义消息的字符串 
    18.     step3:通过Intent传递消息来驱使BroadcastReceiver触发 
    19.  */  
    20. public class clsReceiver2 extends BroadcastReceiver{  
    21.     @Override  
    22.     public void onReceive(Context context, Intent intent) {  
    23.         String action = intent.getAction();  
    24.         Toast.makeText(context, "静态:"+action, 1000).show();  
    25.           
    26.     }  
    27. }  

     

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 11:02

    Android提高第七篇之XML解析与生成

    本文使用SAX来解析XML,在Android里面可以使用SAX和DOM,DOM需要把整个XML文件读入内存再解析,比较消耗内存,而SAX基于事件驱动的处理方式,可以在各节点触发回调函数,不过SAX适合节点结构简单的XML文档,复杂的XML文档在后期的节点深度处理会有点麻烦。

    本文要解析的test.xml文件如下:

  • <?xml version="1.0" encoding="utf-8"?>   
  • <test>   
  •   <title>testSAX</title>   
  •     <content aa="1" bb="2">   
  •       <name>hellogv</name>   
  •       <url>http://blog.csdn.net/hellogv</url>   
  •     </content>  
  • </test>  
  • 解析如上XML的结果如下:

      1.jpg

    使用SAX解析,需要定义SAXParserFactory(使应用程序能够配置和获取基于 SAX 的解析器以解析 XML 文档),SAXParser(从各种输入源解析 XML),XMLReader(使用回调函数读取 XML 文档),其中XMLReader是个关键。XMLReader可以为解析XML定义各种回调函数,“条件符合”的时候触发这些回调函数。

    1. SAXParserFactory factory = SAXParserFactory.newInstance();  
    2. SAXParser parser = factory.newSAXParser();  
    3. XMLReader reader = parser.getXMLReader();  
    4. reader.setContentHandler(handler);  
    5. reader.parse(new InputSource(testSAX.this.getResources()  
    6.         .openRawResource(R.raw.test)));  

    在这段代码里,XMLReader就调用继承DefaultHandler的SAXHandler。DefaultHandler已实现 ContentHandler, DTDHandler, EntityResolver, ErrorHandler等接口,包含常见读取XML的操作,具体请看下面的SAXHandler.java源码。

    生成XML的结果如下:

    2.jpg 上图是读取各节点之后,使用XmlSerializer重新组合并输出XML字符串。

    本文的main.xml代码如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.   
    6.     <Button android:layout_height="wrap_content"  
    7.         android:layout_width="fill_parent" android:id="@+id/btnSAX"  
    8.         android:text="使用SAX解析XML"></Button>  
    9.     <Button android:layout_height="wrap_content"  
    10.         android:layout_width="fill_parent" android:text="生成XML" android:id="@+id/btnOutput"></Button>  
    11.     <EditText android:text="@+id/EditText01" android:id="@+id/EditText01"  
    12.         android:layout_width="fill_parent" android:layout_height="fill_parent"></EditText>  
    13.   
    14. </LinearLayout>  

    SAXHandler.java的源码如下:

    1. package com.testSAX;  
    2.   
    3. import java.util.ArrayList;  
    4. import org.xml.sax.Attributes;  
    5. import org.xml.sax.SAXException;  
    6. import org.xml.sax.helpers.DefaultHandler;  
    7.   
    8. import android.util.Log;  
    9.   
    10. public class SAXHandler extends DefaultHandler{  
    11.         private ArrayList<String> keys = new ArrayList<String>();//保存字段名称  
    12.         private ArrayList<Object> values = new ArrayList<Object>();//保存值  
    13.         @Override  
    14.         public void startDocument() throws SAXException {  
    15.             super.startDocument();  
    16.   
    17.         }  
    18.   
    19.         @Override  
    20.         public void endDocument() throws SAXException {  
    21.             super.endDocument();  
    22.         }  
    23.   
    24.         @Override  
    25.         public void startElement(String uri, String localName, String qName,  
    26.                 Attributes attributes) throws SAXException {  
    27.             //保存开始标记  
    28.             keys.add("startTag");  
    29.             values.add(localName);  
    30.   
    31.             Log.e("startTag",localName);  
    32.             //保存属性值  
    33.             for ( int i = 0; i < attributes.getLength(); i++ ){  
    34.                 keys.add("Attr");  
    35.                 String[] str=new String[2];  
    36.                 str[0]=attributes.getLocalName(i);  
    37.                 str[1]=attributes.getValue(i);  
    38.                 values.add(str);  
    39.                 Log.e("Attr",str[0]+"="+str[1]);  
    40.                 }  
    41.         }  
    42.   
    43.         @Override  
    44.         public void endElement(String uri, String localName, String qName)  
    45.                 throws SAXException {  
    46.             //保存结束标记  
    47.             keys.add("endTag");  
    48.             values.add(localName);  
    49.             Log.e("endTag",localName);  
    50.         }  
    51.   
    52.         @Override  
    53.         public void characters(char[] ch, int start, int length)  
    54.                 throws SAXException {  
    55.             String value = new String(ch, start, length);  
    56.             value = value.trim();  
    57.             if (value.length() == 0)  
    58.                 return;  
    59.               
    60.             keys.add("text");  
    61.             values.add(value);  
    62.             Log.e("text",value);  
    63.         }  
    64.           
    65.         public ArrayList<String> GetKeys()  
    66.         {  
    67.             return keys;  
    68.         }  
    69.           
    70.         public ArrayList<Object> GetValues()  
    71.         {  
    72.             return values;  
    73.         }  
    74.           
    75.   
    76. }  

    testSAX.java的源码如下:

    1. package com.testSAX;  
    2.   
    3. import java.io.StringWriter;  
    4.   
    5. import javax.xml.parsers.SAXParser;  
    6. import javax.xml.parsers.SAXParserFactory;  
    7.   
    8. import org.xml.sax.InputSource;  
    9. import org.xml.sax.XMLReader;  
    10. import org.xmlpull.v1.XmlSerializer;  
    11.   
    12. import android.app.Activity;  
    13. import android.os.Bundle;  
    14.   
    15. import android.util.Xml;  
    16. import android.view.View;  
    17. import android.widget.Button;  
    18. import android.widget.EditText;  
    19.   
    20. public class testSAX extends Activity {  
    21.     /** Called when the activity is first created. */  
    22.     Button btnSAX, btnOutput;  
    23.     EditText memo;  
    24.     SAXHandler handler = new SAXHandler();  
    25.   
    26.       
    27.     @Override  
    28.     public void onCreate(Bundle savedInstanceState) {  
    29.         super.onCreate(savedInstanceState);  
    30.         setContentView(R.layout.main);  
    31.         btnSAX = (Button) this.findViewById(R.id.btnSAX);  
    32.         btnSAX.setOnClickListener(new ClickEvent());  
    33.         btnOutput = (Button) this.findViewById(R.id.btnOutput);  
    34.         btnOutput.setOnClickListener(new ClickEvent());  
    35.         memo = (EditText) this.findViewById(R.id.EditText01);  
    36.   
    37.     }  
    38.   
    39.     class ClickEvent implements View.OnClickListener {  
    40.   
    41.         @Override  
    42.         public void onClick(View v) {  
    43.             if (v == btnSAX) {//解析XML,并保存标记,属性等值  
    44.                 try {  
    45.                     SAXParserFactory factory = SAXParserFactory.newInstance();  
    46.                     SAXParser parser = factory.newSAXParser();  
    47.                     XMLReader reader = parser.getXMLReader();  
    48.                     reader.setContentHandler(handler);  
    49.                     reader.parse(new InputSource(testSAX.this.getResources()  
    50.                             .openRawResource(R.raw.test)));  
    51.                 } catch (Exception ee) {}  
    52.             }  
    53.             else if (v == btnOutput) {//生成XML  
    54.                 try {  
    55.                     XmlSerializer serializer = Xml.newSerializer();  
    56.                     StringWriter writer = new StringWriter();  
    57.                     try {  
    58.                         serializer.setOutput(writer);  
    59.                         serializer.startDocument("UTF-8",true);  
    60.                           
    61.                         for(int i=0;i<handler.GetKeys().size();i++)  
    62.                         {  
    63.                             if(handler.GetKeys().get(i).equals("startTag"))  
    64.                             {  
    65.                                 serializer.startTag("", (String) handler.GetValues().get(i));  
    66.                             }  
    67.                             else if(handler.GetKeys().get(i).equals("Attr")){  
    68.                                 String[] str= (String[]) handler.GetValues().get(i);  
    69.                                 serializer.attribute("",str[0],str[1]);  
    70.                             }  
    71.                             else if(handler.GetKeys().get(i).equals("text"))  
    72.                                 serializer.text((String)handler.GetValues().get(i));  
    73.                             else if(handler.GetKeys().get(i).equals("endTag"))  
    74.                             {  
    75.                                 serializer.endTag("", (String) handler.GetValues().get(i));  
    76.                             }  
    77.                         }  
    78.                         serializer.endDocument();  
    79.                         String text=writer.toString();  
    80.                         text=text.replace("><"">\r\n<");  
    81.                         memo.setText(text);//输出到文本框  
    82.                     } catch (Exception e) {  
    83.                         throw new RuntimeException(e);  
    84.                     }  
    85.                       
    86.                 } catch (Exception e) {}  
    87.             }  
    88.   
    89.         }  
    90.   
    91.     }  
    92. }  
    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 11:13

    Android提高第八篇之SQLite分页读取

    ndroid 包含了常用于嵌入式系统的SQLite,免去了开发者自己移植安装的功夫。SQLite 支持多数 SQL92 标准,很多常用的SQL命令都能在SQLite上面使用,除此之外Android还提供了一系列自定义的方法去简化对SQLite数据库的操作。不过有跨平台需求的程序就建议使用标准的SQL语句,毕竟这样容易在多个平台之间移植。

    先贴出本文程序运行的结果:

    1.gif

    本文主要讲解了SQLite的基本用法,如:创建数据库,使用SQL命令查询数据表、插入数据,关闭数据库,以及使用GridView实现了一个分页栏(关于GridView的用法),用于把数据分页显示。

    分页栏的pagebuttons.xml的源码如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_height="wrap_content" android:paddingBottom="4dip"  
    4.     android:layout_width="fill_parent">  
    5.     <TextView android:layout_width="wrap_content"  
    6.         android:layout_below="@+id/ItemImage" android:layout_height="wrap_content"  
    7.         android:text="TextView01" android:layout_centerHorizontal="true"  
    8.         android:id="@+id/ItemText">  
    9.     </TextView>  
    10. </RelativeLayout>    

    main.xml的源码如下

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.     <Button android:layout_height="wrap_content"  
    6.         android:layout_width="fill_parent" android:id="@+id/btnCreateDB"  
    7.         android:text="创建数据库"></Button>  
    8.     <Button android:layout_height="wrap_content"  
    9.         android:layout_width="fill_parent" android:text="插入一串实验数据" android:id="@+id/btnInsertRec"></Button>  
    10.     <Button android:layout_height="wrap_content" android:id="@+id/btnClose"  
    11.         android:text="关闭数据库" android:layout_width="fill_parent"></Button>  
    12.     <EditText android:text="@+id/EditText01" android:id="@+id/EditText01"  
    13.         android:layout_width="fill_parent" android:layout_height="256dip"></EditText>  
    14.     <GridView android:id="@+id/gridview" android:layout_width="fill_parent"  
    15.         android:layout_height="32dip" android:numColumns="auto_fit"  
    16.         android:columnWidth="40dip"></GridView>  
    17. </LinearLayout>  

    本文程序源码如下:

       1. package com.testSQLite;   
       2.    
       3. import java.util.ArrayList;   
       4. import java.util.HashMap;   
       5. import android.app.Activity;   
       6. import android.database.Cursor;   
       7. import android.database.SQLException;   
       8. import android.database.sqlite.SQLiteDatabase;   
       9. import android.os.Bundle;   
      10. import android.util.Log;   
      11. import android.view.View;   
      12. import android.widget.AdapterView;   
      13. import android.widget.AdapterView.OnItemClickListener;   
      14. import android.widget.Button;   
      15. import android.widget.EditText;   
      16. import android.widget.GridView;   
      17. import android.widget.SimpleAdapter;   
      18.    
      19. public class testSQLite extends Activity {   
      20.     /** Called when the activity is first created. */   
      21.     Button btnCreateDB, btnInsert, btnClose;   
      22.     EditText edtSQL;//显示分页数据   
      23.     SQLiteDatabase db;   
      24.     int id;//添加记录时的id累加标记,必须全局   
      25.     static final int PageSize=10;//分页时,每页的数据总数   
      26.     private static final String TABLE_NAME = "stu";   
      27.     private static final String ID = "id";   
      28.     private static final String NAME = "name";   
      29.        
      30.     SimpleAdapter saPageID;// 分页栏适配器   
      31.     ArrayList<HashMap<String, String>> lstPageID;// 分页栏的数据源,与PageSize和数据总数相关   
      32.    
      33.     @Override   
      34.     public void onCreate(Bundle savedInstanceState) {   
      35.         super.onCreate(savedInstanceState);   
      36.         setContentView(R.layout.main);   
      37.         btnCreateDB = (Button) this.findViewById(R.id.btnCreateDB);   
      38.         btnCreateDB.setOnClickListener(new ClickEvent());   
      39.    
      40.         btnInsert = (Button) this.findViewById(R.id.btnInsertRec);   
      41.         btnInsert.setOnClickListener(new ClickEvent());   
      42.    
      43.         btnClose = (Button) this.findViewById(R.id.btnClose);   
      44.         btnClose.setOnClickListener(new ClickEvent());   
      45.            
      46.         edtSQL=(EditText)this.findViewById(R.id.EditText01);   
      47.            
      48.         GridView gridview = (GridView) findViewById(R.id.gridview);//分页栏控件   
      49.         // 生成动态数组,并且转入数据   
      50.         lstPageID = new ArrayList<HashMap<String, String>>();   
      51.    
      52.         // 生成适配器的ImageItem <====> 动态数组的元素,两者一一对应   
      53.         saPageID = new SimpleAdapter(testSQLite.this, // 没什么解释   
      54.                 lstPageID,// 数据来源   
      55.                 R.layout.pagebuttons,//XML实现   
      56.                 new String[] { "ItemText" },   
      57.                 new int[] { R.id.ItemText });   
      58.    
      59.         // 添加并且显示   
      60.         gridview.setAdapter(saPageID);   
      61.         // 添加消息处理   
      62.         gridview.setOnItemClickListener(new OnItemClickListener(){   
      63.    
      64.             @Override   
      65.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,   
      66.                     long arg3) {   
      67.                 LoadPage(arg2);//根据所选分页读取对应的数据   
      68.             }   
      69.         });   
      70.    
      71.     }   
      72.    
      73.        
      74.     class ClickEvent implements View.OnClickListener {   
      75.    
      76.         @Override   
      77.         public void onClick(View v) {   
      78.             if (v == btnCreateDB) {   
      79.                 CreateDB();   
      80.             } else if (v == btnInsert) {   
      81.                 InsertRecord(16);//插入16条记录   
      82.                 RefreshPage();   
      83.             }else if (v == btnClose) {   
      84.                 db.close();   
      85.             }   
      86.         }   
      87.    
      88.     }   
      89.        
      90.    
      91.     /* 
      92.      * 读取指定ID的分页数据 
      93.      * SQL:Select * From TABLE_NAME Limit 9 Offset 10; 
      94.      * 表示从TABLE_NAME表获取数据,跳过10行,取9行 
      95.      */   
      96.     void LoadPage(int pageID)   
      97.     {   
      98.         String sql= "select * from " + TABLE_NAME +    
      99.         " Limit "+String.valueOf(PageSize)+ " Offset " +String.valueOf(pageID*PageSize);   
     100.         Cursor rec = db.rawQuery(sql, null);   
     101.    
     102.         setTitle("当前分页的数据总数:"+String.valueOf(rec.getCount()));   
     103.            
     104.         // 取得字段名称   
     105.         String title = "";   
     106.         int colCount = rec.getColumnCount();   
     107.         for (int i = 0; i < colCount; i++)   
     108.             title = title + rec.getColumnName(i) + "     ";   
     109.    
     110.            
     111.         // 列举出所有数据   
     112.         String content="";   
     113.         int recCount=rec.getCount();   
     114.         for (int i = 0; i < recCount; i++) {//定位到一条数据   
     115.             rec.moveToPosition(i);   
     116.             for(int ii=0;ii<colCount;ii++)//定位到一条数据中的每个字段   
     117.             {   
     118.                 content=content+rec.getString(ii)+"     ";   
     119.             }   
     120.             content=content+"\r\n";   
     121.         }   
     122.            
     123.         edtSQL.setText(title+"\r\n"+content);//显示出来   
     124.         rec.close();   
     125.     }   
     126.        
     127.     /* 
     128.      * 在内存创建数据库和数据表 
     129.      */   
     130.     void CreateDB() {   
     131.         // 在内存创建数据库   
     132.         db = SQLiteDatabase.create(null);   
     133.         Log.e("DB Path", db.getPath());   
     134.         String amount = String.valueOf(databaseList().length);   
     135.         Log.e("DB amount", amount);   
     136.         // 创建数据表   
     137.         String sql = "CREATE TABLE " + TABLE_NAME + " (" + ID   
     138.                 + " text not null, " + NAME + " text not null " + ");";   
     139.         try {   
     140.             db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);   
     141.             db.execSQL(sql);   
     142.         } catch (SQLException e) {}   
     143.     }   
     144.    
     145.     /* 
     146.      * 插入N条数据 
     147.      */   
     148.     void InsertRecord(int n) {   
     149.         int total = id + n;   
     150.         for (; id < total; id++) {   
     151.             String sql = "insert into " + TABLE_NAME + " (" + ID + ", " + NAME   
     152.                     + ") values('" + String.valueOf(id) + "', 'test');";   
     153.             try {   
     154.                 db.execSQL(sql);   
     155.             } catch (SQLException e) {   
     156.             }   
     157.         }   
     158.     }   
     159.    
     160.     /* 
     161.      * 插入之后刷新分页 
     162.      */   
     163.     void RefreshPage()   
     164.     {   
     165.         String sql = "select count(*) from " + TABLE_NAME;   
     166.         Cursor rec = db.rawQuery(sql, null);   
     167.         rec.moveToLast();   
     168.         long recSize=rec.getLong(0);//取得总数   
     169.         rec.close();   
     170.         int pageNum=(int)(recSize/PageSize) + 1;//取得分页数   
     171.            
     172.         lstPageID.clear();   
     173.         for (int i = 0; i < pageNum; i++) {   
     174.             HashMap<String, String> map = new HashMap<String, String>();   
     175.             map.put("ItemText", "No." + String.valueOf(i)); 
     176.    
     177.             lstPageID.add(map);   
     178.         }   
     179.         saPageID.notifyDataSetChanged();   
     180.     }   
     181. }   

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 11:23
    看的不是很明白耶,程序用C++写的吗?
    勇往直前,奋勇拼搏,不畏浮云遮望眼,直挂云帆济沧海
    点赞  2010-11-18 11:37

    回复 9楼 张无忌1987 的帖子

    先看基础篇  
    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-18 11:54
    开个安卓的版块??
    点赞  2010-11-18 12:41

    引用: 原帖由 张无忌1987 于 2010-11-18 11:37 发表 看的不是很明白耶,程序用C++写的吗?

     

    瞄着有点像java

    点赞  2010-11-18 19:44
    先把LLINUX搞明白,然后在玩这我觉得会很容易。
    QQ:1625345502
    点赞  2010-11-19 13:23
    好长啊!!!我喜欢android!!!
    你好呀
    点赞  2010-11-19 16:15
    看来俺out了……:(
    点赞  2010-11-19 19:02

    Android提高第九篇之SQLite分页表格

    上次讲的Android上的SQLite分页读取,只用文本框显示数据而已,这次就讲得更加深入些,实现并封装一个SQL分页表格控件,不仅支持分页还是以表格的形式展示数据。先来看看本文程序运行的动画:

    0_12900662151134.gif

           这个SQL分页表格控件主要分为“表格区”和“分页栏”这两部分,这两部分都是基于GridView实现的。网上介绍Android上实现表格的DEMO 一般都用ListView。ListView与GridView对比,ListView最大的优势是格单元的大小可以自定义,可以某单元长某单元短,但是不能自适应数据表的结构;而GridView最大的优势就是自适应数据表的结构,但是格单元统一大小。。。对于数据表结构多变的情况,建议使用 GridView实现表格。

    本文实现的SQL分页表格控件有以下特点:

    1.自适应数据表结构,但是格单元统一大小;

    2.支持分页;

    3.“表格区”有按键事件回调处理,“分页栏”有分页切换事件回调处理。

    本文程序代码较多,可以到这里下载整个工程的源码:http://www.rayfile.com/files/72e78b68-f2e5-11df-8469-0015c55db73d/

    items.xml的代码如下,它是“表格区”和“分页栏”的格单元实现:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout android:id="@+id/LinearLayout01"  
    3.     xmlns:android="http://schemas.android.com/apk/res/android"  
    4.     android:layout_width="fill_parent" android:background="#555555"  
    5.     android:layout_height="wrap_content">  
    6.     <TextView android:layout_below="@+id/ItemImage" android:text="TextView01"  
    7.         android:id="@+id/ItemText" android:bufferType="normal"  
    8.         android:singleLine="true" android:background="#000000"  
    9.         android:layout_width="fill_parent" android:gravity="center"  
    10.         android:layout_margin="1dip" android:layout_gravity="center"  
    11.         android:layout_height="wrap_content">  
    12.     </TextView>  
    13. </LinearLayout>  

    main.xml的代码如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent" android:id="@+id/MainLinearLayout">  
    5.   
    6.     <Button android:layout_height="wrap_content"  
    7.         android:layout_width="fill_parent" android:id="@+id/btnCreateDB"  
    8.         android:text="创建数据库"></Button>  
    9.     <Button android:layout_height="wrap_content"  
    10.         android:layout_width="fill_parent" android:text="插入一串实验数据" android:id="@+id/btnInsertRec"></Button>  
    11.     <Button android:layout_height="wrap_content" android:id="@+id/btnClose"  
    12.         android:text="关闭数据库" android:layout_width="fill_parent"></Button>  
    13. </LinearLayout>  

    演示程序testSQLite.java的源码:

    1. package com.testSQLite;  
    2.   
    3. import android.app.Activity;  
    4. import android.database.Cursor;  
    5. import android.database.SQLException;  
    6. import android.database.sqlite.SQLiteDatabase;  
    7. import android.os.Bundle;  
    8. import android.util.Log;  
    9. import android.view.View;  
    10. import android.widget.Button;  
    11. import android.widget.LinearLayout;  
    12. import android.widget.Toast;  
    13.   
    14. public class testSQLite extends Activity {  
    15.     GVTable table;  
    16.     Button btnCreateDB, btnInsert, btnClose;  
    17.     SQLiteDatabase db;  
    18.     int id;//添加记录时的id累加标记,必须全局  
    19.   
    20.     private static final String TABLE_NAME = "stu";  
    21.     private static final String ID = "id";  
    22.     private static final String NAME = "name";  
    23.     private static final String PHONE = "phone";  
    24.     private static final String ADDRESS = "address";  
    25.     private static final String AGE = "age";  
    26.       
    27.     @Override  
    28.     public void onCreate(Bundle savedInstanceState) {  
    29.         super.onCreate(savedInstanceState);  
    30.         setContentView(R.layout.main);  
    31.         btnCreateDB = (Button) this.findViewById(R.id.btnCreateDB);  
    32.         btnCreateDB.setOnClickListener(new ClickEvent());  
    33.   
    34.         btnInsert = (Button) this.findViewById(R.id.btnInsertRec);  
    35.         btnInsert.setOnClickListener(new ClickEvent());  
    36.   
    37.         btnClose = (Button) this.findViewById(R.id.btnClose);  
    38.         btnClose.setOnClickListener(new ClickEvent());  
    39.   
    40.         table=new GVTable(this);  
    41.         table.gvSetTableRowCount(8);//设置每个分页的ROW总数  
    42.         LinearLayout ly = (LinearLayout) findViewById(R.id.MainLinearLayout);  
    43.   
    44.         table.setTableOnClickListener(new GVTable.OnTableClickListener() {  
    45.             @Override  
    46.             public void onTableClickListener(int x,int y,Cursor c) {  
    47.                 c.moveToPosition(y);  
    48.                 String str=c.getString(x)+" 位置:(" />"+String.valueOf(x)+","+String.valueOf(y)+")";  
    49.                 Toast.makeText(testSQLite.this, str, 1000).show();  
    50.             }  
    51.   
    52.         });  
    53.         table.setOnPageSwitchListener(new GVTable.OnPageSwitchListener() {  
    54.               
    55.             @Override  
    56.             public void onPageSwitchListener(int pageID,int pageCount) {  
    57.                 String str="共有"+String.valueOf(pageCount)+  
    58.                 " 当前第"+String.valueOf(pageID)+"页";  
    59.                 Toast.makeText(testSQLite.this, str, 1000).show();  
    60.             }  
    61.         });  
    62.           
    63.         ly.addView(table);  
    64.     }  
    65.   
    66.     class ClickEvent implements View.OnClickListener {  
    67.   
    68.         @Override  
    69.         public void onClick(View v) {  
    70.             if (v == btnCreateDB) {  
    71.                 CreateDB();  
    72.             } else if (v == btnInsert) {  
    73.                 InsertRecord(16);//插入16条记录  
    74.   
    75.                 table.gvUpdatePageBar("select count(*) from " + TABLE_NAME,db);  
    76.                 table.gvReadyTable("select * from " + TABLE_NAME,db);  
    77.             }else if (v == btnClose) {  
    78.                 table.gvRemoveAll();  
    79.                 db.close();  
    80.                   
    81.             }  
    82.         }  
    83.     }  
    84.       
    85.     /** 
    86.      * 在内存创建数据库和数据表 
    87.      */  
    88.     void CreateDB() {  
    89.         // 在内存创建数据库  
    90.         db = SQLiteDatabase.create(null);  
    91.         Log.e("DB Path", db.getPath());  
    92.         String amount = String.valueOf(databaseList().length);  
    93.         Log.e("DB amount", amount);  
    94.         // 创建数据表  
    95.         String sql = "CREATE TABLE " + TABLE_NAME + " (" +   
    96.                 ID  + " text not null, " + NAME + " text not null," +  
    97.                 ADDRESS + " text not null, " + PHONE + " text not null," +  
    98.                 AGE + " text not null "+");";  
    99.         try {  
    100.             db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);  
    101.             db.execSQL(sql);  
    102.         } catch (SQLException e) {}  
    103.     }  
    104.   
    105.     /** 
    106.      * 插入N条数据 
    107.      */  
    108.     void InsertRecord(int n) {  
    109.         int total = id + n;  
    110.         for (; id < total; id++) {  
    111.             String sql = "insert into " + TABLE_NAME + " (" +   
    112.             ID + ", " + NAME+", " + ADDRESS+", " + PHONE+", "+AGE  
    113.                     + ") values('" + String.valueOf(id) + "', 'man','address','123456789','18');";  
    114.             try {  
    115.                 db.execSQL(sql);  
    116.             } catch (SQLException e) {  
    117.             }  
    118.         }  
    119.     }  
    120.       
    121.       
    122.   
    123. }  

    分页表格控件GVTable.java的源码:

    1. package com.testSQLite;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.HashMap;  
    5. import android.content.Context;  
    6. import android.database.Cursor;  
    7. import android.database.sqlite.SQLiteDatabase;  
    8. import android.view.View;  
    9. import android.widget.AdapterView;  
    10. import android.widget.GridView;  
    11. import android.widget.LinearLayout;  
    12. import android.widget.SimpleAdapter;  
    13. import android.widget.AdapterView.OnItemClickListener;  
    14.   
    15. public class GVTable extends LinearLayout {  
    16.     protected GridView gvTable,gvPage;    
    17.     protected SimpleAdapter saPageID,saTable;// 适配器  
    18.     protected ArrayList<HashMap<String, String>> srcPageID,srcTable;// 数据源  
    19.       
    20.     protected int TableRowCount=10;//分页时,每页的Row总数  
    21.     protected int TableColCount=0;//每页col的数量  
    22.   
    23.     protected SQLiteDatabase db;  
    24.     protected String rawSQL="";  
    25.     protected Cursor curTable;//分页时使用的Cursor  
    26.     protected OnTableClickListener clickListener;//整个分页控件被点击时的回调函数  
    27.     protected OnPageSwitchListener switchListener;//分页切换时的回调函数  
    28.       
    29.     public GVTable(Context context) {  
    30.         super(context);  
    31.         this.setOrientation(VERTICAL);//垂直  
    32.         //----------------------------------------  
    33.         gvTable=new GridView(context);  
    34.         addView(gvTable, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,  
    35.                 LayoutParams.WRAP_CONTENT));//宽长式样  
    36.           
    37.         srcTable = new ArrayList<HashMap<String, String>>();  
    38.         saTable = new SimpleAdapter(context,  
    39.                 srcTable,// 数据来源  
    40.                 R.layout.items,//XML实现  
    41.                 new String[] { "ItemText" },// 动态数组与ImageItem对应的子项  
    42.                 new int[] { R.id.ItemText });  
    43.         // 添加并且显示  
    44.         gvTable.setAdapter(saTable);  
    45.         gvTable.setOnItemClickListener(new OnItemClickListener(){  
    46.             @Override  
    47.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
    48.                     long arg3) {  
    49.                 int y=arg2/curTable.getColumnCount()-1;//标题栏的不算  
    50.                 int x=arg2 % curTable.getColumnCount();  
    51.                 if (clickListener != null//分页数据被点击  
    52.                         && y!=-1) {//点中的不是标题栏时  
    53.                     clickListener.onTableClickListener(x,y,curTable);  
    54.                 }  
    55.             }  
    56.         });  
    57.           
    58.         //----------------------------------------  
    59.         gvPage=new GridView(context);  
    60.         gvPage.setColumnWidth(40);//设置每个分页按钮的宽度  
    61.         gvPage.setNumColumns(GridView.AUTO_FIT);//分页按钮数量自动设置  
    62.         addView(gvPage, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,  
    63.                 LayoutParams.WRAP_CONTENT));//宽长式样  
    64.         srcPageID = new ArrayList<HashMap<String, String>>();  
    65.         saPageID = new SimpleAdapter(context,  
    66.                 srcPageID,// 数据来源  
    67.                 R.layout.items,//XML实现  
    68.                 new String[] { "ItemText" },// 动态数组与ImageItem对应的子项  
    69.                 new int[] { R.id.ItemText });  
    70.   
    71.         // 添加并且显示  
    72.         gvPage.setAdapter(saPageID);  
    73.         // 添加消息处理  
    74.         gvPage.setOnItemClickListener(new OnItemClickListener(){  
    75.             @Override  
    76.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
    77.                     long arg3) {  
    78.                 LoadTable(arg2);//根据所选分页读取对应的数据  
    79.                 if(switchListener!=null){//分页切换时  
    80.                     switchListener.onPageSwitchListener(arg2,srcPageID.size());  
    81.                 }  
    82.             }  
    83.         });  
    84.     }  
    85.   
    86.     /** 
    87.      * 清除所有数据 
    88.      */  
    89.     public void gvRemoveAll()  
    90.     {  
    91.         if(this.curTable!=null)  
    92.             curTable.close();  
    93.         srcTable.clear();  
    94.         saTable.notifyDataSetChanged();  
    95.       
    96.         srcPageID.clear();  
    97.         saPageID.notifyDataSetChanged();  
    98.           
    99.     }  
    100.     /** 
    101.      * 读取指定ID的分页数据,返回当前页的总数据 
    102.      * SQL:Select * From TABLE_NAME Limit 9 Offset 10; 
    103.      * 表示从TABLE_NAME表获取数据,跳过10行,取9行 
    104.      * @param pageID 指定的分页ID 
    105.      */  
    106.     protected void LoadTable(int pageID)  
    107.     {  
    108.         if(curTable!=null)//释放上次的数据  
    109.             curTable.close();  
    110.           
    111.         String sql= rawSQL+" Limit "+String.valueOf(TableRowCount)+ " Offset " +String.valueOf(pageID*TableRowCount);  
    112.         curTable = db.rawQuery(sql, null);  
    113.           
    114.         gvTable.setNumColumns(curTable.getColumnCount());//表现为表格的关键点!  
    115.         TableColCount=curTable.getColumnCount();  
    116.         srcTable.clear();  
    117.         // 取得字段名称  
    118.         int colCount = curTable.getColumnCount();  
    119.         for (int i = 0; i < colCount; i++) {  
    120.             HashMap<String, String> map = new HashMap<String, String>();  
    121.             map.put("ItemText", curTable.getColumnName(i));  
    122.             srcTable.add(map);  
    123.         }  
    124.           
    125.         // 列举出所有数据  
    126.         int recCount=curTable.getCount();  
    127.         for (int i = 0; i < recCount; i++) {//定位到一条数据  
    128.             curTable.moveToPosition(i);  
    129.             for(int ii=0;ii<colCount;ii++)//定位到一条数据中的每个字段  
    130.             {  
    131.                 HashMap<String, String> map = new HashMap<String, String>();  
    132.                 map.put("ItemText", curTable.getString(ii));  
    133.                 srcTable.add(map);  
    134.             }  
    135.         }  
    136.           
    137.         saTable.notifyDataSetChanged();  
    138.     }  
    139.   
    140.     /** 
    141.      * 设置表格的最多显示的行数 
    142.      * @param row 表格的行数 
    143.      */  
    144.     public void gvSetTableRowCount(int row)  
    145.     {  
    146.         TableRowCount=row;  
    147.     }  
    148.       
    149.     /** 
    150.      * 取得表格的最大行数     
    151.      * @return 行数 
    152.      */  
    153.     public int gvGetTableRowCount()  
    154.     {  
    155.         return TableRowCount;  
    156.     }  
    157.       
    158.     /** 
    159.      * 取得当前分页的Cursor 
    160.      * @return 当前分页的Cursor 
    161.      */  
    162.     public Cursor gvGetCurrentTable()  
    163.     {  
    164.         return curTable;  
    165.     }  
    166.           
    167.     /** 
    168.      * 准备分页显示数据 
    169.      * @param rawSQL sql语句 
    170.      * @param db 数据库 
    171.      */  
    172.     public void gvReadyTable(String rawSQL,SQLiteDatabase db)  
    173.     {  
    174.         this.rawSQL=rawSQL;  
    175.         this.db=db;  
    176.     }  
    177.       
    178.     /** 
    179.      * 刷新分页栏,更新按钮数量 
    180.      * @param sql SQL语句 
    181.      * @param db 数据库 
    182.      */  
    183.     public void gvUpdatePageBar(String sql,SQLiteDatabase db)  
    184.     {  
    185.         Cursor rec = db.rawQuery(sql, null);  
    186.         rec.moveToLast();  
    187.         long recSize=rec.getLong(0);//取得总数  
    188.         rec.close();  
    189.         int pageNum=(int)(recSize/TableRowCount) + 1;//取得分页数  
    190.           
    191.         srcPageID.clear();  
    192.         for (int i = 0; i < pageNum; i++) {  
    193.             HashMap<String, String> map = new HashMap<String, String>();  
    194.             map.put("ItemText""No." + String.valueOf(i));// 添加图像资源的ID  
    195.   
    196.             srcPageID.add(map);  
    197.         }  
    198.         saPageID.notifyDataSetChanged();  
    199.     }  
    200.   
    201.     //---------------------------------------------------------  
    202.     /** 
    203.      * 表格被点击时的回调函数 
    204.      */  
    205.     public void setTableOnClickListener(OnTableClickListener click) {  
    206.         this.clickListener = click;  
    207.     }  
    208.       
    209.     public interface OnTableClickListener {  
    210.         public void onTableClickListener(int x,int y,Cursor c);  
    211.     }  
    212.     //---------------------------------------------------------  
    213.     /** 
    214.      * 分页栏被点击时的回调函数 
    215.      */  
    216.     public void setOnPageSwitchListener(OnPageSwitchListener pageSwitch) {  
    217.         this.switchListener = pageSwitch;  
    218.     }  
    219.     public interface OnPageSwitchListener {  
    220.         public void onPageSwitchListener(int pageID,int pageCount);  
    221.     }  
    222. }  
    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-23 08:58

    Android提高第十篇之AudioRecord实现"助听器"

    Android 可以通过MediaRecorder和AudioRecord这两个工具来实现录音,MediaRecorder直接把麦克风的数据存到文件,并且能够直接进行编码(如AMR,MP3等),而AudioRecord则是读取麦克风的音频流。本文使用AudioRecord读取音频流,使用 AudioTrack播放音频流,通过“边读边播放”以及增大音量的方式来实现一个简单的助听器程序。

    PS:由于目前的Android模拟器还不支持AudioRecord,因此本程序需要编译之后放到真机运行。

    先贴出本文程序运行截图:

    PS:程序音量调节只是程序内部调节音量而已,要调到最大音量还需要手动设置系统音量。

    1111.png

    使用AudioRecord必须要申请许可,在AndroidManifest.xml里面添加这句:

    1. <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>  

    main.xml的源码如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.   
    6.     <Button android:layout_height="wrap_content" android:id="@+id/btnRecord"  
    7.         android:layout_width="fill_parent" android:text="开始边录边放"></Button>  
    8.     <Button android:layout_height="wrap_content"  
    9.         android:layout_width="fill_parent" android:text="停止" android:id="@+id/btnStop"></Button>  
    10.     <Button android:layout_height="wrap_content" android:id="@+id/btnExit"  
    11.         android:layout_width="fill_parent" android:text="退出"></Button>  
    12.     <TextView android:id="@+id/TextView01" android:layout_height="wrap_content"  
    13.         android:text="程序音量调节" android:layout_width="fill_parent"></TextView>  
    14.     <SeekBar android:layout_height="wrap_content" android:id="@+id/skbVolume"  
    15.         android:layout_width="fill_parent"></SeekBar>  
    16.   
    17. </LinearLayout>  

    testRecord.java的源码如下:

    1. package com.testRecord;  
    2.   
    3. import android.app.Activity;  
    4. import android.media.AudioFormat;  
    5. import android.media.AudioManager;  
    6. import android.media.AudioRecord;  
    7. import android.media.AudioTrack;  
    8. import android.media.MediaRecorder;  
    9. import android.os.Bundle;  
    10. import android.view.View;  
    11. import android.widget.Button;  
    12. import android.widget.SeekBar;  
    13. import android.widget.Toast;  
    14.   
    15. public class testRecord extends Activity {  
    16.     /** Called when the activity is first created. */  
    17.     Button btnRecord, btnStop, btnExit;  
    18.     SeekBar skbVolume;//调节音量  
    19.     boolean isRecording = false;//是否录放的标记  
    20.     static final int frequency = 44100;  
    21.     static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
    22.     static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
    23.     int recBufSize,playBufSize;  
    24.     AudioRecord audioRecord;  
    25.     AudioTrack audioTrack;  
    26.   
    27.     @Override  
    28.     public void onCreate(Bundle savedInstanceState) {  
    29.         super.onCreate(savedInstanceState);  
    30.         setContentView(R.layout.main);  
    31.         setTitle("助听器");  
    32.         recBufSize = AudioRecord.getMinBufferSize(frequency,  
    33.                 channelConfiguration, audioEncoding);  
    34.   
    35.         playBufSize=AudioTrack.getMinBufferSize(frequency,  
    36.                 channelConfiguration, audioEncoding);  
    37.         // -----------------------------------------  
    38.         audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,  
    39.                 channelConfiguration, audioEncoding, recBufSize);  
    40.   
    41.         audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,  
    42.                 channelConfiguration, audioEncoding,  
    43.                 playBufSize, AudioTrack.MODE_STREAM);  
    44.         //------------------------------------------  
    45.         btnRecord = (Button) this.findViewById(R.id.btnRecord);  
    46.         btnRecord.setOnClickListener(new ClickEvent());  
    47.         btnStop = (Button) this.findViewById(R.id.btnStop);  
    48.         btnStop.setOnClickListener(new ClickEvent());  
    49.         btnExit = (Button) this.findViewById(R.id.btnExit);  
    50.         btnExit.setOnClickListener(new ClickEvent());  
    51.         skbVolume=(SeekBar)this.findViewById(R.id.skbVolume);  
    52.         skbVolume.setMax(100);//音量调节的极限  
    53.         skbVolume.setProgress(70);//设置seekbar的位置值  
    54.         audioTrack.setStereoVolume(0.7f, 0.7f);//设置当前音量大小  
    55.         skbVolume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {  
    56.               
    57.             @Override  
    58.             public void onStopTrackingTouch(SeekBar seekBar) {  
    59.                 float vol=(float)(seekBar.getProgress())/(float)(seekBar.getMax());  
    60.                 audioTrack.setStereoVolume(vol, vol);//设置音量  
    61.             }  
    62.               
    63.             @Override  
    64.             public void onStartTrackingTouch(SeekBar seekBar) {  
    65.                 // TODO Auto-generated method stub  
    66.             }  
    67.               
    68.             @Override  
    69.             public void onProgressChanged(SeekBar seekBar, int progress,  
    70.                     boolean fromUser) {  
    71.                 // TODO Auto-generated method stub  
    72.             }  
    73.         });  
    74.     }  
    75.   
    76.     @Override  
    77.     protected void onDestroy() {  
    78.         super.onDestroy();  
    79.         android.os.Process.killProcess(android.os.Process.myPid());  
    80.     }  
    81.   
    82.     class ClickEvent implements View.OnClickListener {  
    83.   
    84.         @Override  
    85.         public void onClick(View v) {  
    86.             if (v == btnRecord) {  
    87.                 isRecording = true;  
    88.                 new RecordPlayThread().start();// 开一条线程边录边放  
    89.             } else if (v == btnStop) {  
    90.                 isRecording = false;  
    91.             } else if (v == btnExit) {  
    92.                 isRecording = false;  
    93.                 testRecord.this.finish();  
    94.             }  
    95.         }  
    96.     }  
    97.   
    98.     class RecordPlayThread extends Thread {  
    99.         public void run() {  
    100.             try {  
    101.                 byte[] buffer = new byte[recBufSize];  
    102.                 audioRecord.startRecording();//开始录制  
    103.                 audioTrack.play();//开始播放  
    104.                   
    105.                 while (isRecording) {  
    106.                     //从MIC保存数据到缓冲区  
    107.                     int bufferReadResult = audioRecord.read(buffer, 0,  
    108.                             recBufSize);  
    109.   
    110.                     byte[] tmpBuf = new byte[bufferReadResult];  
    111.                     System.arraycopy(buffer, 0, tmpBuf, 0, bufferReadResult);  
    112.                     //写入数据即播放  
    113.                     audioTrack.write(tmpBuf, 0, tmpBuf.length);  
    114.                 }  
    115.                 audioTrack.stop();  
    116.                 audioRecord.stop();  
    117.             } catch (Throwable t) {  
    118.                 Toast.makeText(testRecord.this, t.getMessage(), 1000);  
    119.             }  
    120.         }  
    121.     };  
    122. }  

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-23 09:00

    Android提高第十一篇之模拟信号示波器

    上次简单地介绍了AudioRecord和AudioTrack的使用,这次就结合SurfaceView实现一个Android版的手机模拟信号示波器(PS:以前也讲过J2ME版的手机示波器)。最近物联网炒得很火,作为手机软件开发者,如何在不修改手机硬件电路的前提下实现与第三方传感器结合呢?麦克风就是一个很好的ADC接口,通过麦克风与第三方传感器结合,再在软件里对模拟信号做相应的处理,就可以提供更丰富的传感化应用。 先来看看本文程序运行的效果图(屏幕录像速度较慢,真机实际运行起来会更加流畅):   0_1290577166Dx73.gif          本文程序使用8000hz的采样率,对X轴方向绘图的实时性要求较高,如果不降低X轴的分辨率,程序的实时性较差,因此程序对X轴数据缩小区间为8 倍~16倍。由于采用16位采样,因此Y轴数据的高度相对于手机屏幕来说也偏大,程序也对Y轴数据做缩小,区间为1倍~10倍。在SurfaceView 的OnTouchListener方法里加入了波形基线的位置调节,直接在SurfaceView控件上触摸即可控制整体波形偏上或偏下显示。 main.xml源码如下:
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.     <LinearLayout android:id="@+id/LinearLayout01"  
    6.         android:layout_height="wrap_content" android:layout_width="fill_parent"  
    7.         android:orientation="horizontal">  
    8.         <Button android:layout_height="wrap_content" android:id="@+id/btnStart"  
    9.             android:text="开始" android:layout_width="80dip"></Button>  
    10.         <Button android:layout_height="wrap_content" android:text="停止"  
    11.             android:id="@+id/btnExit" android:layout_width="80dip"></Button>  
    12.         <ZoomControls android:layout_width="wrap_content"  
    13.             android:layout_height="wrap_content" android:id="@+id/zctlX"></ZoomControls>  
    14.         <ZoomControls android:layout_width="wrap_content"  
    15.             android:layout_height="wrap_content" android:id="@+id/zctlY"></ZoomControls>  
    16.     </LinearLayout>  
    17.     <SurfaceView android:id="@+id/SurfaceView01"  
    18.         android:layout_height="fill_parent" android:layout_width="fill_parent"></SurfaceView>  
    19. </LinearLayout>  

    ClsOscilloscope.java是实现示波器的类库,包含AudioRecord操作线程和SurfaceView绘图线程的实现,两个线程同步操作,代码如下:

    1. package com.testOscilloscope;  
    2. import java.util.ArrayList;  
    3. import android.graphics.Canvas;  
    4. import android.graphics.Color;  
    5. import android.graphics.Paint;  
    6. import android.graphics.Rect;  
    7. import android.media.AudioRecord;  
    8. import android.view.SurfaceView;  
    9. public class ClsOscilloscope {  
    10.     private ArrayList<short[]> inBuf = new ArrayList<short[]>();  
    11.     private boolean isRecording = false;// 线程控制标记  
    12.     /** 
    13.      * X轴缩小的比例 
    14.      */  
    15.     public int rateX = 4;  
    16.     /** 
    17.      * Y轴缩小的比例 
    18.      */  
    19.     public int rateY = 4;  
    20.     /** 
    21.      * Y轴基线 
    22.      */  
    23.     public int baseLine = 0;  
    24.     /** 
    25.      * 初始化 
    26.      */  
    27.     public void initOscilloscope(int rateX, int rateY, int baseLine) {  
    28.         this.rateX = rateX;  
    29.         this.rateY = rateY;  
    30.         this.baseLine = baseLine;  
    31.     }  
    32.     /** 
    33.      * 开始 
    34.      *  
    35.      * @param recBufSize 
    36.      *            AudioRecord的MinBufferSize 
    37.      */  
    38.     public void Start(AudioRecord audioRecord, int recBufSize, SurfaceView sfv,  
    39.             Paint mPaint) {  
    40.         isRecording = true;  
    41.         new RecordThread(audioRecord, recBufSize).start();// 开始录制线程  
    42.         new DrawThread(sfv, mPaint).start();// 开始绘制线程  
    43.     }  
    44.     /** 
    45.      * 停止 
    46.      */  
    47.     public void Stop() {  
    48.         isRecording = false;  
    49.         inBuf.clear();// 清除  
    50.     }  
    51.     /** 
    52.      * 负责从MIC保存数据到inBuf 
    53.      *  
    54.      * @author GV 
    55.      *  
    56.      */  
    57.     class RecordThread extends Thread {  
    58.         private int recBufSize;  
    59.         private AudioRecord audioRecord;  
    60.         public RecordThread(AudioRecord audioRecord, int recBufSize) {  
    61.             this.audioRecord = audioRecord;  
    62.             this.recBufSize = recBufSize;  
    63.         }  
    64.         public void run() {  
    65.             try {  
    66.                 short[] buffer = new short[recBufSize];  
    67.                 audioRecord.startRecording();// 开始录制  
    68.                 while (isRecording) {  
    69.                     // 从MIC保存数据到缓冲区  
    70.                     int bufferReadResult = audioRecord.read(buffer, 0,  
    71.                             recBufSize);  
    72.                     short[] tmpBuf = new short[bufferReadResult / rateX];  
    73.                     for (int i = 0, ii = 0; i < tmpBuf.length; i++, ii = i  
    74.                             * rateX) {  
    75.                         tmpBuf = buffer[ii];  
    76.                     }  
    77.                     synchronized (inBuf) {//  
    78.                         inBuf.add(tmpBuf);// 添加数据  
    79.                     }  
    80.                 }  
    81.                 audioRecord.stop();  
    82.             } catch (Throwable t) {  
    83.             }  
    84.         }  
    85.     };  
    86.     /** 
    87.      * 负责绘制inBuf中的数据 
    88.      *  
    89.      * @author GV 
    90.      *  
    91.      */  
    92.     class DrawThread extends Thread {  
    93.         private int oldX = 0;// 上次绘制的X坐标  
    94.         private int oldY = 0;// 上次绘制的Y坐标  
    95.         private SurfaceView sfv;// 画板  
    96.         private int X_index = 0;// 当前画图所在屏幕X轴的坐标  
    97.         private Paint mPaint;// 画笔  
    98.         public DrawThread(SurfaceView sfv, Paint mPaint) {  
    99.             this.sfv = sfv;  
    100.             this.mPaint = mPaint;  
    101.         }  
    102.         public void run() {  
    103.             while (isRecording) {  
    104.                 ArrayList<short[]> buf = new ArrayList<short[]>();  
    105.                 synchronized (inBuf) {  
    106.                     if (inBuf.size() == 0)  
    107.                         continue;  
    108.                     buf = (ArrayList<short[]>) inBuf.clone();// 保存  
    109.                     inBuf.clear();// 清除  
    110.                 }  
    111.                 for (int i = 0; i < buf.size(); i++) {  
    112.                     short[] tmpBuf = buf.get(i);  
    113.                     SimpleDraw(X_index, tmpBuf, rateY, baseLine);// 把缓冲区数据画出来  
    114.                     X_index = X_index + tmpBuf.length;  
    115.                     if (X_index > sfv.getWidth()) {  
    116.                         X_index = 0;  
    117.                     }  
    118.                 }  
    119.             }  
    120.         }  
    121.         /** 
    122.          * 绘制指定区域 
    123.          *  
    124.          * @param start 
    125.          *            X轴开始的位置(全屏) 
    126.          * @param buffer 
    127.          *            缓冲区 
    128.          * @param rate 
    129.          *            Y轴数据缩小的比例 
    130.          * @param baseLine 
    131.          *            Y轴基线 
    132.          */  
    133.         void SimpleDraw(int start, short[] buffer, int rate, int baseLine) {  
    134.             if (start == 0)  
    135.                 oldX = 0;  
    136.             Canvas canvas = sfv.getHolder().lockCanvas(  
    137.                     new Rect(start, 0, start + buffer.length, sfv.getHeight()));// 关键:获取画布  
    138.             canvas.drawColor(Color.BLACK);// 清除背景  
    139.             int y;  
    140.             for (int i = 0; i < buffer.length; i++) {// 有多少画多少  
    141.                 int x = i + start;  
    142.                 y = buffer / rate + baseLine;// 调节缩小比例,调节基准线  
    143.                 canvas.drawLine(oldX, oldY, x, y, mPaint);  
    144.                 oldX = x;  
    145.                 oldY = y;  
    146.             }  
    147.             sfv.getHolder().unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像  
    148.         }  
    149.     }  
    150. }  

    testOscilloscope.java是主程序,控制UI和ClsOscilloscope,代码如下:

    1. package com.testOscilloscope;  
    2. import android.app.Activity;  
    3. import android.graphics.Color;  
    4. import android.graphics.Paint;  
    5. import android.media.AudioFormat;  
    6. import android.media.AudioRecord;  
    7. import android.media.MediaRecorder;  
    8. import android.os.Bundle;  
    9. import android.view.MotionEvent;  
    10. import android.view.SurfaceView;  
    11. import android.view.View;  
    12. import android.view.View.OnTouchListener;  
    13. import android.widget.Button;  
    14. import android.widget.ZoomControls;  
    15. public class testOscilloscope extends Activity {  
    16.     /** Called when the activity is first created. */  
    17.     Button btnStart,btnExit;  
    18.     SurfaceView sfv;  
    19.     ZoomControls zctlX,zctlY;  
    20.       
    21.     ClsOscilloscope clsOscilloscope=new ClsOscilloscope();  
    22.       
    23.     static final int frequency = 8000;//分辨率  
    24.     static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
    25.     static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
    26.     static final int xMax = 16;//X轴缩小比例最大值,X轴数据量巨大,容易产生刷新延时  
    27.     static final int xMin = 8;//X轴缩小比例最小值  
    28.     static final int yMax = 10;//Y轴缩小比例最大值  
    29.     static final int yMin = 1;//Y轴缩小比例最小值  
    30.       
    31.     int recBufSize;//录音最小buffer大小  
    32.     AudioRecord audioRecord;  
    33.     Paint mPaint;  
    34.     @Override  
    35.     public void onCreate(Bundle savedInstanceState) {  
    36.         super.onCreate(savedInstanceState);  
    37.         setContentView(R.layout.main);  
    38.         //录音组件  
    39.         recBufSize = AudioRecord.getMinBufferSize(frequency,  
    40.                 channelConfiguration, audioEncoding);  
    41.         audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,  
    42.                 channelConfiguration, audioEncoding, recBufSize);  
    43.         //按键  
    44.         btnStart = (Button) this.findViewById(R.id.btnStart);  
    45.         btnStart.setOnClickListener(new ClickEvent());  
    46.         btnExit = (Button) this.findViewById(R.id.btnExit);  
    47.         btnExit.setOnClickListener(new ClickEvent());  
    48.         //画板和画笔  
    49.         sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);   
    50.         sfv.setOnTouchListener(new TouchEvent());  
    51.         mPaint = new Paint();    
    52.         mPaint.setColor(Color.GREEN);// 画笔为绿色    
    53.         mPaint.setStrokeWidth(1);// 设置画笔粗细   
    54.         //示波器类库  
    55.         clsOscilloscope.initOscilloscope(xMax/2, yMax/2, sfv.getHeight()/2);  
    56.           
    57.         //缩放控件,X轴的数据缩小的比率高些  
    58.         zctlX = (ZoomControls)this.findViewById(R.id.zctlX);  
    59.         zctlX.setOnZoomInClickListener(new View.OnClickListener() {  
    60.             @Override  
    61.             public void onClick(View v) {  
    62.                 if(clsOscilloscope.rateX>xMin)  
    63.                     clsOscilloscope.rateX--;  
    64.                 setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"  
    65.                         +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
    66.             }  
    67.         });  
    68.         zctlX.setOnZoomOutClickListener(new View.OnClickListener() {  
    69.             @Override  
    70.             public void onClick(View v) {  
    71.                 if(clsOscilloscope.rateX<xMax)  
    72.                     clsOscilloscope.rateX++;      
    73.                 setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"  
    74.                         +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
    75.             }  
    76.         });  
    77.         zctlY = (ZoomControls)this.findViewById(R.id.zctlY);  
    78.         zctlY.setOnZoomInClickListener(new View.OnClickListener() {  
    79.             @Override  
    80.             public void onClick(View v) {  
    81.                 if(clsOscilloscope.rateY>yMin)  
    82.                     clsOscilloscope.rateY--;  
    83.                 setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"  
    84.                         +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
    85.             }  
    86.         });  
    87.           
    88.         zctlY.setOnZoomOutClickListener(new View.OnClickListener() {  
    89.             @Override  
    90.             public void onClick(View v) {  
    91.                 if(clsOscilloscope.rateY<yMax)  
    92.                     clsOscilloscope.rateY++;      
    93.                 setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"  
    94.                         +","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
    95.             }  
    96.         });  
    97.     }  
    98.     @Override  
    99.     protected void onDestroy() {  
    100.         super.onDestroy();  
    101.         android.os.Process.killProcess(android.os.Process.myPid());  
    102.     }  
    103.       
    104.     /** 
    105.      * 按键事件处理 
    106.      * @author GV 
    107.      * 
    108.      */  
    109.     class ClickEvent implements View.OnClickListener {  
    110.         @Override  
    111.         public void onClick(View v) {  
    112.             if (v == btnStart) {  
    113.                 clsOscilloscope.baseLine=sfv.getHeight()/2;  
    114.                 clsOscilloscope.Start(audioRecord,recBufSize,sfv,mPaint);  
    115.             } else if (v == btnExit) {  
    116.                 clsOscilloscope.Stop();  
    117.             }  
    118.         }  
    119.     }  
    120.     /** 
    121.      * 触摸屏动态设置波形图基线 
    122.      * @author GV 
    123.      * 
    124.      */  
    125.     class TouchEvent implements OnTouchListener{  
    126.         @Override  
    127.         public boolean onTouch(View v, MotionEvent event) {  
    128.             clsOscilloscope.baseLine=(int)event.getY();  
    129.             return true;  
    130.         }  
    131.           
    132.     }  
    133. }  

     

     

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-30 09:35

    Android提高第十二篇之蓝牙传感应用

    上次介绍了Android利用麦克风采集并显示模拟信号,这种采集手段适用于无IO控制、单纯读取信号的情况。如果传感器本身需要包含控制电路(例如采集血氧信号需要红外和红外线交替发射),那么传感器本身就需要带一片主控IC,片内采集并输出数字信号了。Android手机如何在不改硬件电路的前提下与这类数字传感器交互呢?可选的通信方式就有USB和蓝牙,两种方式各有好处:USB方式可以给传感器供电,蓝牙方式要自备电源;USB接口标准不一,蓝牙普遍支持SPP协议。本文选择蓝牙方式做介绍,介绍 Android的蓝牙API以及蓝牙客户端的用法。
          在Android 2.0,官方终于发布了蓝牙API(2.0以下系统的非官方的蓝牙API可以参考这里:http://code.google.com/p/android-bluetooth/)。Android手机一般以客户端的角色主动连接SPP协议设备(接上蓝牙模块的数字传感器),连接流程是:
    1.使用registerReceiver注册BroadcastReceiver来获取蓝牙状态、搜索设备等消息;
    2.使用BlueAdatper的搜索;
    3.在BroadcastReceiver的onReceive()里取得搜索所得的蓝牙设备信息(如名称,MAC,RSSI);
    4.通过设备的MAC地址来建立一个BluetoothDevice对象;

    5.由BluetoothDevice衍生出BluetoothSocket,准备SOCKET来读写设备;

    6.通过BluetoothSocket的createRfcommSocketToServiceRecord()方法来选择连接的协议/服务,这里用的是SPP(UUID:00001101-0000-1000-8000-00805F9B34FB);
    7.Connect之后(如果还没配对则系统自动提示),使用BluetoothSocket的getInputStream()和getOutputStream()来读写蓝牙设备。

    先来看看本文程序运行的效果图,所选的SPP协议设备是一款单导联心电采集表:

    0_1290738502t5bT.gif

     

    本文的代码较多,可以到这里下载:http://www.pudn.com/downloads305/sourcecode/comm/android/detail1359043.html

    本文程序包含两个Activity(testBlueTooth和WaveDiagram),testBlueTooth是搜索建立蓝牙连接。 BluetoothAdapter、BluetoothDevice和BluetoothSocket的使用很简单,除了前三者提供的功能外,还可以通过给系统发送消息来控制、获取蓝牙信息,例如:

    注册BroadcastReceiver:

    1. IntentFilter intent = new IntentFilter();  
    2. intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果  
    3. intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);  
    4. intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);  
    5. intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);  
    6. registerReceiver(searchDevices, intent);  

    在BroadcastReceiver的onReceive()枚举所有消息的内容:

    1. String action = intent.getAction();  
    2.             Bundle b = intent.getExtras();  
    3.             Object[] lstName = b.keySet().toArray();  
    4.   
    5.             // 显示所有收到的消息及其细节  
    6.             for (int i = 0; i < lstName.length; i++) {  
    7.                 String keyName = lstName.toString();  
    8.                 Log.e(keyName, String.valueOf(b.get(keyName)));  
    9.             }  

    在DDMS里面可以看到BluetoothDevice.ACTION_FOUND返回的消息:

    1.jpg

    程序另外一个Activity~~~WaveDiagram用于读取蓝牙数据并绘制波形图,这里要注意一下JAVA的byte的取值范围是跟C/C++不一样的,Android接收到的byte数据要做"& 0xFF"处理,转为C/C++等值的数据。

     

     

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-30 09:39

    Android提高第十三篇之探秘蓝牙隐藏API

    上次讲解Android的蓝牙基本用法,这次讲得深入些,探讨下蓝牙方面的隐藏API。用过Android系统设置(Setting)的人都知道蓝牙搜索之后可以建立配对解除配对,但是这两项功能的函数没有在SDK中给出,那么如何去使用这两项功能呢?本文利用JAVA的反射机制去调用这两项功能对应的函数:createBond和removeBond,具体的发掘和实现步骤如下:

    1.使用Git工具下载platform/packages/apps/Settings.git,在Setting源码中查找关于建立配对解除配对的API,知道这两个API的宿主(BluetoothDevice);

    2.使用反射机制对BluetoothDevice枚举其所有方法和常量,看看是否存在:

    1. static public void printAllInform(Class clsShow) {  
    2.     try {  
    3.         // 取得所有方法  
    4.         Method[] hideMethod = clsShow.getMethods();  
    5.         int i = 0;  
    6.         for (; i < hideMethod.length; i++) {  
    7.             Log.e("method name", hideMethod.getName());  
    8.         }  
    9.         // 取得所有常量  
    10.         Field[] allFields = clsShow.getFields();  
    11.         for (i = 0; i < allFields.length; i++) {  
    12.             Log.e("Field name", allFields.getName());  
    13.         }  
    14.     } catch (SecurityException e) {  
    15.         // throw new RuntimeException(e.getMessage());  
    16.         e.printStackTrace();  
    17.     } catch (IllegalArgumentException e) {  
    18.         // throw new RuntimeException(e.getMessage());  
    19.         e.printStackTrace();  
    20.     } catch (Exception e) {  
    21.         // TODO Auto-generated catch block  
    22.         e.printStackTrace();  
    23.     }  
    24. }  

    结果如下:

    11-29 09:19:12.012: method name(452): cancelBondProcess
    11-29 09:19:12.020: method name(452): cancelPairingUserInput
    11-29 09:19:12.020: method name(452): createBond
    11-29 09:19:12.020: method name(452): createInsecureRfcommSocket
    11-29 09:19:12.027: method name(452): createRfcommSocket
    11-29 09:19:12.027: method name(452): createRfcommSocketToServiceRecord
    11-29 09:19:12.027: method name(452): createScoSocket
    11-29 09:19:12.027: method name(452): describeContents
    11-29 09:19:12.035: method name(452): equals
    11-29 09:19:12.035: method name(452): fetchUuidsWithSdp
    11-29 09:19:12.035: method name(452): getAddress
    11-29 09:19:12.035: method name(452): getBluetoothClass
    11-29 09:19:12.043: method name(452): getBondState
    11-29 09:19:12.043: method name(452): getName
    11-29 09:19:12.043: method name(452): getServiceChannel
    11-29 09:19:12.043: method name(452): getTrustState
    11-29 09:19:12.043: method name(452): getUuids
    11-29 09:19:12.043: method name(452): hashCode
    11-29 09:19:12.043: method name(452): isBluetoothDock
    11-29 09:19:12.043: method name(452): removeBond
    11-29 09:19:12.043: method name(452): setPairingConfirmation
    11-29 09:19:12.043: method name(452): setPasskey
    11-29 09:19:12.043: method name(452): setPin
    11-29 09:19:12.043: method name(452): setTrust
    11-29 09:19:12.043: method name(452): toString
    11-29 09:19:12.043: method name(452): writeToParcel
    11-29 09:19:12.043: method name(452): convertPinToBytes
    11-29 09:19:12.043: method name(452): getClass
    11-29 09:19:12.043: method name(452): notify
    11-29 09:19:12.043: method name(452): notifyAll
    11-29 09:19:12.043: method name(452): wait
    11-29 09:19:12.051: method name(452): wait
    11-29 09:19:12.051: method name(452): wait

     

    3.如果枚举发现API存在(SDK却隐藏),则自己实现调用方法:

    1. /** 
    2.  * 与设备配对 参考源码:platform/packages/apps/Settings.git 
    3.  * \Settings\src\com\android\settings\bluetooth\CachedBluetoothDevice.java 
    4.  */  
    5. static public boolean createBond(Class btClass,BluetoothDevice btDevice) throws Exception {  
    6.     Method createBondMethod = btClass.getMethod("createBond");  
    7.     Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);  
    8.     return returnValue.booleanValue();  
    9. }  
    10.   
    11. /** 
    12.  * 与设备解除配对 参考源码:platform/packages/apps/Settings.git 
    13.  * \Settings\src\com\android\settings\bluetooth\CachedBluetoothDevice.java 
    14.  */  
    15. static public boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception {  
    16.     Method removeBondMethod = btClass.getMethod("removeBond");  
    17.     Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);  
    18.     return returnValue.booleanValue();  
    19. }  

    PS:SDK之所以不给出隐藏的API肯定有其原因,也许是出于安全性或者是后续版本兼容性的考虑,因此不能保证隐藏API能在所有Android平台上很好地运行。。。

    本文程序运行效果如下:

    0_129099631961F8.gif

     

    main.xml源码如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical" android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent">  
    5.     <LinearLayout android:id="@+id/LinearLayout01"  
    6.         android:layout_height="wrap_content" android:layout_width="fill_parent">  
    7.         <Button android:layout_height="wrap_content" android:id="@+id/btnSearch"  
    8.             android:text="Search" android:layout_width="160dip"></Button>  
    9.         <Button android:layout_height="wrap_content"  
    10.             android:layout_width="160dip" android:text="Show" android:id="@+id/btnShow"></Button>  
    11.     </LinearLayout>  
    12.     <LinearLayout android:id="@+id/LinearLayout02"  
    13.         android:layout_width="wrap_content" android:layout_height="wrap_content"></LinearLayout>  
    14.     <ListView android:id="@+id/ListView01" android:layout_width="fill_parent"  
    15.         android:layout_height="fill_parent">  
    16.     </ListView>  
    17. </LinearLayout>  

    工具类ClsUtils.java源码如下:

    1. package com.testReflect;  
    2.   
    3. import java.lang.reflect.Field;  
    4. import java.lang.reflect.Method;  
    5.   
    6. import android.bluetooth.BluetoothDevice;  
    7. import android.util.Log;  
    8.   
    9. public class ClsUtils {  
    10.   
    11.     /** 
    12.      * 与设备配对 参考源码:platform/packages/apps/Settings.git 
    13.      * \Settings\src\com\android\settings\bluetooth\CachedBluetoothDevice.java 
    14.      */  
    15.     static public boolean createBond(Class btClass,BluetoothDevice btDevice) throws Exception {  
    16.         Method createBondMethod = btClass.getMethod("createBond");  
    17.         Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice);  
    18.         return returnValue.booleanValue();  
    19.     }  
    20.   
    21.     /** 
    22.      * 与设备解除配对 参考源码:platform/packages/apps/Settings.git 
    23.      * \Settings\src\com\android\settings\bluetooth\CachedBluetoothDevice.java 
    24.      */  
    25.     static public boolean removeBond(Class btClass,BluetoothDevice btDevice) throws Exception {  
    26.         Method removeBondMethod = btClass.getMethod("removeBond");  
    27.         Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice);  
    28.         return returnValue.booleanValue();  
    29.     }  
    30.   
    31.     /** 
    32.      *  
    33.      * @param clsShow 
    34.      */  
    35.     static public void printAllInform(Class clsShow) {  
    36.         try {  
    37.             // 取得所有方法  
    38.             Method[] hideMethod = clsShow.getMethods();  
    39.             int i = 0;  
    40.             for (; i < hideMethod.length; i++) {  
    41.                 Log.e("method name", hideMethod.getName());  
    42.             }  
    43.             // 取得所有常量  
    44.             Field[] allFields = clsShow.getFields();  
    45.             for (i = 0; i < allFields.length; i++) {  
    46.                 Log.e("Field name", allFields.getName());  
    47.             }  
    48.         } catch (SecurityException e) {  
    49.             // throw new RuntimeException(e.getMessage());  
    50.             e.printStackTrace();  
    51.         } catch (IllegalArgumentException e) {  
    52.             // throw new RuntimeException(e.getMessage());  
    53.             e.printStackTrace();  
    54.         } catch (Exception e) {  
    55.             // TODO Auto-generated catch block  
    56.             e.printStackTrace();  
    57.         }  
    58.     }  
    59. }  

    主程序testReflect.java的源码如下:

    1. package com.testReflect;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.List;  
    5. import android.app.Activity;  
    6. import android.bluetooth.BluetoothAdapter;  
    7. import android.bluetooth.BluetoothDevice;  
    8. import android.content.BroadcastReceiver;  
    9. import android.content.Context;  
    10. import android.content.Intent;  
    11. import android.content.IntentFilter;  
    12. import android.os.Bundle;  
    13. import android.util.Log;  
    14. import android.view.View;  
    15. import android.widget.AdapterView;  
    16. import android.widget.ArrayAdapter;  
    17. import android.widget.Button;  
    18. import android.widget.ListView;  
    19. import android.widget.Toast;  
    20.   
    21. public class testReflect extends Activity {  
    22.     Button btnSearch, btnShow;  
    23.     ListView lvBTDevices;  
    24.     ArrayAdapter<String> adtDevices;  
    25.     List<String> lstDevices = new ArrayList<String>();  
    26.     BluetoothDevice btDevice;  
    27.     BluetoothAdapter btAdapt;  
    28.   
    29.     @Override  
    30.     public void onCreate(Bundle savedInstanceState) {  
    31.         super.onCreate(savedInstanceState);  
    32.         setContentView(R.layout.main);  
    33.   
    34.         btnSearch = (Button) this.findViewById(R.id.btnSearch);  
    35.         btnSearch.setOnClickListener(new ClickEvent());  
    36.         btnShow = (Button) this.findViewById(R.id.btnShow);  
    37.         btnShow.setOnClickListener(new ClickEvent());  
    38.   
    39.         lvBTDevices = (ListView) this.findViewById(R.id.ListView01);  
    40.         adtDevices = new ArrayAdapter<String>(testReflect.this,  
    41.                 android.R.layout.simple_list_item_1, lstDevices);  
    42.         lvBTDevices.setAdapter(adtDevices);  
    43.         lvBTDevices.setOnItemClickListener(new ItemClickEvent());  
    44.   
    45.         btAdapt = BluetoothAdapter.getDefaultAdapter();// 初始化本机蓝牙功能  
    46.         if (btAdapt.getState() == BluetoothAdapter.STATE_OFF)// 开蓝牙  
    47.             btAdapt.enable();  
    48.   
    49.         // 注册Receiver来获取蓝牙设备相关的结果  
    50.         IntentFilter intent = new IntentFilter();  
    51.         intent.addAction(BluetoothDevice.ACTION_FOUND);  
    52.         intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);  
    53.         registerReceiver(searchDevices, intent);  
    54.   
    55.     }  
    56.   
    57.       
    58.     private BroadcastReceiver searchDevices = new BroadcastReceiver() {  
    59.         public void onReceive(Context context, Intent intent) {  
    60.             String action = intent.getAction();  
    61.             Bundle b = intent.getExtras();  
    62.             Object[] lstName = b.keySet().toArray();  
    63.   
    64.             // 显示所有收到的消息及其细节  
    65.             for (int i = 0; i < lstName.length; i++) {  
    66.                 String keyName = lstName.toString();  
    67.                 Log.e(keyName, String.valueOf(b.get(keyName)));  
    68.             }  
    69.             // 搜索设备时,取得设备的MAC地址  
    70.             if (BluetoothDevice.ACTION_FOUND.equals(action)) {  
    71.                 BluetoothDevice device = intent  
    72.                         .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);  
    73.   
    74.                 if (device.getBondState() == BluetoothDevice.BOND_NONE) {  
    75.                     String str = "未配对|" + device.getName() + "|" + device.getAddress();  
    76.                     lstDevices.add(str); // 获取设备名称和mac地址  
    77.                     adtDevices.notifyDataSetChanged();  
    78.                 }  
    79.             }  
    80.         }  
    81.     };  
    82.   
    83.     class ItemClickEvent implements AdapterView.OnItemClickListener {  
    84.   
    85.         @Override  
    86.         public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
    87.                 long arg3) {  
    88.             btAdapt.cancelDiscovery();  
    89.             String str = lstDevices.get(arg2);  
    90.             String[] values = str.split("\\|");  
    91.             String address=values[2];  
    92.   
    93.             btDevice = btAdapt.getRemoteDevice(address);  
    94.             try {  
    95.                 if(values[0].equals("未配对"))  
    96.                 {     
    97.                     Toast.makeText(testReflect.this"由未配对转为已配对"500).show();  
    98.                     ClsUtils.createBond(btDevice.getClass(), btDevice);  
    99.                 }  
    100.                 else if(values[0].equals("已配对"))  
    101.                 {  
    102.                     Toast.makeText(testReflect.this"由已配对转为未配对"500).show();  
    103.                     ClsUtils.removeBond(btDevice.getClass(), btDevice);  
    104.                 }  
    105.             } catch (Exception e) {  
    106.                 // TODO Auto-generated catch block  
    107.                 e.printStackTrace();  
    108.             }  
    109.         }  
    110.           
    111.     }  
    112.       
    113.     /** 
    114.      * 按键处理 
    115.      * @author GV 
    116.      * 
    117.      */  
    118.     class ClickEvent implements View.OnClickListener {  
    119.   
    120.         @Override  
    121.         public void onClick(View v) {  
    122.             if (v == btnSearch) {//搜索附近的蓝牙设备  
    123.                 lstDevices.clear();  
    124.                   
    125.                 Object[] lstDevice = btAdapt.getBondedDevices().toArray();  
    126.                 for (int i = 0; i < lstDevice.length; i++) {  
    127.                     BluetoothDevice device=(BluetoothDevice)lstDevice;  
    128.                     String str = "已配对|" + device.getName() + "|" + device.getAddress();  
    129.                     lstDevices.add(str); // 获取设备名称和mac地址  
    130.                     adtDevices.notifyDataSetChanged();  
    131.                 }  
    132.                 // 开始搜索  
    133.                 setTitle("本机蓝牙地址:" + btAdapt.getAddress());  
    134.                 btAdapt.startDiscovery();  
    135.             }  
    136.             else if(v==btnShow){//显示BluetoothDevice的所有方法和常量,包括隐藏API  
    137.                 ClsUtils.printAllInform(btDevice.getClass());  
    138.             }  
    139.   
    140.         }  
    141.   
    142.     }  
    143.   
    144.   
    145. }  

     

    加油!在电子行业默默贡献自己的力量!:)
    点赞  2010-11-30 09:45
    12下一页
    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
      写回复