zoukankan      html  css  js  c++  java
  • 2018-2019-2 20189203 移动平台应用开发实践第十一周学习总结

    第43,44,45,46章

    第43章 制作视频

    • 制作视频主要有两种方法,一种是使用内建意图,一种是使用MediaRecorder。
      如果使用默认的Camera应用程序来制作视频,可以使用内建意图。
      如果选择直接处理API而不是使用Camera来为应用程序提供视频制作功能,需要使用MediaRecorder。
      当使用MediaRecorder录制视频时,必须以指定的顺序执行配置步骤,然后调用MediaRecorder.prepare()检查和使用配置。
    private boolean prepareVideoRecorder(){
    
        mCamera = getCameraInstance();
        mMediaRecorder = new MediaRecorder();
    
        // Step 1: Unlock and set camera to MediaRecorder
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);
    
        // Step 2: Set sources
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
    
        // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
    
        // Step 4: Set output file
        mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
    
        // Step 5: Set the preview output
        mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
    
        // Step 6: Prepare configured MediaRecorder
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }
        return true;
    }
    

    以下MediaRecorder的视频录制参数已经有了预设值,不过也可以用下面的方法调整以适用自己的应用:
    setVideoEncodingBitRate()
    setVideoSize()
    setVideoFrameRate()
    setAudioEncodingBitRate()
    setAudioChannels()
    setAudioSamplingRate()
    启动和停止MediaRecorder
    当使用MediaRecorder启动和停止录制时,必须遵从指定的顺序:

    1. Camera.unlock()
    2. 如以上的代码示例配置MediaRecorder
    3. MediaRecorder.start()启动录制
    4. 录制视频
    5. MediaRecorder.stop()停止录制
    6. MediaRecorder.release()释放MediaRecorder
    7. Camera.lock()锁定摄像头
      以下代码演示了怎样使用Camera和MediaRecorder通过一个按钮正确的启动和停止视频录制
      当完成一个视频录制后,不要释放Camera,否则预览视图也会停止
    private boolean isRecording = false;
    
    // Add a listener to the Capture button
    Button captureButton = (Button) findViewById(id.button_capture);
    captureButton.setOnClickListener(
        new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRecording) {
                    // stop recording and release camera
                    mMediaRecorder.stop();  // stop the recording
                    releaseMediaRecorder(); // release the MediaRecorder object
                    mCamera.lock();         // take camera access back from MediaRecorder
    
                    // inform the user that recording has stopped
                    setCaptureButtonText("Capture");
                    isRecording = false;
                } else {
                    // initialize video camera
                    if (prepareVideoRecorder()) {
                        // Camera is available and unlocked, MediaRecorder is prepared,
                        // now you can start recording
                        mMediaRecorder.start();
    
                        // inform the user that recording has started
                        setCaptureButtonText("Stop");
                        isRecording = true;
                    } else {
                        // prepare didn't work, release the camera
                        releaseMediaRecorder();
                        // inform user
                    }
                }
            }
        }
    );
    

    释放相机
    一个设备上,摄像头是所有应用的共享资源,因此在自身的应用处于onPause状态时,要立即释放掉正在使用的Camera对象

    public class CameraActivity extends Activity {
        private Camera mCamera;
        private SurfaceView mPreview;
        private MediaRecorder mMediaRecorder;
    
        ...
    
        @Override
        protected void onPause() {
            super.onPause();
            releaseMediaRecorder();       // if you are using MediaRecorder, release it first
            releaseCamera();              // release the camera immediately on pause event
        }
    
        private void releaseMediaRecorder(){
            if (mMediaRecorder != null) {
                mMediaRecorder.reset();   // clear recorder configuration
                mMediaRecorder.release(); // release the recorder object
                mMediaRecorder = null;
                mCamera.lock();           // lock camera for later use
            }
        }
    
        private void releaseCamera(){
            if (mCamera != null){
                mCamera.release();        // release the camera for other applications
                mCamera = null;
            }
        }
    }
    

    第44章 声音录制

    下边来介绍下这三种录制的方式;
    1、通过Intent调用系统的录音器功能,然后在录制完毕保存以后在onActivityResult中返回录制的音频的uri,然后通过Mediaplayer进行播放
    调用系统的录音器

     private final static int REQUEST_RECORDER = 100;
        private Uri uri;
        public void recorder_Intent(){
            Intent intent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
            startActivityForResult(intent,REQUEST_RECORDER);
        }
    获取返回的信息
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == RESULT_OK && REQUEST_RECORDER == requestCode){
            uri = data.getData();
        }
    }
    <span style="background-color: rgb(255, 255, 255);"><span style="font-size:24px;">通过Mediaplayer进行播放</span></span>
      if (uri != null){
                                if (mediaPlayer != null) {
                                    try {
                                        mediaPlayer.reset();
                                        mediaPlayer.setDataSource(RecorderActivity.this, uri);
                                        mediaPlayer.prepare();
    
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
    
                                }else
                                    Toast.makeText(RecorderActivity.this,"没有成功创建Mediaplayer",Toast.LENGTH_SHORT).show();
                            }
    

    2、通过MediaRecorder来进行音频的录制:
    MediaRecorder 类可用于音频和视频的捕获。再构造了一个MediaRecorder对象之后,为了捕获音频,必须调用setAudioEncoder和setAudioSource这俩个方法。
    假设不调用这些方法,那么将不会录制音频(视频也相同不会),另外,MediaRecorder在准备录制之前通常还会调用setOutputFormat 和setOutputFile,
    在实例化MediaRecorder之后。应该调用的第一个方法是setAudioSource。它採用一个AudioSource内部类中定义的常量作为參数,我们通常使用的常量是MediaRecorder。
    AudioSource.MIC.
    依据顺序,下一个调用的就是setOutputFormat ,这种方法採用在MediaRecorder.OutputFormat内部类中指定的常量作为參数:
    (1)MediaRecorder.OutputFormat.MPEG_4:这个常量指定输出的文件将是一个MPEG_4文件,包括音频跟视频轨
    (2)MediaRecorder.OutputFormat.RAW_AMR;这个常量表示输出一个没有不论什么容器类型的原始文件,仅仅有在捕获没有视频的音频且音频编码器是AMR_NB时才会使用这个常量。
    (3)MediaRecorder.OutputFormat.THREE_GPP:这个常量指定输出的文件将是一个3gpp文件(.3gp)。它可能同一时候包括音频跟视频轨

    MediaRecorder音频编码。在设置输出格式之后,能够调用setAudioEncoder方法来设置应该使用编码器,可能的值指定为MediaRecorder.AudioEncoder类中的常量。出来使用DEFAULT之外,仅仅存在一个其它的值:MediaRecorder.AudioEncoder.AMR_NB,这是自适应多速率窄带编解码器。
    这样的编解码器针对语音进行了优化,因此不适应于语音之外的其它内容。默认情况下他的採样率是8kHz,码率在 4.75~12.2kbps之间。这个俩个数据对于录制语音之外的其它内容而言很低。可是,这是当前可用于MediaRecorder的唯一选择。

    3 使用AudioRecord录制原始音频:
    这就是第三种捕获音频的方法。使用AudioRecord的类。AudioRecord是三个方法中最灵活的(由于他同意訪问原始音频流),可是他是拥有最少的内置功能。如不会自己主动压缩音频等等。
    使用AudioRecord的基础知识很easy。我们仅仅须要构造一个AudioRecord类型的对象,并传入各种不同配置參数。
    须要制定的第一个值就是音频源。以下使用值与之前用于MediaRecorder的值同样,其在MediaRecorder.AudioSource 中定义。实际上。这意味着能够使用MediaRecorder.AudioSource.MIC;
    int audiosource = MediaRecorder.AudioSource.MIC;
    须要指定的下一个值是录制的採样率,应以赫兹为单位,我们知道。MediaRecorder採样的音频是8000赫兹。
    而CD质量的音频一般是44100赫兹(44100Hz)。Hz或赫兹是每秒的样本数量。
    不同的Android手机硬件将可以以不同的採样率进行採样。对于我的这个样例将以11025Hz的採样率来进行採样,这是一个经常使用的採样率。
    int sampleRateInHz = 11025;

       接下来,须要指定捕获的音频通道的数量,在AudioFormat类中指定了用于此參数的常量。并且可依据名称理解他们。
    

    下面将使用单声道配置。
    int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
    随后。须要指定音频格式。
    在AudioFormat类中也指定了一下各种可能的常量。
    AudioFormat.ENCODING_DEFAULT
    AudioFormat.ENCODING_INVALID
    AudioFormat.ENCODING_PCM_16BIT
    AudioFormat.ENCODING_PCM_8BIT

    在这四个选择中,选择PCM_16位和PCM 8位。
    

    PCM代表脉冲编码调制(Pulse Code Modulation) ,这个实际上是原始的音频样本。
    因此能够设置每一个样本的分辨率为16位或8位。16位将占用很多其它的控件和处理能力,但表示的音频将更接近真实。
    int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
    最后将须要指定缓冲区大小。
    时间上能够查询AudioRecord类以获得最小缓冲区大小。查询方式是调用getMinBufferSize的静态方法,同一时候传入採样率,通道配置以及音频格式。

    第45章 处理Handler

    Handler的主要用途

    1. 推送未来某个时间点将要执行的Message或者Runnable到消息队列。
      方法一,通过Handler + Message的方式实现倒计时。代码如下:
    public class MainActivity extends AppCompatActivity {
        private ActivityMainBinding mBinding;
     
        private Handler mHandler ;
     
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
     
            //设置监听事件
            mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //通过Handler + Message的方式实现倒计时
                    for (int i = 1; i <= 10; i++) {
                        Message message = Message.obtain(mHandler);
                        message.what = 10 - i;
                        mHandler.sendMessageDelayed(message, 1000 * i); //通过延迟发送消息,每隔一秒发送一条消息
                    }
                }
            });
     
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    mBinding.time.setText(msg.what + "");   //在handleMessage中处理消息队列中的消息
                }
            };
        }
    }
    

    可以了解到Handler的一个作用就是,在主线程中,可以通过Handler来处理一些有顺序的操作,让它们在固定的时间点被执行。
    方法二,通过Handler + Runnable的方式实现倒计时。代码如下:

    public class MainActivity extends AppCompatActivity {
        private ActivityMainBinding mBinding;
        private Handler mHandler = new Handler();
     
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
     
            //设置监听事件
            mBinding.clickBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    for (int i = 1; i <= 10; i++) {
                        final int fadedSecond = i;
                        //每延迟一秒,发送一个Runnable对象
                        mHandler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                mBinding.time.setText((10 - fadedSecond) + "");
                            }
                        }, 1000 * i);
                    }
                }
            });
        }
    }
    
    1. 在子线程把需要在另一个线程执行的操作加入到消息队列中去。

    第46章 异步工具

    AsyncTask提供了方便的接口实现工作线程和主线程的通信,代码如下:

    public class MyAsyncTask extends AsyncTask<Integer, String, String> {
            private Button btn;
            public MyAsyncTask(Button btn) {
                super();
                this.btn = btn;
            }
      
            @Override
            protected String doInBackground(Integer... integers) {
                Log.e("xxxxxx","xxxxxxexecute传入参数="+integers[0]);
                try {
                    Thread.sleep(1000);
                    publishProgress("过了一秒");
                    Thread.sleep(1000);
                    publishProgress("过了两秒");
                    Thread.sleep(1000);
                    publishProgress("过了三秒");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                return "doInBackground的返回";
            }
            /**
             * 这里的String参数对应AsyncTask中的第三个参数(也就是接收doInBackground的返回值)
             * 在doInBackground方法执行结束之后在运行,并且运行在UI线程当中 可以对UI空间进行设置
             */
            @Override
            protected void onPostExecute(String result) {
                btn.setText("线程结束" + result);
            }
            //该方法运行在UI线程当中,并且运行在UI线程当中 可以对UI空间进行设置
            @Override
            protected void onPreExecute() {
                btn.setText("开始执行异步线程");
            }
            /**
             * 这里的Intege参数对应AsyncTask中的第二个参数
             * 在doInBackground方法当中,,每次调用publishProgress方法都会触发onProgressUpdate执行
             * onProgressUpdate是在UI线程中执行,所有可以对UI空间进行操作
             */
            @Override
            protected void onProgressUpdate(String... values) {
    
                String vlaue = values[0]+"";
                Log.e("xxxxxx","xxxxxx vlaue="+vlaue);
                btn.setText(vlaue+"");
    
    
            }
        }
    

    AsyncTask就是一个封装过的后台任务类,顾名思义就是异步任务。
    AsyncTask定义了三种泛型类型 Params,Progress和Result。
    Params 启动任务执行的输入参数,比如HTTP请求的URL。
    Progress 后台任务执行的百分比。
    Result 后台执行任务最终返回的结果,比如String。
    对应到上面的demo就是Integer, String, String。
    doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里。注意这里不能直接操作UI。此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间。在执行过程中可以调用publicProgress(Progress…)来更新任务的进度。
    onProgressUpdate(String... Progress)这里对应的是doInBackground中调用的publicProgress,在这里进行处理,这里是UI主线程可以进行界面的更新
    onPreExecute()这里相当于线程的开始,可以进行UI的处理
    onPostExecute(Result) 相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
    我们再来看一下如何开启
    myAsyncTask.execute(1000);
    execute的参数对应的就是上面提到过的Params。

  • 相关阅读:
    https://scrapingclub.com/exercise/detail_sign/
    https://scrapingclub.com/exercise/basic_captcha/
    https://scrapingclub.com/exercise/basic_login/
    344. 反转字符串(简单)
    142. 环形链表 II(中等)
    面试题02.07.链表相交
    19. 删除链表的倒数第 N 个结点
    24.两两交换链表中的节点
    206.反转链表(简单)
    707.设计链表
  • 原文地址:https://www.cnblogs.com/23du/p/10853703.html
Copyright © 2011-2022 走看看