flutter调用视屏播放和音乐播放

本文讲解的是flutter与android原生通信,调用视屏播放和音乐播放的功能,如果要使用音乐播放那么肯定是需要用到网络资源的,在写代码之前先将权限添加,添加了这些权限即可以使用网络资源也可以使用本地资源,但是要使用网络资源还需要添加另外的资源

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />读取权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 写入权限
    <uses-permission android:name="android.permission.INTERNET" /> 网络权限

在res文件下下添加xml文件夹,再在里面添加一个network_security_config.xml 资源文件,应用程序不访问有些网络资源比如https的资源他使用不了,所以需要添加这个文件,它是用来配置网络安全策略,然后在AndroidManifest.xml中的Application里面将这个资源文件添加到应用程序当中,这样就能使用所有网络资源啦

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true"/>
</network-security-config>
 <application
        android:icon="@mipmap/ic_launcher"
        android:label="flutter_android"
        android:networkSecurityConfig="@xml/network_security_config"
        android:theme="@style/Theme.AppCompat.NoActionBar">

接下来开始写代码 

首先是视屏播放

需要写原生代码,使用VideoView这个控件来展示播放视频

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@android:color/white"
    tools:context=".PlayVideoActivity"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <VideoView
        android:id="@+id/mVideoViewLand"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

然后再写java代码 ,代码中已经详细注释了说明,这边就不过多赘述

package com.example.flutter_android;
import android.content.Intent;
import android.content.res.Configuration;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.view.OrientationEventListener;
import android.widget.MediaController;
import android.widget.VideoView;

import androidx.annotation.NonNull;

import io.flutter.embedding.android.FlutterActivity;

public class PlayVideoActivity extends FlutterActivity {
    
    private VideoView mVideoView;
    private MediaController mediaController;
    private String path;
    private OrientationEventListener orientationEventListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        path = getIntent().getStringExtra("path");
        if(mediaController == null){
            initView();
        }
        isOrientation();
    }
    private void isOrientation(){
        则合格是用来判断手机的横竖屏的
        int currentOrientation = getResources().getConfiguration().orientation;
        if(currentOrientation == Configuration.ORIENTATION_PORTRAIT){
            setContentView(R.layout.activiti_play_video_land);
            mVideoView = findViewById(R.id.mVideoViewLand);
            initData();
            System.out.println("竖屏");
        }else{
            setContentView(R.layout.activity_play_video);
            mVideoView = findViewById(R.id.mVideoView);
            initData();
            System.out.println("横屏");
        }
    }

    //当屏幕方向发生改变的时候调用这个方法
    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            setContentView(R.layout.activiti_play_video_land);
            mVideoView = findViewById(R.id.mVideoViewLand);
            initData();
        }else{
            setContentView(R.layout.activity_play_video);
            mVideoView = findViewById(R.id.mVideoView);
            initData();
        }
    }

    private void initView(){
        初始化控制器,用来控制视屏的播放和视屏的进度
        mediaController = new MediaController(this);
    }
    private void initData() {
        在视屏播放器中将播放控制器添加进去
        mVideoView.setMediaController(mediaController);
        //这个是使用本地资源视屏
        Uri videoUri = Uri.parse("android.resource://" + getPackageName() + "/raw/play1");
        

        mVideoView.setVideoURI(videoUri);
        //如果想使用网络资源那么将上方代码替换成下方代码
        mVideoView.setVideoPath(path);
        //监听播放是否完成
        mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
         
            @Override
            public void onCompletion(MediaPlayer mp) {
                mVideoView.suspend();
                backResult("1");
            }
        });
        mVideoView.start();
    }
    //结果返回的方法
    private void backResult(String result){
        Intent intent = new Intent();
        intent.putExtra("result",result);
        setResult(RESULT_OK,intent);
        finish();
    }
    //当意外返回的时候将自动调用backResult将返回值设置为0表示播放未完成
    @Override
    protected void onDestroy() {
        mVideoView.suspend();
        backResult("0");
        super.onDestroy();
    }
}

当进入之后屏幕方向发生改变的时候会重新更新Activitiy,那么就会退回到flutter页面中,我想要的效果是当切换屏幕方向时,只需要切换到另一个xml文件视图,这样的话就需要在AndroidManifest再添加一行代码


configChanges="orientation | screenSize" 告诉系统不要销毁当前活动,而是自行处理配置更改。
<activity
            android:name=".PlayVideoActivity"
            android:configChanges="orientation|screenSize" 
            android:exported="false" />

调用音乐播放功能

这是界面代码,用来展示音乐播放的界面,当中写了一个动画,用来当音乐播放时,图片进行旋转,控件的作用已在代码中注释

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical"
    tools:context=".PlayMusic">


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="24dp"
        android:layout_marginTop="40dp"
        android:textColor="@android:color/black"
        android:text="标题"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textSize="16dp"
        android:textColorHint="@android:color/darker_gray"
        android:textColor="@android:color/black"
        android:text="歌手"/>
    
    //将音乐图片设置为原型
    <androidx.cardview.widget.CardView
        android:layout_height="200dp"
        android:layout_width="200dp"
        android:layout_gravity="center"
        app:cardCornerRadius="100dp"
        app:cardElevation="50dp"
        android:layout_marginVertical="20dp">
        <ImageView
            android:id="@+id/mImgView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@mipmap/music_logo"
            android:scaleType="fitXY"/>
    </androidx.cardview.widget.CardView>
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center">

        //展示播放视屏的当前进度
        <TextView
            android:id="@+id/mPosition"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textSize="16dp"
            android:textColorHint="@android:color/black"
            android:textColor="@android:color/black"
            android:text="歌手"/>
        
        //用来控制播放视屏的进度
        <SeekBar
            android:id="@+id/mSeekBar"
            android:layout_width="300dp"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_gravity="center"
            android:layout_height="wrap_content">

        </SeekBar>
        //视屏播放的最大进度
        <TextView
            android:id="@+id/mDuration"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:textSize="16dp"
            android:textColorHint="@android:color/black"
            android:textColor="@android:color/black"
            android:text="00:00"/>
    </LinearLayout>

    用来控制播放或暂停
    <ImageButton
        android:layout_marginTop="20dp"
        android:id="@+id/mImgBtn"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:scaleType="fitXY"
        android:src="@mipmap/play_icon"
        android:background="@android:color/white"
        android:layout_gravity="center"/>

