編輯:關於Android編程
之前也試過vitamio這個庫,後來不知道被什麼事情給耽擱了,就沒繼續下去。近來覺得視頻還是需要學習一下的,誰讓直播那麼火呢,就想著寫一個簡單的視頻播放的app先吧。好了那就開始吧,暫時取名為JPlayer,後續慢慢改進,源碼也在github上(https://github.com/imchenjianneng/JPlayer),後續不斷更新吧。
首先新建工程JPlayer,然後新建個主界面吧:
這裡簡單簡紹下,具體可以看源碼,界面由是兩個radiobutton,一個viewpager組成,比較簡陋,後續再改吧,我們先實現功能要緊。真實項目一般ui都會提供好界面的。
??既然界面搭建好了,那麼繼續開始代碼實現吧:
public class MainActivity extends BaseActivity implements ViewPager.OnPageChangeListener { private MainBinding binding; private Listbts = Arrays.asList( R.id.rb_local, R.id.rb_intenet); private float normalSize, normalSelected; @Override protected void initParams() { binding = DataBindingUtil.setContentView(getActivity(), R.layout.activity_main); } @Override protected void initViews() { super.initViews(); normalSize = getResources().getDimension(R.dimen.normal_size); normalSelected = getResources().getDimension(R.dimen.selected_size); binding.viewpager.setOffscreenPageLimit(2); binding.viewpager.setAdapter(new MyFragmentPagerAdapter(getSupportFragmentManager())); initTabPagerListener(); binding.rgTab.check(bts.get(0)); } private void initTabPagerListener() { binding.viewpager.addOnPageChangeListener(this); binding.rgTab.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { int i = bts.indexOf(checkedId); if (i != -1) { selectTitle(checkedId); binding.viewpager.setCurrentItem(i); } } }); } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { selectTitle(bts.get(position)); binding.rgTab.check(bts.get(position)); } @Override public void onPageScrollStateChanged(int state) { } private void selectTitle(int selectResId) { binding.rbLocal.setTextSize(TypedValue.COMPLEX_UNIT_PX, normalSize); binding.rbIntenet.setTextSize(TypedValue.COMPLEX_UNIT_PX, normalSize); ((TextView)findViewById(selectResId)).setTextSize(TypedValue.COMPLEX_UNIT_PX, normalSelected); } public class MyFragmentPagerAdapter extends FragmentPagerAdapter { LocalVideoFragment localVideoFragment = new LocalVideoFragment(); InternetVideoFragment internetVideoFragment = new InternetVideoFragment(); private List list = Arrays.asList( localVideoFragment, internetVideoFragment); public MyFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public int getCount() { return list.size(); } @Override public Fragment getItem(int position) { return list.get(position); } } }
代碼其實比較簡單,主要實現了viewpager,然後LocalVideoFragment和InternetVideoFragment兩個fragment,第一個是本地的界面,第二個是網絡(這裡暫時不實現),好了,主要的代碼都在LocalVideoFragment裡了。那麼就接著看這個Frament的代碼了。
既然要播放視頻,首先是需要實現掃描所有視頻文件。先看這一段代碼吧:
private class ScanVideoTask extends AsyncTask{ @Override protected Void doInBackground(Void... params) { eachAllMedias(Environment.getExternalStorageDirectory()); return null; } @Override protected void onProgressUpdate(File... values) { LocalSource localSource = new LocalSource(); localSource.setName(values[0].getName()); localSource.setUrl(values[0].getAbsolutePath()); localSource.setBitmap(getVideoThumbnail(localSource, localSource.getUrl())); localSource.setBitmap(getVideoThumbnail(localSource.getUrl())); Log.d("LocalVideoFragment", "hhh"+localSource.getName()+":"+localSource.getUrl()); fileAdapter.appendItem(localSource); fileAdapter.notifyDataSetChanged(); } /** 遍歷所有文件夾,查找出視頻文件 */ public void eachAllMedias(File f) { if (f != null && f.exists() && f.isDirectory()) { File[] files = f.listFiles(); if (files != null) { for (File file : f.listFiles()) { if (file.isDirectory()) { eachAllMedias(file); } else if (file.exists() && file.canRead() && isVideo(file)) { publishProgress(file); } } } } } }
??掃描需要花費比較長的時間,所以這裡放到一個異步task中去處理,深度優先的搜索所有的文件,掃描到了文件判斷是否為視頻文件,若是的話,那就直接加到recycleview中去。對於是否是視頻文件,這裡僅僅是判斷後綴名,更合理的方式應該是解碼一部分,然後判斷頭文件的信息的,之類就偷懶了一下,具體可以參考源碼。
??既然已經掃描出了文件,那麼接下來就需要這個播放列表了,因為我們要顯示視頻的縮略圖,視頻的文件名,以及播放時長和大小。用到了MediaMetadataRetriever類,通過extractMetadata方法來獲取視頻的相關信息,看下代碼吧:
public Bitmap getVideoThumbnail(LocalSource localSource, String filePath) { Bitmap bitmap = null; MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(filePath); bitmap = retriever.getFrameAtTime(0); localSource.setAuthor(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_AUTHOR)); localSource.setDuration(Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION))); localSource.setDate(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DATE)); localSource.setBitrate(Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE))); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } return bitmap; }
這通過retriever.getFrameAtTime來獲取一幀的圖像bitmap用來當縮略圖,然後通過MediaMetadataRetriever.METADATA_KEY_DURATION獲取播放時長。通過MediaMetadataRetriever.METADATA_KEY_BITRATE獲取比特率,計算就可以得到所需要的文件大小。
要上班去了,接下去的話就是重點了,怎麼使用vitamio,下次繼續了,想直接看代碼的話可以直接github看起來,代碼寫得比較挫,還沒有整理過,為了實現功能而寫。
(一)前言今天我們一起來看一下工具欄控件ToolBarAndroid的介紹完全解析以及最佳實踐。剛創建的React Native技術交流群(282693535),歡迎各位
一、概述在Android的開發中,經常聽到“內存洩漏”這個詞。“內存洩漏”就是一個對象已經不需要再使用了,但是因為其它的對象持有該對象的引用,導致它的內存不能被回收。“內
一、建立測試環境 安裝了Android Developer Tools (ADT) 插件的Eclipse將為你創建,構建,以及運行Android程序提供一個基於圖形界面的
推薦閱讀:Android Webview添加網頁加載進度條實例詳解先給大家展示下效果圖:這個效果圖大家一看就懂,在生活經常見到1.wevbview_progressbar