依赖的导入:compile 'io.reactivex.rxjava2:rxjava:2.1.1' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' //retrofit compile 'com.squareup.retrofit2:retrofit:2.2.0' //Gson converter compile 'com.squareup.retrofit2:converter-gson:2.2.0' //RxJava2 Adapter compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' //okhttp compile 'com.squareup.okhttp3:okhttp:3.6.0' implementation 'com.android.support:recyclerview-v7:26.1.0' compile 'com.youth.banner:banner:1.4.9' compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.facebook.fresco:fresco:0.11.0' compile(name: 'ijkplayer-java-release', ext: 'aar') compile 'org.greenrobot:greendao:3.2.0'
第一步:注解@Streaming/*大文件需要加入这个判断,防止下载过程中写入到内存中*/@GET
//我们在下载文件的时候,需要传回range值来继续下载
Observable<ResponseBody> download(@Header("RANGE") String start, @Url String url);第二步:封装Retrofitpublic class BaseService { //okhttp的简单实例,如果我们加拦截器的话,就配上用场了 private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); //实例retrofit private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl("http://result.eolinker.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()); //创建一个方法,提供外部创建retrofit public static <S> S createService(Class<S> serviceClass) { Retrofit retrofit = builder.client(httpClient.build()).build(); return retrofit.create(serviceClass); } }第5步:视频播放:第三步:model层处理下载问题 //这个方法使我们实现model接口中的那个方法String url3=""; @Override public void getData(String start, String url, final String url2, final GetCallback callback) { this.url3 = url; //调用我们自己创建的retrofit中的方法 BaseService.createService(GetInterface.class).download(start, url3) .subscribeOn(Schedulers.io()) //可以不写在主线程, .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<ResponseBody>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(ResponseBody responseBody) { //获取文件的总长度 final long l = responseBody.contentLength(); Log.i("=====length=====", "onNext: " + l); //调用文件的长度 downloadfile(l, url2); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } }); } //传来的参数是我们文件的总长度和我们文件下载的路径 public void downloadfile(long length, String url2) { final File file = new File(url2); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } }第4步:int threadNum = 5; long blockSize = length / threadNum; long startPosition = 0; long end = 0; // //四舍五入--- 让一个数字+0。5在四舍五入 就变成 向上取整 //计算出下载块以后 创建线程执行下载操作 for (int i = 0; i < threadNum; i++) { //在下载之前,我们先判断一下数据库有没有值,因为断点续传我们暂停后会有数据保存到数据库 List<Bean2> cityInfoList = DBHelper.getInstance(context).getCityInfoList(i); //如果有的话,我们将数据库中的数据查询出来,然后对我们下载的开始值和结束值进行赋值 if (cityInfoList.size() > 0) { Long range = cityInfoList.get(0).getRange(); Long end1 = cityInfoList.get(0).getEnd(); startPosition = range; end = end1; Log.i("=====", "downloadFile: " + startPosition + "==" + end); } else { //如果没有值的话我们要计算它的长度,然后给开始结束的位置进行赋值 startPosition = blockSize * i; //让最后一个线程下载的大小是正好的, 总长度 - 除了最后一个块的大小和 if (i == threadNum - 1) { blockSize = length - blockSize * (threadNum - 1); } //然后将我们计算好的中存放到数据库 end = startPosition + blockSize - 1; Bean2 bean2 = new Bean2(); bean2.setThreadNum(i + ""); bean2.setRange(startPosition); bean2.setEnd(end); //数据库方法,插入的 DBHelper.getInstance(context).addToCityInfoTable(bean2); } //开启下载的任务 downloadTask(startPosition, file, end, length, i); }} }downloadTask方法:public void downloadTask(final long startPosition, final File file, long end, final long length, final int i) { //计算开始位置 String range = "bytes=" + startPosition + "-" + end; BaseService.createService(GetInterface.class).download(range, url3) .subscribeOn(Schedulers.io()) .observeOn(Schedulers.io()) .subscribe(new Observer<ResponseBody>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(ResponseBody responseBody) { ///文件的 输入流 BufferedInputStream bis = null; //写入文件的地址 RandomAccessFile raf = null; try { bis = new BufferedInputStream(responseBody.byteStream()); raf = new RandomAccessFile(file, "rwd"); raf.seek(startPosition); byte[] buff = new byte[1024 * 8]; int len = 0; long length2 = 0; List<Bean2> cityInfoList = DBHelper.getInstance(context).getCityInfoList(i); if (cityInfoList.size() > 0) { length2 = cityInfoList.get(0).getRange(); Log.i("=====继续length2=======", "onNext: " + length2); } while ((len = bis.read(buff)) != -1) { Log.i("===循环继续====", "onNext: "); //正在下载的判断 if (stateDownload == DOWNLOAD_ING) { Log.i("===继续下载====", "onNext: "); length2 += len; raf.write(buff, 0, len); handler.sendEmptyMessage((int) length2); //当我们点击暂停的时候,我们要改变状态。当我们点击继续的时候,我们一定要记得把状态值改变回下载的状态,(本人就是犯了这么个地级错误) } else if (stateDownload == DOWNLOAD_PAUSE) { //更新数据库 DBHelper.getInstance(context).updateInfo(i, length2); break; } } } catch (IOException e) { e.printStackTrace(); } finally { if (bis != null) { try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if (raf != null) { try { raf.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });第5步:接口改变状态值: //暂停@Override public void stop() { stateDownload = DOWNLOAD_PAUSE; } //继续 @Override public void jixu() { stateDownload = DOWNLOAD_ING; } @Override public void getProgress() { }//集成GreenDaopublic class DBHelper { private static Context mContext; private static DBHelper instance; Bean2Dao bean2Dao; Bean2 bean; //使用单例模式 private DBHelper() { } public static DBHelper getInstance(Context context) { if (instance == null) { instance = new DBHelper(); if (mContext == null) { mContext = context; } // 数据库对象 // 数据库对象 DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(mContext, "student.db", null); DaoMaster daoMaster = new DaoMaster(devOpenHelper.getWritableDb()); DaoSession daoSession = daoMaster.newSession(); instance.bean2Dao = daoSession.getBean2Dao(); } return instance; } /** 添加数据 */ public void addToCityInfoTable(Bean2 item) { bean2Dao.insert(item); } /** 查询 */ /** 通过我们的线程数量号进行查询 */ public List<Bean2> getCityInfoList(int threadNum) { QueryBuilder<Bean2> qb = bean2Dao.queryBuilder(); qb.where(Bean2Dao.Properties.ThreadNum.eq(threadNum)); List<Bean2> list = qb.list(); Log.i("========", "getCityInfoList: " + list); return list; } //更新数据库的方法 public void updateInfo(int id,long rang){ QueryBuilder<Bean2> qb = bean2Dao.queryBuilder(); qb.where(Bean2Dao.Properties.ThreadNum.eq(id)); List<Bean2> list = qb.list(); Bean2 bean2 = list.get(0); bean2.setRange(rang); bean2Dao.update(bean2); } }//bean类@Entity public class Bean2 { @Id private Long id; @Property(nameInDb = "RANGE") private Long range; @Property(nameInDb = "END") private Long end; @Property(nameInDb = "ThREADNUM") private String ThreadNum;compile(name: 'ijkplayer-java-release', ext: 'aar')android { compileSdkVersion 26 defaultConfig { applicationId "com.bwie.mcowu.lx_zhouthree" minSdkVersion 19 targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } sourceSets { main { jniLibs.srcDirs = ['libs'] } } } repositories { mavenCentral() flatDir { dirs 'libs' //this way we can find the .aar file in libs folder } }第五步:/** * 日志工具类 在发布时不显示日志 * @author RANDY_ZHANG */ public class DebugLog { static String className; static String methodName; static int lineNumber; private DebugLog(){ /* Protect from instantiations */ } public static boolean isDebuggable() { return BuildConfig.DEBUG; } private static String createLog(String log ) { StringBuffer buffer = new StringBuffer(); buffer.append("["); buffer.append(methodName); buffer.append(":"); buffer.append(lineNumber); buffer.append("]"); buffer.append(log); return buffer.toString(); } private static void getMethodNames(StackTraceElement[] sElements){ className = sElements[1].getFileName(); methodName = sElements[1].getMethodName(); lineNumber = sElements[1].getLineNumber(); } public static void e(String message){ if (!isDebuggable()) return; // Throwable instance must be created before any methods getMethodNames(new Throwable().getStackTrace()); Log.e(className, createLog(message)); } public static void i(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.i(className, createLog(message)); } public static void d(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.d(className, createLog(message)); } public static void v(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.v(className, createLog(message)); } public static void w(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.w(className, createLog(message)); } public static void wtf(String message){ if (!isDebuggable()) return; getMethodNames(new Throwable().getStackTrace()); Log.wtf(className, createLog(message)); } } 第六步: playManagerpublic class PlayerManager { /** * 可能会剪裁,保持原视频的大小,显示在中心,当原视频的大小超过view的大小超过部分裁剪处理 */ public static final String SCALETYPE_FITPARENT="fitParent"; /** * 可能会剪裁,等比例放大视频,直到填满View为止,超过View的部分作裁剪处理 */ public static final String SCALETYPE_FILLPARENT="fillParent"; /** * 将视频的内容完整居中显示,如果视频大于view,则按比例缩视频直到完全显示在view中 */ public static final String SCALETYPE_WRAPCONTENT="wrapContent"; /** * 不剪裁,非等比例拉伸画面填满整个View */ public static final String SCALETYPE_FITXY="fitXY"; /** * 不剪裁,非等比例拉伸画面到16:9,并完全显示在View中 */ public static final String SCALETYPE_16_9="16:9"; /** * 不剪裁,非等比例拉伸画面到4:3,并完全显示在View中 */ public static final String SCALETYPE_4_3="4:3"; /** * 状态常量 */ private final int STATUS_ERROR=-1; private final int STATUS_IDLE=0; private final int STATUS_LOADING=1; private final int STATUS_PLAYING=2; private final int STATUS_PAUSE=3; private final int STATUS_COMPLETED=4; private final Activity activity; private final IjkVideoView videoView; private final AudioManager audioManager; public GestureDetector gestureDetector; private boolean playerSupport; private boolean isLive = false;//是否为直播 private boolean fullScreenOnly; private boolean portrait; private final int mMaxVolume; private int screenWidthPixels; private int currentPosition; private int status=STATUS_IDLE; private long pauseTime; private String url; private float brightness=-1; private int volume=-1; private long newPosition = -1; private long defaultRetryTime=5000; private OrientationEventListener orientationEventListener; private PlayerStateListener playerStateListener; public void setPlayerStateListener(PlayerStateListener playerStateListener) { this.playerStateListener = playerStateListener; } private OnErrorListener onErrorListener=new OnErrorListener() { @Override public void onError(int what, int extra) { } }; private OnCompleteListener onCompleteListener=new OnCompleteListener() { @Override public void onComplete() { } }; private OnInfoListener onInfoListener=new OnInfoListener(){ @Override public void onInfo(int what, int extra) { } }; private OnControlPanelVisibilityChangeListener onControlPanelVisibilityChangeListener=new OnControlPanelVisibilityChangeListener() { @Override public void change(boolean isShowing) { } }; /** * try to play when error(only for live video) * @param defaultRetryTime millisecond,0 will stop retry,default is 5000 millisecond */ public void setDefaultRetryTime(long defaultRetryTime) { this.defaultRetryTime = defaultRetryTime; } public PlayerManager(final Activity activity) { try { IjkMediaPlayer.loadLibrariesOnce(null); IjkMediaPlayer.native_profileBegin("libijkplayer.so"); playerSupport=true; } catch (Throwable e) { Log.e("GiraffePlayer", "loadLibraries error", e); } this.activity=activity; screenWidthPixels = activity.getResources().getDisplayMetrics().widthPixels; videoView = (IjkVideoView) activity.findViewById(R.id.video_view); videoView.setOnCompletionListener(new IMediaPlayer.OnCompletionListener() { @Override public void onCompletion(IMediaPlayer mp) { statusChange(STATUS_COMPLETED); onCompleteListener.onComplete(); } }); videoView.setOnErrorListener(new IMediaPlayer.OnErrorListener() { @Override public boolean onError(IMediaPlayer mp, int what, int extra) { statusChange(STATUS_ERROR); onErrorListener.onError(what,extra); return true; } }); videoView.setOnInfoListener(new IMediaPlayer.OnInfoListener() { @Override public boolean onInfo(IMediaPlayer mp, int what, int extra) { switch (what) { case IMediaPlayer.MEDIA_INFO_BUFFERING_START: statusChange(STATUS_LOADING); break; case IMediaPlayer.MEDIA_INFO_BUFFERING_END: statusChange(STATUS_PLAYING); break; case IMediaPlayer.MEDIA_INFO_NETWORK_BANDWIDTH: //显示下载速度 // Toast.show("download rate:" + extra); break; case IMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: statusChange(STATUS_PLAYING); break; default:break; } onInfoListener.onInfo(what,extra); return false; } }); audioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); mMaxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC); gestureDetector = new GestureDetector(activity, new PlayerGestureListener()); if (fullScreenOnly) { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } portrait=getScreenOrientation()== ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; if (!playerSupport) { DebugLog.e("","播放器不支持此设备"); } } private void statusChange(int newStatus) { status = newStatus; if (!isLive && newStatus==STATUS_COMPLETED) { DebugLog.d("","statusChange STATUS_COMPLETED..."); if (playerStateListener != null){ playerStateListener.onComplete(); } }else if (newStatus == STATUS_ERROR) { DebugLog.d("","statusChange STATUS_ERROR..."); if (playerStateListener != null){ playerStateListener.onError(); } } else if(newStatus==STATUS_LOADING){ // $.id(R.id.app_video_loading).visible(); if (playerStateListener != null){ playerStateListener.onLoading(); } DebugLog.d("","statusChange STATUS_LOADING..."); } else if (newStatus == STATUS_PLAYING) { DebugLog.d("","statusChange STATUS_PLAYING..."); if (playerStateListener != null){ playerStateListener.onPlay(); } } } public void onPause() { pauseTime= System.currentTimeMillis(); if (status==STATUS_PLAYING) { videoView.pause(); if (!isLive) { currentPosition = videoView.getCurrentPosition(); } } } public void onResume() { pauseTime=0; if (status==STATUS_PLAYING) { if (isLive) { videoView.seekTo(0); } else { if (currentPosition>0) { videoView.seekTo(currentPosition); } } videoView.start(); } } public void onDestroy() { orientationEventListener.disable(); videoView.stopPlayback(); } public void play(String url) { this.url = url; if (playerSupport) { videoView.setVideoPath(url); videoView.start(); } } private String generateTime(long time) { int totalSeconds = (int) (time / 1000); int seconds = totalSeconds % 60; int minutes = (totalSeconds / 60) % 60; int hours = totalSeconds / 3600; return hours > 0 ? String.format("%02d:%02d:%02d", hours, minutes, seconds) : String.format("%02d:%02d", minutes, seconds); } private int getScreenOrientation() { int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); DisplayMetrics dm = new DisplayMetrics(); activity.getWindowManager().getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; int height = dm.heightPixels; int orientation; // if the device's natural orientation is portrait: if ((rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) && height > width || (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) && width > height) { switch (rotation) { case Surface.ROTATION_0: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; case Surface.ROTATION_90: orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; case Surface.ROTATION_180: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; break; case Surface.ROTATION_270: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; break; default: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; } } // if the device's natural orientation is landscape or if the device // is square: else { switch (rotation) { case Surface.ROTATION_0: orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; case Surface.ROTATION_90: orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; break; case Surface.ROTATION_180: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; break; case Surface.ROTATION_270: orientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT; break; default: orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; break; } } return orientation; } /** * 滑动改变声音大小 * * @param percent */ private void onVolumeSlide(float percent) { if (volume == -1) { volume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC); if (volume < 0) volume = 0; } int index = (int) (percent * mMaxVolume) + volume; if (index > mMaxVolume) { index = mMaxVolume; } else if (index < 0){ index = 0; } // 变更声音 audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, index, 0); // 变更进度条 int i = (int) (index * 1.0 / mMaxVolume * 100); String s = i + "%"; if (i == 0) { s = "off"; } DebugLog.d("","onVolumeSlide:"+s); } private void onProgressSlide(float percent) { long position = videoView.getCurrentPosition(); long duration = videoView.getDuration(); long deltaMax = Math.min(100 * 1000, duration - position); long delta = (long) (deltaMax * percent); newPosition = delta + position; if (newPosition > duration) { newPosition = duration; } else if (newPosition <= 0) { newPosition=0; delta=-position; } int showDelta = (int) delta / 1000; if (showDelta != 0) { String text = showDelta > 0 ? ("+" + showDelta) : "" + showDelta; DebugLog.d("","onProgressSlide:" + text); } } /** * 滑动改变亮度 * * @param percent */ private void onBrightnessSlide(float percent) { if (brightness < 0) { brightness = activity.getWindow().getAttributes().screenBrightness; if (brightness <= 0.00f){ brightness = 0.50f; }else if (brightness < 0.01f){ brightness = 0.01f; } } DebugLog.d("","brightness:"+brightness+",percent:"+ percent); WindowManager.LayoutParams lpa = activity.getWindow().getAttributes(); lpa.screenBrightness = brightness + percent; if (lpa.screenBrightness > 1.0f){ lpa.screenBrightness = 1.0f; }else if (lpa.screenBrightness < 0.01f){ lpa.screenBrightness = 0.01f; } activity.getWindow().setAttributes(lpa); } public void setFullScreenOnly(boolean fullScreenOnly) { this.fullScreenOnly = fullScreenOnly; tryFullScreen(fullScreenOnly); if (fullScreenOnly) { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } else { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); } } private void tryFullScreen(boolean fullScreen) { if (activity instanceof AppCompatActivity) { ActionBar supportActionBar = ((AppCompatActivity) activity).getSupportActionBar(); if (supportActionBar != null) { if (fullScreen) { supportActionBar.hide(); } else { supportActionBar.show(); } } } setFullScreen(fullScreen); } private void setFullScreen(boolean fullScreen) { if (activity != null) { WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); if (fullScreen) { attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; activity.getWindow().setAttributes(attrs); activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } else { attrs.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); activity.getWindow().setAttributes(attrs); activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); } } } /** * <pre> * fitParent:可能会剪裁,保持原视频的大小,显示在中心,当原视频的大小超过view的大小超过部分裁剪处理 * fillParent:可能会剪裁,等比例放大视频,直到填满View为止,超过View的部分作裁剪处理 * wrapContent:将视频的内容完整居中显示,如果视频大于view,则按比例缩视频直到完全显示在view中 * fitXY:不剪裁,非等比例拉伸画面填满整个View * 16:9:不剪裁,非等比例拉伸画面到16:9,并完全显示在View中 * 4:3:不剪裁,非等比例拉伸画面到4:3,并完全显示在View中 * </pre> * @param scaleType */ public void setScaleType(String scaleType) { if (SCALETYPE_FITPARENT.equals(scaleType)) { videoView.setAspectRatio(IRenderView.AR_ASPECT_FIT_PARENT); }else if (SCALETYPE_FILLPARENT.equals(scaleType)) { videoView.setAspectRatio(IRenderView.AR_ASPECT_FILL_PARENT); }else if (SCALETYPE_WRAPCONTENT.equals(scaleType)) { videoView.setAspectRatio(IRenderView.AR_ASPECT_WRAP_CONTENT); }else if (SCALETYPE_FITXY.equals(scaleType)) { videoView.setAspectRatio(IRenderView.AR_MATCH_PARENT); }else if (SCALETYPE_16_9.equals(scaleType)) { videoView.setAspectRatio(IRenderView.AR_16_9_FIT_PARENT); }else if (SCALETYPE_4_3.equals(scaleType)) { videoView.setAspectRatio(IRenderView.AR_4_3_FIT_PARENT); } } public void start() { videoView.start(); } public void pause() { videoView.pause(); } public boolean onBackPressed() { if (!fullScreenOnly && getScreenOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); return true; } return false; } class Query { private final Activity activity; private View view; public Query(Activity activity) { this.activity=activity; } public Query id(int id) { view = activity.findViewById(id); return this; } public Query image(int resId) { if (view instanceof ImageView) { ((ImageView) view).setImageResource(resId); } return this; } public Query visible() { if (view != null) { view.setVisibility(View.VISIBLE); } return this; } public Query gone() { if (view != null) { view.setVisibility(View.GONE); } return this; } public Query invisible() { if (view != null) { view.setVisibility(View.INVISIBLE); } return this; } public Query clicked(View.OnClickListener handler) { if (view != null) { view.setOnClickListener(handler); } return this; } public Query text(CharSequence text) { if (view!=null && view instanceof TextView) { ((TextView) view).setText(text); } return this; } public Query visibility(int visible) { if (view != null) { view.setVisibility(visible); } return this; } private void size(boolean width, int n, boolean dip){ if(view != null){ ViewGroup.LayoutParams lp = view.getLayoutParams(); if(n > 0 && dip){ n = dip2pixel(activity, n); } if(width){ lp.width = n; }else{ lp.height = n; } view.setLayoutParams(lp); } } public void height(int height, boolean dip) { size(false,height,dip); } public int dip2pixel(Context context, float n){ int value = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, n, context.getResources().getDisplayMetrics()); return value; } public float pixel2dip(Context context, float n){ Resources resources = context.getResources(); DisplayMetrics metrics = resources.getDisplayMetrics(); float dp = n / (metrics.densityDpi / 160f); return dp; } } public class PlayerGestureListener extends GestureDetector.SimpleOnGestureListener { private boolean firstTouch; private boolean volumeControl; private boolean toSeek; /** * 双击 */ @Override public boolean onDoubleTap(MotionEvent e) { videoView.toggleAspectRatio(); return true; } @Override public boolean onDown(MotionEvent e) { firstTouch = true; return super.onDown(e); } /** * 滑动 */ @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { float mOldX = e1.getX(), mOldY = e1.getY(); float deltaY = mOldY - e2.getY(); float deltaX = mOldX - e2.getX(); if (firstTouch) { toSeek = Math.abs(distanceX) >= Math.abs(distanceY); volumeControl=mOldX > screenWidthPixels * 0.5f; firstTouch = false; } if (toSeek) { if (!isLive) { onProgressSlide(-deltaX / videoView.getWidth()); } } else { float percent = deltaY / videoView.getHeight(); if (volumeControl) { onVolumeSlide(percent); } else { onBrightnessSlide(percent); } } return super.onScroll(e1, e2, distanceX, distanceY); } @Override public boolean onSingleTapUp(MotionEvent e) { return true; } } /** * is player support this device * @return */ public boolean isPlayerSupport() { return playerSupport; } /** * 是否正在播放 * @return */ public boolean isPlaying() { return videoView!=null?videoView.isPlaying():false; } public void stop(){ videoView.stopPlayback(); } public int getCurrentPosition(){ return videoView.getCurrentPosition(); } /** * get video duration * @return */ public int getDuration(){ return videoView.getDuration(); } public PlayerManager playInFullScreen(boolean fullScreen){ if (fullScreen) { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } return this; } public PlayerManager onError(OnErrorListener onErrorListener) { this.onErrorListener = onErrorListener; return this; } public PlayerManager onComplete(OnCompleteListener onCompleteListener) { this.onCompleteListener = onCompleteListener; return this; } public PlayerManager onInfo(OnInfoListener onInfoListener) { this.onInfoListener = onInfoListener; return this; } public PlayerManager onControlPanelVisibilityChange(OnControlPanelVisibilityChangeListener listener){ this.onControlPanelVisibilityChangeListener = listener; return this; } /** * set is live (can't seek forward) * @param isLive * @return */ public PlayerManager live(boolean isLive) { this.isLive = isLive; return this; } public PlayerManager toggleAspectRatio(){ if (videoView != null) { videoView.toggleAspectRatio(); } return this; } public interface PlayerStateListener{ void onComplete(); void onError(); void onLoading(); void onPlay(); } public interface OnErrorListener{ void onError(int what, int extra); } public interface OnCompleteListener{ void onComplete(); } public interface OnControlPanelVisibilityChangeListener{ void change(boolean isShowing); } public interface OnInfoListener{ void onInfo(int what, int extra); } }第七步:初始化private void initPlayer() { player = new PlayerManager(this); player.setFullScreenOnly(true); player.setScaleType(PlayerManager.SCALETYPE_FILLPARENT); player.playInFullScreen(true); player.setPlayerStateListener(this); player.play(url); } @Override public boolean onTouchEvent(MotionEvent event) { if (player.gestureDetector.onTouchEvent(event)) return true; return super.onTouchEvent(event); } @Override public void onComplete() { Log.i("+++++", "onComplete: "); } @Override public void onError() { Log.i("+++++", "onError: "); } @Override public void onLoading() { Log.i("+++++", "onLoading: "); } @Override public void onPlay() { Log.i("+++++", "onPlay: "); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn: String url2 = getCacheDir() + "haha.mp4"; presenter.down(String.valueOf(0), url, url2); break; default: break; } } @Override public void getData(ResponseBody responseBody) { }
Retrofit+RxJava+Mvp实现多线程视频下载
最新推荐文章于 2021-05-26 07:10:07 发布