使用Android制作视频播放器

使用Android制作视屏播放器

前言

Android小作业,含实现本地视频播放界面,实现全屏播放视频界面,两个界面所采用的的控件不同,可进行比较学习,作为大作业参考代码。

一、展示预览

第一界面:主要使用VideoView、button、mediaConrtroller类
在这里插入图片描述

第二界面:SurfaceView控件和MediaPlayer共同放视频
在这里插入图片描述

将这两个界面进行跳转只需要在跳转的button中设置intent事件即可(具体代码看两个java文件中intent部分)

二、详细步骤

1.准备工作

准备一张背景图,作为界面1背景,命名为bg;准备一个.mp4格式的视频light。如果是其他格式,可以通过【格式工厂】进行格式转换,若无,点击前往下载……

文件界面如图:
文件界面如图

2、主界面设计

确定布局为约束布局,为了方便控制视频的开始与结束,设置两个button来控制播放和暂停,id为start和pause; 通过VideoView将视频导入,id为videoView;

主界面布局代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity"
    android:background="@drawable/bg">

    <VideoView
        android:id="@+id/videoView"
        android:layout_width="match_parent"
        android:layout_height="250dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.239"
        tools:layout_editor_absoluteX="0dp" />

    <Button
        android:id="@+id/start"
        android:layout_width="204dp"
        android:layout_height="71dp"
        android:text="播放"
        android:backgroundTint="@color/black"
        android:textColor="@color/white"
        android:textSize="25dp"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />


    <Button
        android:id="@+id/pause"
        android:layout_width="204dp"
        android:layout_height="68dp"
        android:backgroundTint="@color/black"
        android:textColor="@color/white"
        android:text="暂停"
        android:textSize="25dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.004" />

    <Button
        android:id="@+id/all"
        android:layout_width="match_parent"
        android:layout_height="71dp"
        android:backgroundTint="@color/black"
        android:text="点击全屏播放>>"
        android:textColor="@color/white"
        android:textSize="25dp"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.586" />
</androidx.constraintlayout.widget.ConstraintLayout>

3、主界面java文件

要想让视频播放,需要在java文件设置对应的方法。需要修改对应的id以及包名、文件名。
代码如下:

package com.example.miao1115;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.MediaController;
import android.widget.VideoView;

public class MainActivity extends AppCompatActivity {

    VideoView videoview;
    Button start;
    Button pause;
    MediaController mediaController;
    Button all;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        videoview=findViewById(R.id.videoView);
        all=findViewById(R.id.all);
        mediaController= new MediaController(this);
        initview();
        //跳转全屏界面
        all.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent backmain = new Intent(MainActivity.this, MainActivity2.class);
                startActivity(backmain);
                finish();
            }
        });
    }
    private  void initview(){

        start=findViewById(R.id.start);
        pause=findViewById(R.id.pause);

       start.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               init();
           }
       });
        pause.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                videoview.stopPlayback();
            }
        });
    }
    private void init(){
        //启动视频播放的方法
        String uri="android.resource://"+getPackageName()+"/"+R.raw.light;
        videoview.setVideoURI(Uri.parse(uri));
        videoview.setMediaController(mediaController);
        mediaController.setMediaPlayer(videoview);
        videoview.requestFocus();//设置视频控制组件传入videoview对象
        videoview.start();//设置开始播放
    }

}

4、全屏界面设计

主要应用的是SurfaceView控件和MediaPlayer共同放视频,可以大大减少内存,避免视频卡顿。

使用SurfaceView好处:

  • 使用了双缓存技术
  • 两个线程来完成 一个线程来显示页面 另一个线程来后台计算
  • 两个线程完成任务后,可以实现两个线程交替计算。
  • 可避免线程阻塞

全屏播放界面只需要设置一个返回按钮回到主界面即可,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity2"
    android:id="@+id/cl"
    android:background="@color/black">

    <SurfaceView
        android:id="@+id/sv"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <SeekBar
        android:id="@+id/sbar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="0"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.977" />

    <ImageView
        android:id="@+id/play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:onClick="click"
        android:src="@android:drawable/ic_media_pause"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <Button
        android:id="@+id/back"
        android:layout_width="143dp"
        android:layout_height="70dp"
        android:backgroundTint="@color/black"
        android:text="返回"
        android:textColor="@color/white"
        android:textSize="25dp"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />
</androidx.constraintlayout.widget.ConstraintLayout>

