本节是Android多媒体基本API调用的一节,带来的是MediaRecord的简单使用, 用法很是简单,咱们写个例子来熟悉熟悉~
java
布局代码:activity_main.xml:android
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/btn_control" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始录音" /> </RelativeLayout>
MainActivity.java:程序员
public class MainActivity extends AppCompatActivity { private Button btn_control; private boolean isStart = false; private MediaRecorder mr = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btn_control = (Button) findViewById(R.id.btn_control); btn_control.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(!isStart){ startRecord(); btn_control.setText("中止录制"); isStart = true; }else{ stopRecord(); btn_control.setText("开始录制"); isStart = false; } } }); } //开始录制 private void startRecord(){ if(mr == null){ File dir = new File(Environment.getExternalStorageDirectory(),"sounds"); if(!dir.exists()){ dir.mkdirs(); } File soundFile = new File(dir,System.currentTimeMillis()+".amr"); if(!soundFile.exists()){ try { soundFile.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } mr = new MediaRecorder(); mr.setAudioSource(MediaRecorder.AudioSource.MIC); //音频输入源 mr.setOutputFormat(MediaRecorder.OutputFormat.AMR_WB); //设置输出格式 mr.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB); //设置编码格式 mr.setOutputFile(soundFile.getAbsolutePath()); try { mr.prepare(); mr.start(); //开始录制 } catch (IOException e) { e.printStackTrace(); } } } //中止录制,资源释放 private void stopRecord(){ if(mr != null){ mr.stop(); mr.release(); mr = null; } } }
最后别忘了在AndroidManifest.xml中添加下述权限:数据库
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/>
方法一:(java习惯,在android平台开发时这样是不行的,由于它违背了单线程模型)
刚刚开始接触android线程编程的时候,习惯好像java同样,试图用下面的代码解决问题编程
new Thread( new Runnable() { public void run() { myView.invalidate(); } }).start();
能够实现功能,刷新UI界面。可是这样是不行的,由于它违背了单线程模型:Android UI操做并非线程安全的而且这些操做必须在UI线程中执行。api
方法二:(Thread+Handler)安全
查阅了文档和apidemo后,发觉经常使用的方法是利用Handler来实现UI线程的更新的。网络
Handler来根据接收的消息,处理UI更新。Thread线程发出Handler消息,通知更新UI。异步
Handler myHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case TestHandler.GUIUPDATEIDENTIFIER: myBounceView.invalidate(); break; } super.handleMessage(msg); } };
class myThread implements Runnable { public void run() { while (!Thread.currentThread().isInterrupted()) { Message message = new Message(); message.what = TestHandler.GUIUPDATEIDENTIFIER; TestHandler.this.myHandler.sendMessage(message); try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } }
方法三:(java习惯。Android平台中,这样作是不行的,这跟Android的线程安全有关)ide
在Android平台中须要反复按周期执行方法可使用Java上自带的TimerTask类,TimerTask相对于Thread来讲对于资源消耗的更低,除了使用Android自带的AlarmManager使用Timer定时器是一种更好的解决方法。 咱们须要引入import java.util.Timer; 和 import java.util.TimerTask;
public class JavaTimer extends Activity { Timer timer = new Timer(); TimerTask task = new TimerTask(){ public void run() { setTitle("hear me?"); } }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); timer.schedule(task, 10000); } }
方法四:(TimerTask + Handler)
经过配合Handler来实现timer功能的!
public class TestTimer extends Activity { Timer timer = new Timer(); Handler handler = new Handler(){ public void handleMessage(Message msg) { switch (msg.what) { case 1: setTitle("hear me?"); break; } super.handleMessage(msg); } }; TimerTask task = new TimerTask(){ public void run() { Message message = new Message(); message.what = 1; handler.sendMessage(message); } }; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); timer.schedule(task, 10000); } }
方法五:( Runnable + Handler.postDelayed(runnable,time) )
在Android里定时更新 UI,一般使用的是 java.util.Timer, java.util.TimerTask, android.os.Handler组合。实际上Handler 自身已经提供了定时的功能。
private Handler handler = new Handler(); private Runnable myRunnable= new Runnable() { public void run() { if (run) { handler.postDelayed(this, 1000); count++; } tvCounter.setText("Count: " + count); } };
不少初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask因为目前市面上的书籍等资料都没有谈到这些问题,今天就这一问题作更系统性的总结。咱们建立的Service、Activity以及Broadcast均是一个主线程处理,这里咱们能够理解为UI线程。可是在操做一些耗时操做时,好比I/O读写的大文件读写,数据库操做以及网络下载须要很长时间,为了避免阻塞用户界面,出现ANR的响应提示窗口,这个时候咱们能够考虑使用Thread线程来解决。
对于从事过J2ME开发的程序员来讲Thread比较简单,直接匿名建立重写run方法,调用start方法执行便可。或者从Runnable接口继承,但对于Android平台来讲UI控件都没有设计成为线程安全类型,因此须要引入一些同步的机制来使其刷新,这点Google在设计Android时却是参考了下Win32的消息处理机制。
对于线程中的刷新一个View为基类的界面,可使用postInvalidate()方法在线程中来处理,其中还提供了一些重写方法好比postInvalidate(int left,int top,int right,int bottom) 来刷新一个矩形区域,以及延时执行,好比postInvalidateDelayed(long delayMilliseconds)或postInvalidateDelayed(long delayMilliseconds,int left,int top,int right,int bottom) 方法,其中第一个参数为毫秒
固然推荐的方法是经过一个Handler来处理这些,能够在一个线程的run方法中调用handler对象的 postMessage或sendMessage方法来实现,Android程序内部维护着一个消息队列,会轮训处理这些,若是你是Win32程序员能够很好理解这些消息处理,不过相对于Android来讲没有提供 PreTranslateMessage这些干涉内部的方法。
Looper又是什么呢? ,其实Android中每个Thread都跟着一个Looper,Looper能够帮助Thread维护一个消息队列,可是Looper和Handler没有什么关系,咱们从开源的代码能够看到Android还提供了一个Thread继承类HanderThread能够帮助咱们处理,在HandlerThread对象中能够经过getLooper方法获取一个Looper对象控制句柄,咱们能够将其这个Looper对象映射到一个Handler中去来实现一个线程同步机制,Looper对象的执行须要初始化Looper.prepare方法就是昨天咱们看到的问题,同时推出时还要释放资源,使用Looper.release方法。
4.Message 在Android是什么呢? 对于Android中Handler能够传递一些内容,经过Bundle对象能够封装String、Integer以及Blob二进制对象,咱们经过在线程中使用Handler对象的sendEmptyMessage或sendMessage方法来传递一个Bundle对象到Handler处理器。对于Handler类提供了重写方法handleMessage(Message msg) 来判断,经过msg.what来区分每条信息。将Bundle解包来实现Handler类更新UI线程中的内容实现控件的刷新操做。相关的Handler对象有关消息发送sendXXXX相关方法以下,同时还有postXXXX相关方法,这些和Win32中的道理基本一致,一个为发送后直接返回,一个为处理后才返回 .
java.util.concurrent对象分析,对于过去从事Java开发的程序员不会对Concurrent对象感到陌生吧,他是JDK 1.5之后新增的重要特性做为掌上设备,咱们不提倡使用该类,考虑到Android为咱们已经设计好的Task机制,这里不作过多的赘述,相关缘由参考下面的介绍:
在Android中还提供了一种有别于线程的处理方式,就是Task以及AsyncTask,从开源代码中能够看到是针对Concurrent的封装,开发人员能够方便的处理这些异步任务。
用Java方法来实现异步
主要有两种方法来实现异步,继承Thread类和实现Runnable接口
一、继承Thread类
public class MyThread extends Thread{ private String str; public MyThread(String str){ this.str= str; } @Override public void run(){ System.out.println(str); runOnUIThread(new Runnable() { //此处更新UI }); } } public class MainText{ public static void main(String[] args){ MyThread thread1= new MyThread("myThread1"); MyThread thread2= new MyThread("myThread2"); MyThread thread3= new MyThread("myThread3"); thread1.start(); thread2.start(); thread3.start(); } }
二、实现Runnable接口
public class MyThreadRunnable implements Runnable{ private String str; public MyThreadRunnable(String str){ this.str = str; } @Override public void run(){ System.out.print(str); runOnUIThread(new Runnable(){ //此处更新UI } } } public class MainTest{ public static void main(String[] args){ MyThreadRunnable thread1 = new MyThreadRunnable("runnable1"); MyThreadRunnable thread2 = new MyThreadRunnable("runnable2"); Thread t1 = new Thread(thread1); Thread t2 = new Thread(thread2); t1.start(); t2.start(); } } //或者直接 使用内部类: new Thread(new Runnable(){ @Override public void run(){ System.out.print("执行耗时或者异步操做"); runOnUIThread(new Runnable(){ //此处更新UI }); } });
使用Android 特有的方法实现异步
一、AsyncTask
实现一个内部类并继承AsyncTask类,并重写方法
public class MainActivity extends Activity{ private ProgressBar mProgressBar; private ImageView mImageView; @Override public void onCreate(................){ MyAsyncTask myAsyncTask = new MyAsyncTask(); myAsyncTask.execute("www.baidu.com/xxx.jpg"); } } class MyAsyncTask extends AsyncTask<String, Integer, Bitmap>{ @Override protected void onPreExecture(){ //这里是开始线程以前执行的,是在UI线程 mProgressBar.setMax(100); super.onPreExecute(); } @Override protected Bitmap doInBackground(String... params){ //这是在后台子线程中执行的 Bitmap bitmap = null; try{ URL url = new URL(params[0]); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); InputStream stream = connection.getInputStream(); bitmap = BitmapFactory.decodeStream(inputStrem); publishProgress(70); //这里是更新进度 inputStream.close(); }catch(Exception e){ e.printStackTrace(); } return bitmap; } @Override protected void onCancelled(){ //当任务被取消时回调 super.onCancelled(); } @Override protected void onProgressUpdate(Integer... values){ super.onP......(values); //更新进度 mProgressBar.setProgress(values[0]); } @Override protected void onPostExecute(Bitmap bitmap){ super............(bitmap); //当任务执行完成时调用,在UI线程 mImageView.setImageBitmap(bitmap); }