├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── leo │ │ └── ijkplayer │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── leo │ │ │ └── ijkplayer │ │ │ ├── App.java │ │ │ ├── ListActivity.java │ │ │ └── MainActivity.java │ └── res │ │ ├── drawable-xhdpi │ │ └── xxx2.png │ │ ├── layout │ │ ├── activity_list.xml │ │ ├── activity_main.xml │ │ └── item_video.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── leo │ └── ijkplayer │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── player ├── .gitignore ├── build.gradle ├── gradle.properties ├── maven_push.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── leo │ │ └── player │ │ └── media │ │ ├── IjkVideoManager.java │ │ ├── Settings.java │ │ ├── StateChangeListener.java │ │ ├── controller │ │ ├── IMediaController.java │ │ └── MediaController.java │ │ ├── datasource │ │ └── FileMediaDataSource.java │ │ ├── render │ │ ├── IRenderView.java │ │ ├── SurfaceRenderView.java │ │ └── TextureRenderView.java │ │ ├── util │ │ ├── CommonUtils.java │ │ ├── LoggerUtils.java │ │ ├── MeasureHelper.java │ │ ├── NetworkUtils.java │ │ ├── OrientationUtils.java │ │ ├── SimpleTransitionListener.java │ │ └── StorageUtils.java │ │ ├── videoview │ │ ├── IVideoView.java │ │ └── IjkVideoView.java │ │ └── weiget │ │ ├── ENDownloadView.java │ │ └── ENPlayView.java │ └── res │ ├── anim │ ├── fade_in.xml │ └── fade_out.xml │ ├── drawable-xhdpi │ ├── brightness.png │ ├── fast_forward.png │ ├── video_enlarge.png │ ├── video_shrink.png │ ├── volume_1.png │ ├── volume_2.png │ └── volume_x.png │ ├── drawable │ ├── video_dialog_progress.xml │ ├── video_position_bg.xml │ ├── video_progress.xml │ ├── video_seek_progress.xml │ ├── video_seek_thumb.xml │ ├── video_seek_thumb_normal.xml │ └── video_seek_thumb_pressed.xml │ ├── layout │ ├── dialog_brightness.xml │ ├── dialog_video_position.xml │ ├── dialog_volume.xml │ └── media_controller.xml │ └── values │ ├── attr.xml │ └── styles.xml └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .idea 5 | .DS_Store 6 | /build 7 | /captures 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 因为最近项目有视频播放的需求,所以就有了这个项目。视频的编解码功能是由 Bilibili 开源的 ijkplayer 处理的,这个项目只是基于 UI 层面的上封装。 3 | > **注意:** 这个项目部分代码参考于 GSYVideoPlayer。 4 | 5 | ## 感谢 6 | * [ijkplayer](https://github.com/Bilibili/ijkplayer) 7 | * [AndroidVideoCache](https://github.com/danikula/AndroidVideoCache) 8 | * [GSYVideoPlayer](https://github.com/CarGuo/GSYVideoPlayer) 9 | * [ENViews](https://github.com/codeestX/ENViews) 10 | 11 | ![](https://user-gold-cdn.xitu.io/2017/8/24/eb05fe5b0eb7cb5e061cf82970f67e29) 12 | 13 | ## 功能 14 | * 播放器的基础功能(播放,暂停,快进等等) 15 | * 支持列表播放,自动释放上一个播放器 16 | * 视频封面图设置 17 | * 提供两种视频全屏(设置屏幕的旋转方向和添加一个全屏的播放器) 18 | * 手势滑动改变播放进度,屏幕亮度和音量 19 | * 简单的 Wifi 网络检查 20 | * 使用 AndroidVideoCache 实现的视频缓存 21 | * 添加全屏播放器转场动画 **(New)** 22 | * 待续。。。 23 | 24 | ## 用法 25 | 在列表中使用,这里的代码是基于 `RecyclerView` 的: 26 | ``` java 27 | @Override 28 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 29 | View contentView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false); 30 | ViewHolder viewHolder = new ViewHolder(contentView); 31 | viewHolder.controller = new MediaController(parent.getContext()); 32 | viewHolder.controller.setEnableSlideBrightness(false); 33 | viewHolder.controller.setEnableSliderVolume(false); 34 | viewHolder.controller.setEnableSlidePosition(false); 35 | // viewHolder.controller.setFullScreenViewEnableSlideBrightness(false); 36 | // viewHolder.controller.setFullScreenViewEnableSlidePosition(false); 37 | // viewHolder.controller.setFullScreenViewEnableSliderVolume(false); 38 | viewHolder.controller.setFullScreenMode(MediaController.FULLSCREEN_VIEW); 39 | viewHolder.controller.setMute(true); 40 | viewHolder.controller.setShowBottomLayout(false); 41 | viewHolder.video.setMediaController(viewHolder.controller); 42 | mVideoWidth = parent.getContext().getResources().getDisplayMetrics().widthPixels; 43 | mVideoHeight = viewHolder.video.getLayoutParams().height; 44 | return viewHolder; 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(final ViewHolder holder, int position) { 49 | holder.video.setVideoPath(VIDEO_URL); 50 | holder.video.setPlayPosition(position); 51 | holder.controller.setPlayPosition(position); 52 | holder.controller.setOnClickListener(new View.OnClickListener() { 53 | @Override 54 | public void onClick(View v) { 55 | holder.controller.toggleFullScreenView(); 56 | } 57 | }); 58 | if (holder.controller.getImgThumb() != null) { 59 | Glide 60 | .with(holder.itemView.getContext()) 61 | .load(IMGS[position]) 62 | .apply(RequestOptions.centerCropTransform()) 63 | .into(holder.controller.getImgThumb()); 64 | } else { 65 | Log.d(getClass().getSimpleName(), "Thumb ImgView is null"); 66 | } 67 | 68 | } 69 | 70 | ``` 71 | 这里需要注意的是,在列表中使用,需要开发者在 Item 不可见的时候,手动释放播放器,来节约内存。 72 | ``` java 73 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 74 | 75 | @Override 76 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 77 | super.onScrollStateChanged(recyclerView, newState); 78 | if (newState == RecyclerView.SCROLL_STATE_IDLE) { 79 | autoPlay(); 80 | } 81 | } 82 | 83 | @Override 84 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 85 | super.onScrolled(recyclerView, dx, dy); 86 | 87 | if (IjkVideoManager.getInstance().getPlayPosition() > -1) { 88 | int position = IjkVideoManager.getInstance().getPlayPosition(); 89 | if (!isVisible(position)) { 90 | IjkVideoManager.getInstance().release(); 91 | } 92 | } 93 | } 94 | }); 95 | 96 | ``` 97 | 而在单个播放器的页面使用,则相对要简单一点: 98 | ``` java 99 | mIjkVideoView = (IjkVideoView) findViewById(R.id.video_view); 100 | MediaController mediaController = new MediaController(this); 101 | mediaController.setShowThumb(true); 102 | mIjkVideoView.setMediaController(mediaController); 103 | 104 | mIjkVideoView.setVideoPath("http://baobab.wdjcdn.com/14564977406580.mp4"); 105 | 106 | ``` 107 | 需要注意的地方是,不管是列表中使用,还是只是单个播放器,都需要在页面关闭时,手动调用释放播放器: 108 | ``` java 109 | @Override 110 | protected void onDestroy() { 111 | super.onDestroy(); 112 | IjkVideoManager.getInstance().release(); 113 | } 114 | 115 | @Override 116 | protected void onPause() { 117 | super.onPause(); 118 | IjkVideoManager.getInstance().pause(); 119 | } 120 | 121 | ``` 122 | 更多代码可以参见项目。 123 | 124 | 有这方面需要的朋友可以自由复制属于我的代码,唯一希望就是能给我提点 Bug,或者有更好的实现,多谢。 125 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.leo.ijkplayer" 8 | minSdkVersion 19 9 | targetSdkVersion 25 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:25.3.1' 28 | testCompile 'junit:junit:4.12' 29 | compile project(':player') 30 | // compile 'com.leo.android:player:1.0.4-SNAPSHOT' 31 | compile 'com.android.support:recyclerview-v7:25.3.1' 32 | debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.2' 33 | releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.2' 34 | 35 | annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0' 36 | compile 'com.github.bumptech.glide:glide:4.0.0' 37 | } 38 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/linxiaotao/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/leo/ijkplayer/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.leo.ijkplayer; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.leo.ijkplayer", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 15 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/leo/ijkplayer/App.java: -------------------------------------------------------------------------------- 1 | package com.leo.ijkplayer; 2 | 3 | import android.app.Application; 4 | 5 | import com.squareup.leakcanary.LeakCanary; 6 | 7 | /** 8 | * Created on 2017/8/17 上午10:08. 9 | * leo linxiaotao1993@vip.qq.com 10 | */ 11 | 12 | public class App extends Application { 13 | 14 | 15 | @Override 16 | public void onCreate() { 17 | super.onCreate(); 18 | 19 | if (!LeakCanary.isInAnalyzerProcess(this)){ 20 | LeakCanary.install(this); 21 | } 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/leo/ijkplayer/ListActivity.java: -------------------------------------------------------------------------------- 1 | package com.leo.ijkplayer; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.support.v7.widget.LinearLayoutManager; 8 | import android.support.v7.widget.RecyclerView; 9 | import android.util.Log; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.Button; 14 | 15 | import com.bumptech.glide.Glide; 16 | import com.bumptech.glide.request.RequestOptions; 17 | import com.leo.player.media.IjkVideoManager; 18 | import com.leo.player.media.controller.MediaController; 19 | import com.leo.player.media.util.NetworkUtils; 20 | import com.leo.player.media.videoview.IjkVideoView; 21 | 22 | 23 | /** 24 | * Created on 2017/8/15 下午5:08. 25 | * leo linxiaotao1993@vip.qq.com 26 | */ 27 | 28 | public class ListActivity extends AppCompatActivity { 29 | 30 | private RecyclerView mRecyclerView; 31 | private Button mBtnDetail; 32 | private LinearLayoutManager mLinearLayoutManager; 33 | /** 上一次播放下标 */ 34 | private int mPrePlayPosition = -1; 35 | 36 | private static final String VIDEO_URL = "http://baobab.wdjcdn.com/14564977406580.mp4"; 37 | 38 | @Override 39 | protected void onCreate(@Nullable Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_list); 42 | 43 | mBtnDetail = (Button) findViewById(R.id.btn_detail); 44 | mBtnDetail.setOnClickListener(new View.OnClickListener() { 45 | @Override 46 | public void onClick(View v) { 47 | Intent intent = new Intent(ListActivity.this, MainActivity.class); 48 | startActivity(intent); 49 | } 50 | }); 51 | 52 | mRecyclerView = (RecyclerView) findViewById(R.id.recyclerview); 53 | mRecyclerView.setLayoutManager(mLinearLayoutManager = new LinearLayoutManager(this)); 54 | mRecyclerView.setAdapter(new Adapter()); 55 | mRecyclerView.post(new Runnable() { 56 | @Override 57 | public void run() { 58 | autoPlay(); 59 | } 60 | }); 61 | mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 62 | 63 | @Override 64 | public void onScrollStateChanged(RecyclerView recyclerView, int newState) { 65 | super.onScrollStateChanged(recyclerView, newState); 66 | if (newState == RecyclerView.SCROLL_STATE_IDLE) { 67 | autoPlay(); 68 | } 69 | } 70 | 71 | @Override 72 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) { 73 | super.onScrolled(recyclerView, dx, dy); 74 | 75 | if (IjkVideoManager.getInstance().getPlayPosition() > -1) { 76 | int position = IjkVideoManager.getInstance().getPlayPosition(); 77 | if (!isVisible(position)) { 78 | IjkVideoManager.getInstance().release(); 79 | } 80 | } 81 | } 82 | }); 83 | 84 | } 85 | 86 | 87 | /** 自动播放 */ 88 | private void autoPlay() { 89 | if (!NetworkUtils.isWifiConnected(this)) { 90 | return; 91 | } 92 | int firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition(); 93 | int lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition(); 94 | int position = (firstVisibleItem + lastVisibleItem) / 2; 95 | if (mPrePlayPosition != position && !isVisible(mPrePlayPosition)) { 96 | mPrePlayPosition = position; 97 | ViewHolder viewHolder = (ViewHolder) mRecyclerView.findViewHolderForAdapterPosition(position); 98 | viewHolder.controller.setPreparedPlay(true); 99 | viewHolder.video.openVideo(); 100 | } 101 | } 102 | 103 | /** 104 | * 当前下标是否可见 105 | * 106 | * @param position 107 | * @return 108 | */ 109 | private boolean isVisible(int position) { 110 | int firstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition(); 111 | int lastVisibleItem = mLinearLayoutManager.findLastVisibleItemPosition(); 112 | return !(position < firstVisibleItem || position > lastVisibleItem); 113 | } 114 | 115 | @Override 116 | protected void onPause() { 117 | super.onPause(); 118 | IjkVideoManager.getInstance().pause(); 119 | } 120 | 121 | @Override 122 | protected void onDestroy() { 123 | super.onDestroy(); 124 | IjkVideoManager.getInstance().release(); 125 | } 126 | 127 | 128 | private static class Adapter extends RecyclerView.Adapter { 129 | 130 | private int mVideoWidth; 131 | private int mVideoHeight; 132 | 133 | private static final String[] IMGS = {"http://pic4.nipic.com/20091217/3279936_085313832375_2.jpg" 134 | , "https://b-ssl.duitang.com/uploads/item/201203/21/20120321162242_wdG8r.thumb.700_0.jpeg" 135 | , "http://imgsrc.baidu.com/baike/pic/item/f636afc379310a550e25d28ab34543a98226104e.jpg" 136 | , "http://c1.hoopchina.com.cn/uploads/star/event/images/141208/067438ed3ecdbdff6067d056315aed16ed2d3358.jpg" 137 | , "http://b.zol-img.com.cn/desk/bizhi/image/1/960x600/1348724812863.jpg" 138 | , "http://news.cnhubei.com/xw/ty/201612/W020161226410633306261.jpeg" 139 | , "http://img.zybus.com/uploads/allimg/141110/1-141110163R2.jpg" 140 | , "http://img4q.duitang.com/uploads/item/201406/26/20140626135444_jruft.jpeg" 141 | , "http://img0.imgtn.bdimg.com/it/u=2763254483,2728302026&fm=214&gp=0.jpg" 142 | , "http://cdn.duitang.com/uploads/item/201411/27/20141127184622_SEwUF.jpeg" 143 | , "http://pic19.nipic.com/20120320/8279160_140432483114_2.jpg" 144 | , "http://img1.gtimg.com/sports/pics/hv1/232/231/1859/120940612.jpg" 145 | , "http://img.zybus.com/uploads/allimg/141110/1-141110163K5.jpg" 146 | , "http://cdnq.duitang.com/uploads/item/201404/14/20140414001638_hratS.jpeg"}; 147 | 148 | 149 | @Override 150 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 151 | View contentView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_video, parent, false); 152 | ViewHolder viewHolder = new ViewHolder(contentView); 153 | viewHolder.controller = new MediaController(parent.getContext()); 154 | viewHolder.controller.setEnableSlideBrightness(false); 155 | viewHolder.controller.setEnableSliderVolume(false); 156 | viewHolder.controller.setEnableSlidePosition(false); 157 | // viewHolder.controller.setFullScreenViewEnableSlideBrightness(false); 158 | // viewHolder.controller.setFullScreenViewEnableSlidePosition(false); 159 | // viewHolder.controller.setFullScreenViewEnableSliderVolume(false); 160 | viewHolder.controller.setFullScreenMode(MediaController.FULLSCREEN_VIEW); 161 | viewHolder.controller.setMute(true); 162 | viewHolder.controller.setShowBottomLayout(false); 163 | viewHolder.video.setMediaController(viewHolder.controller); 164 | mVideoWidth = parent.getContext().getResources().getDisplayMetrics().widthPixels; 165 | mVideoHeight = viewHolder.video.getLayoutParams().height; 166 | return viewHolder; 167 | } 168 | 169 | @Override 170 | public void onBindViewHolder(final ViewHolder holder, int position) { 171 | holder.video.setVideoPath(VIDEO_URL); 172 | holder.video.setPlayPosition(position); 173 | holder.controller.setPlayPosition(position); 174 | holder.controller.setOnClickListener(new View.OnClickListener() { 175 | @Override 176 | public void onClick(View v) { 177 | holder.controller.toggleFullScreenView(); 178 | } 179 | }); 180 | if (holder.controller.getImgThumb() != null) { 181 | Glide 182 | .with(holder.itemView.getContext()) 183 | .load(IMGS[position]) 184 | .apply(RequestOptions.centerCropTransform()) 185 | .into(holder.controller.getImgThumb()); 186 | } else { 187 | Log.d(getClass().getSimpleName(), "Thumb ImgView is null"); 188 | } 189 | 190 | } 191 | 192 | @Override 193 | public int getItemCount() { 194 | return 10; 195 | } 196 | } 197 | 198 | private static class ViewHolder extends RecyclerView.ViewHolder { 199 | 200 | IjkVideoView video; 201 | MediaController controller; 202 | 203 | ViewHolder(View itemView) { 204 | super(itemView); 205 | 206 | video = (IjkVideoView) itemView.findViewById(R.id.video_view); 207 | } 208 | } 209 | 210 | 211 | } 212 | -------------------------------------------------------------------------------- /app/src/main/java/com/leo/ijkplayer/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.leo.ijkplayer; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | 6 | import com.leo.player.media.IjkVideoManager; 7 | import com.leo.player.media.videoview.IjkVideoView; 8 | import com.leo.player.media.controller.MediaController; 9 | 10 | public class MainActivity extends AppCompatActivity { 11 | 12 | private IjkVideoView mIjkVideoView; 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | setContentView(R.layout.activity_main); 18 | 19 | mIjkVideoView = (IjkVideoView) findViewById(R.id.video_view); 20 | MediaController mediaController = new MediaController(this); 21 | mediaController.setShowThumb(true); 22 | mIjkVideoView.setMediaController(mediaController); 23 | 24 | mIjkVideoView.setVideoPath("http://baobab.wdjcdn.com/14564977406580.mp4"); 25 | } 26 | 27 | 28 | @Override 29 | protected void onDestroy() { 30 | super.onDestroy(); 31 | IjkVideoManager.getInstance().release(); 32 | } 33 | 34 | @Override 35 | protected void onPause() { 36 | super.onPause(); 37 | IjkVideoManager.getInstance().pause(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/xxx2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LinXiaoTao/Oatmeal/a8d998c2b0ad5771f6e839edb71cca3741ae90c5/app/src/main/res/drawable-xhdpi/xxx2.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 |