5、全屏布局
注意:在默认情况下全屏是竖屏,显然这不是我们想要的结果。
有两种方法进行调整,第一种方法是在AndroidManifest文件中加入以下语句:

android:screenOrientation="landscape"

但是加过去后,我发现因为这是全局配置文件,会影响主界面也变成横屏,所以如果不是想要所有界面都采用横屏应该采用第二种方法。

第二种办法是在Java文件中设置全屏,为了更为稳定,常常需要一个if语句来对原本是否横屏进行判断,如果不是横屏,就进行横屏设置。加入代码如下:

if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT)
{
     setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}

全屏界面Java完整代码如下:

package com.example.miao1115;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.Toast;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity2 extends AppCompatActivity implements SurfaceHolder.Callback, SeekBar.OnSeekBarChangeListener {
    private SurfaceView sv;
    private SurfaceHolder holder;
    private MediaPlayer mediaplayer;
    private ConstraintLayout cl;
    private Timer timer;
    private TimerTask task;
    private SeekBar sbar;
    private ImageView play;
    private Button back;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if(this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        sv = (SurfaceView) findViewById(R.id.sv);
        // 得到SurfaceView的容器,界面内容是显示在容器里面的
        cl = (ConstraintLayout) findViewById(R.id.cl);
        play = (ImageView) findViewById(R.id.play);
        sbar = (SeekBar) findViewById(R.id.sbar);
        back = findViewById(R.id.back);
        sbar.setOnSeekBarChangeListener(this);
        holder = sv.getHolder();
        // 过时的APT,如果4.0以上的系统不写没问题,否则必须要写
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        holder.addCallback(this);
        // 初始化计时器
        timer = new Timer();
        back.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent backmain = new Intent(MainActivity2.this, MainActivity.class);
                startActivity(backmain);
                finish();
            }
        });

        task = new TimerTask()
        {
            @Override
            public void run()
            {
                if (mediaplayer != null && mediaplayer.isPlaying())
                {
                    int total = mediaplayer.getDuration();
                    sbar.setMax(total);
                    int progress = mediaplayer.getCurrentPosition();
                    sbar.setProgress(progress);
                }
                else{
                    play.setImageResource(android.R.drawable.ic_media_play);
                }
            }
        };
        // 设置TimerTask延迟500ms,每隔500ms执行一次
        timer.schedule(task, 500, 500);
    }
    //播放暂停按钮的点击事件
    public void click(View view)
    {
        if (mediaplayer != null && mediaplayer.isPlaying())
        {
            mediaplayer.pause();
            play.setImageResource(android.R.drawable.ic_media_play);
        } else
        {
            mediaplayer.start();
            play.setImageResource(android.R.drawable.ic_media_pause);
        }
    }
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder)
    {
        try {
            mediaplayer = new MediaPlayer();
            mediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            Uri uri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE+"://"+
                    getPackageName()+"/"+R.raw.light);
            try {
                mediaplayer.setDataSource(MainActivity2.this,uri);
            } catch (IOException e) {
                Toast.makeText(MainActivity2.this,"播放失败",
                        Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
            mediaplayer.setDisplay(holder);
            mediaplayer.prepareAsync();
            mediaplayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener()
            {
                @Override
                public void onPrepared(MediaPlayer mp) {
                    mediaplayer.start();
                }
            });
        } catch (Exception e) {
            Toast.makeText(MainActivity2.this, "播放失败",
                    Toast.LENGTH_SHORT).show();
            e.printStackTrace();
        }
    }
    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { }
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if(mediaplayer. isPlaying()){
            mediaplayer.stop();    }                   }
    @Override
    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    }
    @Override
    public void onStartTrackingTouch(SeekBar seekBar) { }
    @Override
    public void onStopTrackingTouch(SeekBar seekBar)
    {
        int position = seekBar.getProgress();
        if (mediaplayer != null)
        {
            mediaplayer.seekTo(position);
        }
    }

}

总结

针对不同情况选择适合的视频播放器插入方法,但是如果可以像平常使用腾讯、爱奇艺在视频播放角落处设置一个全屏按钮,不用进行页面跳转的话会更好。具体实现还在学习中。

  • 6
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经过本地编译可运行的,下载完成之后配置相应环境即可使用。源码功能都是经过老师肯定的,都能满足要求,有需要放心下载即可。源码是经

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喵小胡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值