diff --git a/app/src/main/java/com/gh/download/cache/CacheManager.java b/app/src/main/java/com/gh/download/cache/CacheManager.java index f22811d676..5787296b2d 100644 --- a/app/src/main/java/com/gh/download/cache/CacheManager.java +++ b/app/src/main/java/com/gh/download/cache/CacheManager.java @@ -22,19 +22,21 @@ import io.reactivex.ObservableOnSubscribe; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; import okhttp3.Call; +import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; public class CacheManager { private static final AtomicReference INSTANCE = new AtomicReference<>(); - private HashMap downCalls; + private volatile HashMap downCalls; private OkHttpClient mClient; private File cacheDirectory = StorageUtils.getIndividualCacheDirectory(HaloApp.getInstance().getApplication()); private FileNameGenerator generator = new Md5FileNameGenerator(); private final String TEMP_POSTFIX = ".download"; private final int preLength = 5 * 1024 * 1024;//预加载大小 + public static CacheManager getInstance() { for (; ; ) { CacheManager current = INSTANCE.get(); @@ -122,48 +124,58 @@ public class CacheManager { @Override public void subscribe(ObservableEmitter e) throws Exception { String url = cacheInfo.getUrl(); - long downloadLength = cacheInfo.getProgress();//已经下载好的长度 + final long[] downloadLength = {cacheInfo.getProgress()};//已经下载好的长度 long contentLength = cacheInfo.getTotal();//文件的总长度 - if (downloadLength >= preLength) { + if (downloadLength[0] >= preLength) { e.onComplete(); return; } e.onNext(cacheInfo); Request request = new Request.Builder() - .addHeader("RANGE", "bytes=" + downloadLength + "-" + (contentLength > preLength ? preLength : contentLength)) + .addHeader("RANGE", "bytes=" + downloadLength[0] + "-" + (contentLength > preLength ? preLength : contentLength)) .url(url) .build(); Call call = mClient.newCall(request); downCalls.put(url, call); - Response response = call.execute(); - File file = new File(cacheDirectory, cacheInfo.getFileName()); - InputStream is = null; - FileOutputStream fileOutputStream = null; - try { - is = response.body().byteStream(); - fileOutputStream = new FileOutputStream(file, true); - byte[] buffer = new byte[2048]; - int len; - while (!call.isCanceled() && (len = is.read(buffer)) != -1) { - fileOutputStream.write(buffer, 0, len); - downloadLength += len; - cacheInfo.setProgress(downloadLength); - e.onNext(cacheInfo); + call.enqueue(new Callback() { + @Override + public void onFailure(Call call, IOException e) { + } - fileOutputStream.flush(); - downCalls.remove(url); - } finally { - if (is != null) { - is.close(); + + @Override + public void onResponse(Call call, Response response) throws IOException { + File file = new File(cacheDirectory, cacheInfo.getFileName()); + InputStream is = null; + FileOutputStream fileOutputStream = null; + try { + is = response.body().byteStream(); + fileOutputStream = new FileOutputStream(file, true); + byte[] buffer = new byte[2048]; + int len; + while (!call.isCanceled() && (len = is.read(buffer)) != -1) { + fileOutputStream.write(buffer, 0, len); + downloadLength[0] += len; + cacheInfo.setProgress(downloadLength[0]); + e.onNext(cacheInfo); + } + fileOutputStream.flush(); + downCalls.remove(url); + } finally { + if (is != null) { + is.close(); + } + if (fileOutputStream != null) { + fileOutputStream.close(); + } + } + if (file.length() == contentLength) { + file.renameTo(new File(file.getPath().substring(0, file.getPath().lastIndexOf(TEMP_POSTFIX)))); + } + e.onComplete(); } - if (fileOutputStream != null) { - fileOutputStream.close(); - } - } - if (file.length() == contentLength) { - file.renameTo(new File(file.getPath().substring(0, file.getPath().lastIndexOf(TEMP_POSTFIX)))); - } - e.onComplete(); + }); + } } diff --git a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt index cc64ced4d4..71a3e9b6ab 100644 --- a/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt +++ b/app/src/main/java/com/gh/gamecenter/video/detail/VideoDetailContainerFragment.kt @@ -14,11 +14,11 @@ import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.OrientationHelper import androidx.recyclerview.widget.RecyclerView -import com.danikula.videocache.HttpProxyCacheServer import com.gh.base.fragment.BaseLazyFragment import com.gh.common.constant.Config import com.gh.common.constant.Constants import com.gh.common.exposure.ExposureListener +import com.gh.common.runOnIoThread import com.gh.common.util.* import com.gh.common.view.vertical_recycler.OnPagerListener import com.gh.common.view.vertical_recycler.PagerLayoutManager @@ -36,13 +36,13 @@ import com.lightgame.download.DataWatcher import com.lightgame.download.DownloadEntity import com.lightgame.listeners.OnBackPressedListener import com.scwang.smartrefresh.layout.footer.ClassicsFooter +import com.shuyu.gsyvideoplayer.video.base.GSYVideoView.CURRENT_STATE_PAUSE import io.reactivex.disposables.Disposable import kotlinx.android.synthetic.main.fragment_video_detail_container.* import kotlinx.android.synthetic.main.reuse_no_connection.* import kotlinx.android.synthetic.main.reuse_none_data.* import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode -import java.net.ServerSocket class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { @@ -60,6 +60,7 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { private var mIsHomeVideo = false//是否是视频总入口 private var mExposureListener: ExposureListener? = null + private var mScheduledPlayDisposable: Disposable? = null companion object { var pauseVideo = HashMap()//跳转页面时是否需要暂停视频 @@ -211,6 +212,10 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { video?.let { CacheManager.getInstance().cancel(video.url) + val proxy = CustomProxyCacheManager.getProxy(requireContext(), null) + val client = proxy.getClients(video.url) + runOnIoThread { client.closeSource() } + val titleAndId = StringUtils.combineTwoString(video.title, video.id) video.videoIsMuted = false if (isNext) { @@ -231,6 +236,11 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { override fun onPageSelected(position: Int, isBottom: Boolean) { smartRefreshLayout.isEnableLoadMore = isBottom smartRefreshLayout.setNoMoreData(isBottom) + + if (mScheduledPlayDisposable != null && !mScheduledPlayDisposable!!.isDisposed) { + mScheduledPlayDisposable!!.dispose() + } + val isShowClick = SPUtils.getBoolean(Constants.SP_SHOW_CLICK_GUIDE) if (!isShowClick) { showClickGuide() @@ -249,18 +259,25 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { } else if (pos + 1 <= mAdapter.videoList.size - 1) { CacheManager.getInstance().download(mAdapter.videoList[pos + 1].url, object : CacheObserver() {}) } - if (mLastPosition != pos && videoView?.isInPlayingState != true) { - CacheManager.getInstance().cancel(mAdapter.videoList[pos].url) - CustomManager.releaseAllVideos("detail_${mViewModel.uuid}") - mBaseHandler.postDelayed({ - videoView?.startPlayLogic() - }, 500) - mBaseHandler.postDelayed({ - videoView?.updateMuteStatus() - }, 700) + CustomManager.releaseAllVideos("detail_${mViewModel.uuid}") + if (userVisibleHint) { + //延时处理,快速滑动不播放视频 + mScheduledPlayDisposable = rxTimer(1) { + if (it >= 500) { + mScheduledPlayDisposable?.dispose() + if (/*mLastPosition != pos &&*/ videoView?.isInPlayingState != true) { + CacheManager.getInstance().cancel(mAdapter.videoList[pos].url) + + videoView?.startPlayLogic() + mBaseHandler.postDelayed({ + videoView?.updateMuteStatus() + }, 500) + } + mLastPosition = pos + mViewModel.addHistoryRecord(mAdapter.videoList[pos]) + } + } } - mLastPosition = pos - mViewModel.addHistoryRecord(mAdapter.videoList[pos]) mViewModel.videoList.value?.apply { if (pos > mViewModel.startPosition) {//向上滑动 @@ -408,7 +425,15 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { findFirstCompletelyVisibleVideoViewByPosition()?.uploadVideoStreamingPlaying("恢复页面") DownloadManager.getInstance(requireContext()).addObserver(dataWatcher) if (pauseVideo[mViewModel.uuid] == true) { - CustomManager.onResume("detail_${mViewModel.uuid}", false) + val videoView = findFirstCompletelyVisibleVideoViewByPosition() + videoView?.run { + if (currentState == CURRENT_STATE_PAUSE) { + CustomManager.onResume("detail_${mViewModel.uuid}", false) + videoView.onVideoResume(false) + } else {//快速切换视频后再切换页面可能没有播放 + videoView.startPlayLogic() + } + } } else { pauseVideo[mViewModel.uuid] = true } @@ -421,40 +446,42 @@ class VideoDetailContainerFragment : BaseLazyFragment(), OnBackPressedListener { super.onFragmentResume() } - override fun onFragmentPause() { - - super.onFragmentPause() - } - override fun onPause() { + if (mScheduledPlayDisposable != null && !mScheduledPlayDisposable!!.isDisposed) { + mScheduledPlayDisposable!!.dispose() + mScheduledPlayDisposable = null + } + DownloadManager.getInstance(requireContext()).removeObserver(dataWatcher) findFirstCompletelyVisibleVideoViewByPosition()?.uploadVideoStreamingPlaying("暂停页面") if (pauseVideo[mViewModel.uuid] == true) { CustomManager.onPause("detail_${mViewModel.uuid}") + findFirstCompletelyVisibleVideoViewByPosition()?.onVideoPause() } mBaseHandler.postDelayed({ if (pauseVideo[mViewModel.uuid] == true) { CustomManager.onPause("detail_${mViewModel.uuid}") + findFirstCompletelyVisibleVideoViewByPosition()?.onVideoPause() } - },500) + }, 500) if (slideGuideAnimation.isAnimating) { slideGuideAnimation.cancelAnimation() guideRl.visibility = View.GONE } SPUtils.setBoolean(Constants.SP_SHOW_SLIDE_GUIDE, true) - mBaseHandler.postDelayed({CacheManager.getInstance().removeAllCall()},500) + mBaseHandler.postDelayed({ CacheManager.getInstance().removeAllCall() }, 500) val proxy = CustomProxyCacheManager.getProxy(requireContext(), null) proxy.allClients.forEach { it.value.closeSource() } - proxy.shutdown() - tryWithDefaultCatch { - val field = HttpProxyCacheServer::class.java.getDeclaredField("serverSocket") - field.isAccessible = true - val serverSocket = field.get(proxy) as ServerSocket - serverSocket.close() - } + /* proxy.shutdown() + tryWithDefaultCatch { + val field = HttpProxyCacheServer::class.java.getDeclaredField("serverSocket") + field.isAccessible = true + val serverSocket = field.get(proxy) as ServerSocket + serverSocket.close() + }*/ super.onPause() } diff --git a/app/src/main/res/drawable/bg_video_detail_bottom.xml b/app/src/main/res/drawable/bg_video_detail_bottom.xml index da7a281c9f..60e348c1a8 100644 --- a/app/src/main/res/drawable/bg_video_detail_bottom.xml +++ b/app/src/main/res/drawable/bg_video_detail_bottom.xml @@ -4,5 +4,5 @@ + android:startColor="#000000" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_video_detail_base.xml b/app/src/main/res/layout/layout_video_detail_base.xml index 8a1dd402e5..6cbc644f2a 100644 --- a/app/src/main/res/layout/layout_video_detail_base.xml +++ b/app/src/main/res/layout/layout_video_detail_base.xml @@ -91,7 +91,7 @@ android:layout_width="40dp" android:layout_height="40dp" android:layout_centerInParent="true" - android:indeterminateDrawable="@drawable/progressbar_video_detail_circle" /> + style = "@style/android:Widget.Holo.ProgressBar"/>