</LinearLayout>

现在开始写java代码,同样的以便于理解我将说明都写在了代码注释上

package com.example.flutter_android;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.MediaController;
import android.widget.SeekBar;
import android.widget.TextView;

import java.util.Locale;

public class PlayMusic extends AppCompatActivity {
    private TextView mPosition;
    private TextView mDuration;
    private SeekBar mSeekBar;
    private ImageView mImgView;
    private ImageButton mImgBtn;
    private MediaPlayer mediaPlayer;
    private ObjectAnimator rotationAnimator;
    private Handler handler;
    private Runnable mRunnable;
    private long runTime;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_music);
        initView();
    }


    private void initView() {
        //初始化通过查找id获取界面中的控件
        mPosition = findViewById(R.id.mPosition);
        mDuration = findViewById(R.id.mDuration);
        mSeekBar = findViewById(R.id.mSeekBar);
        mImgView = findViewById(R.id.mImgView);
        mImgBtn = findViewById(R.id.mImgBtn);
        
        handler = new Handler();//初始化线程通信, 他是用来重复使用一个线程更新ui
        mediaPlayer = MediaPlayer.create(this,R.raw.music2);    //初始化音乐播放控件,资源文件选择本地
        如果想要使用网络资源那么将以上代码替换成下方代码
        mediaPlayer = new MediaPlayer();   
        try {
            mediaPlayer.setDataSource("path"); //将网络地址放入
            mediaPlayer.prepareAsync();        //异步在后台进行准备工作,这样可以避免在网络请求过程中主线程被阻塞,提高流畅性。
        }catch (Exception e){
            e.printStackTrace();
        }

        //添加播放按钮事件
        mImgBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                playMusic();
            }
        });
        //监听设置好资源后初始化数据,直接播放
        mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
       
                mDuration.setText(formatTime(mp.getDuration()));
                mSeekBar.setMax(mp.getDuration());
                handler.post(mRunnable);    //将代码块放入主线程队列中
                playMusic();    //播放
            }
        });
        //播放完成监听
        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                backResult();
            }
        });
            //监听进度条修改时进行的操作
        mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            //当进度条被改变时
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                mPosition.setText(formatTime(progress));
            }
            
            //当用户拉动进度条时
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                mPosition.setText(formatTime(seekBar.getProgress()));
                mediaPlayer.pause();
                //由于动画会重新播放,所以保存上一次动画的进度
                runTime = rotationAnimator.getCurrentPlayTime();
                rotationAnimator.cancel();
                mImgBtn.setImageResource(R.mipmap.play_icon);
            }

            //当拉动进度条完成时
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                mediaPlayer.seekTo(seekBar.getProgress());
                mediaPlayer.start();
                mImgBtn.setImageResource(R.mipmap.pause_icon);
                setImgView();
            }
        });
        

        将需要在单独线程中执行的代码逻辑放在其中
        mRunnable = new Runnable() {
            @Override
            public void run() {
                if(mediaPlayer.isPlaying()){
                    mSeekBar.setProgress(mediaPlayer.getCurrentPosition());
                }
                //每隔一秒执行当前代码块
                handler.postDelayed(this,1000);
            }
        };
    }

    private void backResult() {
        setResult(RESULT_OK);
        handler.removeCallbacks(mRunnable);
        rotationAnimator.cancel();
        mediaPlayer.release();
        finish();
    }

    
    //用来处理时间返回字符串
    private String formatTime(int duration) {
        int minute = (duration / (1000 * 60)) % 60;
        int seconds = (duration / 1000) % 60;
        return String.format(
                Locale.getDefault(),
                "%02d:%02d",minute,seconds
        );
    }
    
    
    private void playMusic() {
        //当歌曲正在播放时进行的操作
        if(mediaPlayer.isPlaying()){
            mediaPlayer.pause();
            //这个变量在进度条监听的时候讲过
            runTime = rotationAnimator.getCurrentPlayTime();
            rotationAnimator.cancel();
            mImgBtn.setImageResource(R.mipmap.play_icon);
        }else{
            mediaPlayer.start();
            mImgBtn.setImageResource(R.mipmap.pause_icon);
            setImgView();
        }
    }

    @Override
    protected void onDestroy() {
        backResult();
        super.onDestroy();
    }

    private void setImgView() {
        rotationAnimator = ObjectAnimator.ofFloat(mImgView,"rotation",0f,360f);
        rotationAnimator.setDuration(10000);
        rotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
        rotationAnimator.setInterpolator(new LinearInterpolator());
        rotationAnimator.setCurrentPlayTime(runTime);
        rotationAnimator.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值