TextureView SurfaceView 簡介 案例 MD


Markdown版本筆記 我的GitHub首頁 我的博客 我的微信 我的郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目錄

TextureView 簡介

Android普通窗口的視圖繪制機制是一層一層的,任何一個子元素或者是局部的刷新都會導致整個視圖結構全部重繪一次,因此效率相對較低。

視頻或者opengl內容往往是顯示在SurfaceView中的,SurfaceView的工作方式是:創建一個置於應用窗口之后的新窗口。因為SurfaceView窗口刷新的時候不需要重繪應用程序的窗口,所以這種方式的效率非常高。

但是SurfaceView也有一些非常不便的限制,因為SurfaceView的內容不在應用窗口上,所以不能使用平移、縮放、旋轉等變換操作,也難以放在ListView或者ScrollView中,同樣不能使用UI控件的一些特性,比如View.setAlpha()。

為了解決這個問題,Android 4.0 中引入了TextureView,與SurfaceView相比,TextureView並沒有創建一個單獨的 Surface 用來繪制,這使得它可以像一般的View一樣執行一些變換操作,設置透明度等

TextureView的使用非常簡單,你唯一要做的就是獲取用於渲染內容的SurfaceTexture。

Textureview必須在硬件加速開啟的窗口中。

官方文檔

Class Overview
A TextureView can be used to display a content stream. Such a content stream can for instance be a video or an OpenGL scene場景. The content stream can come from the application's process as well as a remote遠程 process.

TextureView can only be used in a hardware accelerated硬件加速 window. When rendered in呈現在 software, TextureView will draw nothing.

Unlike SurfaceView, TextureView does not create a separate單獨的 window but behaves as a regular像平常的 View. This key核心的 difference allows a TextureView to be moved, transformed, animated動畫, etc. For instance, you can make a TextureView semi-translucent半透明 by calling myView.setAlpha(0.5f).

Using a TextureView is simple: all you need to do is get its SurfaceTexture. The SurfaceTexture can then be used to render展示 content. The following example demonstrates how to render the camera preview into a TextureView:

A TextureView's SurfaceTexture can be obtained獲得 either by invoking引用 getSurfaceTexture() or by using a TextureView.SurfaceTextureListener. It is important to know that a SurfaceTexture is available only after the TextureView is attached to a window (and onAttachedToWindow() has been invoked.) It is therefore highly recommended推薦 you use a listener to be notified when the SurfaceTexture becomes available.

It is important to note that only one producer制片人 can use the TextureView. For instance, if you use a TextureView to display the camera preview, you cannot use lockCanvas() to draw onto the TextureView at the same time.

案例:使用TextureView和MediaPlayer播放視頻

Activity

public class TextureViewTestActivity extends Activity implements TextureView.SurfaceTextureListener {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//取消狀態欄
        TextureView textureView = new TextureView(this);
        textureView.setSurfaceTextureListener(this);
        textureView.setRotation(45.0f);//可以像普通View一樣使用平移、縮放、旋轉等變換操作
        textureView.setAlpha(0.5f);
        setContentView(textureView);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        Log.i("bqt", "onSurfaceTextureAvailable");// SurfaceTexture准備就緒
        if (new Random().nextBoolean()) {
            String path = "http://ozvd186ua.bkt.clouddn.com/douyin.mp4";
            MediaPlayerManager.getInstance().playUrlMedia(new Surface(surface), path);
        } else {
            try {
                MediaPlayerManager.getInstance().playAssetMedia(new Surface(surface), getAssets().openFd("douyin.mp4"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        Log.i("bqt", "onSurfaceTextureSizeChanged");// SurfaceTexture緩沖大小變化

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        Log.i("bqt", "onSurfaceTextureDestroyed");// SurfaceTexture即將被銷毀
        MediaPlayerManager.getInstance().stopMedia();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        //Log.i("bqt", "onSurfaceTextureUpdated");// SurfaceTexture通過updateImage更新
    }
}

MediaPlayerManager

public class MediaPlayerManager {

    private MediaPlayer mPlayer;

    private static MediaPlayerManager instance = new MediaPlayerManager();

    private MediaPlayerManager() {//構造方法私有
    }

    public static MediaPlayerManager getInstance() {
        return instance;
    }

    /**
     * 播放網絡或本地中的Media資源
     */
    public void playUrlMedia(Surface surface, String mediaPath) {
        try {
            if (mPlayer == null) {
                mPlayer = new MediaPlayer();
                mPlayer.setDataSource(mediaPath);
            } else {
                if (mPlayer.isPlaying()) {
                    mPlayer.stop();
                }
                mPlayer.reset();
                mPlayer.setDataSource(mediaPath);
            }
            mPlayer.setSurface(surface);
            mPlayer.setVolume(0.5f, 0.5f);
            mPlayer.setLooping(true);
            mPlayer.prepareAsync();
            mPlayer.setOnPreparedListener(MediaPlayer::start);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 播放Asset中的Media資源
     */
    public void playAssetMedia(Surface surface, AssetFileDescriptor fileDescriptor) {
        try {
            if (mPlayer == null) {
                mPlayer = new MediaPlayer();
                mPlayer.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getDeclaredLength());
            } else {
                if (mPlayer.isPlaying()) {
                    mPlayer.stop();
                }
                mPlayer.reset();
                mPlayer.setDataSource(fileDescriptor.getFileDescriptor(), fileDescriptor.getStartOffset(), fileDescriptor.getDeclaredLength());
            }
            mPlayer.setSurface(surface);
            mPlayer.setVolume(0.5f, 0.5f);
            mPlayer.setLooping(true);
            mPlayer.prepareAsync();
            mPlayer.setOnPreparedListener(MediaPlayer::start);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止播放Media
     */
    public void stopMedia() {
        try {
            if (mPlayer != null) {
                if (mPlayer.isPlaying()) {
                    mPlayer.stop();
                }
                mPlayer.release();
                mPlayer = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

案例:使用TextureView和Camera預覽拍照

public class TextureViewTestActivity extends Activity implements TextureView.SurfaceTextureListener {
    private Camera mCamera;//權限【android.permission.CAMERA】

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);//取消狀態欄
        TextureView mTextureView = new TextureView(this);
        mTextureView.setSurfaceTextureListener(this);
        mTextureView.setRotation(45.0f);//可以像普通View一樣使用平移、縮放、旋轉等變換操作
        mTextureView.setAlpha(0.5f);
        setContentView(mTextureView);
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        Log.i("bqt", "onSurfaceTextureAvailable");// SurfaceTexture准備就緒
        try {
            mCamera = Camera.open();//如果提示【Fail to connect to camera service】很可能是沒申請權限,或申請權限了單用戶沒有給你權限
            mCamera.setPreviewTexture(surface);
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        Log.i("bqt", "onSurfaceTextureSizeChanged");// SurfaceTexture緩沖大小變化

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        Log.i("bqt", "onSurfaceTextureDestroyed");// SurfaceTexture即將被銷毀
        mCamera.stopPreview();
        mCamera.release();
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        //Log.i("bqt", "onSurfaceTextureUpdated");// SurfaceTexture通過updateImage更新
    }
}

2018-5-23


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM