Android 在recyclerview中第一帧高效加载图像和视频

Android 在recyclerview中第一帧高效加载图像和视频,android,android-recyclerview,video-streaming,rx-java,Android,Android Recyclerview,Video Streaming,Rx Java,使用媒体浏览器类型的应用程序,在该应用程序中,我使用自定义驱动程序从USB读取文件。通过NanoHTTPServer公开文件。这里不重要,只是为了提供信息 下面的代码逻辑工作得很好,但看起来很糟糕,并开始与快速滚动作斗争。 是否有任何方法可以更快地加载视频帧,并避免挂起和延迟帧。这个代码有什么缺陷吗?因为我使用的是rxjava @Override public void onBindViewHolder(BasicHolder holder,final int posit

使用媒体浏览器类型的应用程序,在该应用程序中,我使用自定义驱动程序从USB读取文件。通过
NanoHTTPServer
公开文件。这里不重要,只是为了提供信息

下面的代码逻辑工作得很好,但看起来很糟糕,并开始与快速滚动作斗争。 是否有任何方法可以更快地加载视频帧,并避免挂起和延迟帧。这个代码有什么缺陷吗?因为我使用的是rxjava

    @Override
        public void onBindViewHolder(BasicHolder holder,final int position) {
    ...
    if(multiMedia.isImage()){
    Glide.with(context)
                        .load(multiMedia.getUrl())
                        .crossFade()
                        .into(holder.imageThumbnail);
    }else{
    Bitmap bitmap = mThumbnailsCache.get(multiMedia.getUrl()+THUMBNAIL_AT_PERCENT);
                if(bitmap == null || multiMedia.getLength() == 0){
                    //check for already running task
                    if(holder.imageThumbnail.getTag(R.string.tag_for_video) == null){
                        loadVideoThumbnail(holder,multiMedia,position);
                    }
                }else {
                    holder.imageThumbnail.setImageBitmap(bitmap);
                }
    }
    ....
//this method will trigger rxjava task on io and set back results emitted by
    private void loadVideoThumbnail(final BasicHolder holder, final MultiMedia multiMedia,final int position){
            final SoftReference<BasicHolder> mHolderRef = new SoftReference<>(holder);
            final Subscription sub = extractFrameAndDuration(multiMedia.getUrl(), THUMBNAIL_AT_PERCENT)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(emittedObject -> {
                        if (emittedObject == null || mHolderRef.get() == null) return;

                        if (mHolderRef.get().getLayoutPosition() != position) {
                            notifyItemChanged(position);
                            return;
                        }

                        if (emittedObject instanceof Bitmap) {
                            ImageView imageThumbnail = mHolderRef.get().imageThumbnail;
                            if (imageThumbnail.getTag(R.string.tag_for_video) != null) {
                                imageThumbnail.setTag(R.string.tag_for_video, null);
                                imageThumbnail.setImageBitmap((Bitmap) emittedObject);
                            }
                        } else {
                            multiMedia.setLength((long)emittedObject);
                            TextView textInfo = mHolderRef.get().textInfo;
                            if (textInfo.getTag() == Filetype.MOVIE) {
                                mHolderRef.get().viewHighlight.setData(multiMedia.getSavedClips(),multiMedia.getLength());
                                textInfo.setText(VideoUtils.getTotalClipDuration((long) emittedObject, App.context));
                            }
                        }
                    }, Throwable::printStackTrace);

            if(reqSubQueue.size() > 8){
                //cancel previous requests
                reqSubQueue.pop().unsubscribe();
            }
            reqSubQueue.add(sub);
            holder.imageThumbnail.setTag(R.string.tag_for_video,sub);
        }

    ...
    //this method will get thumbnail from video url
    private Observable<Object> extractFrameAndDuration(String url, final long atPercent){
            return Observable.create(subscriber -> {
                final MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
                subscriber.add(new Subscription() {
                    @Override
                    public void unsubscribe() {
                       //this will actually cancel loading
                        Observable.fromCallable(() -> {
                            mediaMetadataRetriever.release();
                            return true;
                        }).subscribeOn(Schedulers.io())
                                .subscribe();
                    }

                    @Override
                    public boolean isUnsubscribed() {
                        return false;
                    }
                });

                try{
                    mediaMetadataRetriever.setDataSource(url, new HashMap<>());

                    String durationString = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
                    final long duration = Long.parseLong(TextUtils.isEmpty(durationString)? "0": durationString);

                    //cache duration
                    clipsDurations.put(url,duration);

                    subscriber.onNext(duration);

                    long timeUs = (long) (duration / 100.0 * atPercent);

                    if(timeUs > duration) timeUs = duration;

                    Bitmap bitmap = mThumbnailsCache.get(url+THUMBNAIL_AT_PERCENT);
                    if(bitmap == null){
                        //1 milli sec = 1000 microseconds
                        bitmap = MediaUtils.getFrameFromVideoAt(mediaMetadataRetriever, timeUs * 1000);
                        if(bitmap != null){
                            bitmap = MediaUtils.resize(bitmap,thumbSize,thumbSize);
                            mThumbnailsCache.put(url+THUMBNAIL_AT_PERCENT,bitmap);
                            subscriber.onNext(bitmap);
                        }
                    }else {
                        subscriber.onNext(bitmap);
                    }

                }
                catch (Exception e){
                    e.printStackTrace();
                }
                finally{
                    if (mediaMetadataRetriever != null){
                        mediaMetadataRetriever.release();
                    }
                }
                //remove item from queue
                subscriber.onCompleted();
                reqSubQueue.remove(subscriber);
            });
        }
@覆盖
BindViewHolder上的公共无效(基本文件夹持有人,最终整数位置){
...
if(multiMedia.isImage()){
带(上下文)滑动
.load(multiMedia.getUrl())
.crossFade()
.插入(支架.图像缩略图);
}否则{
位图Bitmap=mThumbnailsCache.get(multiMedia.getUrl()+缩略图百分比);
如果(位图==null | | multiMedia.getLength()==0){
//检查是否已在运行任务
if(holder.image缩略图.getTag(R.string.tag\u表示视频)==null){
加载视频缩略图(支架、多媒体、位置);
}
}否则{
holder.image缩略图.setImageBitmap(位图);
}
}
....
//此方法将在io上触发rxjava任务,并设置
私有void loadvideo缩略图(最终基本文件夹持有者、最终多媒体、最终整数位置){
最终软参考mHolderRef=新软参考(支架);
最终订阅sub=extractFrameAndDuration(multiMedia.getUrl(),缩略图位于百分比处)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.订阅(emittedObject->{
if(emittedObject==null | | mHolderRef.get()==null)返回;
if(mHolderRef.get().getLayoutPosition()!=position){
(职位)变更;
返回;
}
if(位图的emittedObject实例){
ImageView imageThumbnail=mHolderRef.get().imageThumbnail;
if(imageThumbnail.getTag(R.string.tag用于视频)!=null){
setTag(R.string.tag_表示_视频,null);
setImageBitmap((位图)emittedObject);
}
}否则{
multiMedia.setLength((长)emittedObject);
TextView textInfo=mHolderRef.get().textInfo;
if(textInfo.getTag()==Filetype.MOVIE){
mHolderRef.get().viewHighlight.setData(multiMedia.getSavedClips(),multiMedia.getLength());
textInfo.setText(VideoUtils.getTotalClipDuration((长)emittedObject,App.context));
}
}
},Throwable::printStackTrace);
if(reqSubQueue.size()>8){
//取消以前的请求
reqSubQueue.pop().unsubscribe();
}
请求子队列。添加(子);
holder.image缩略图.setTag(R.string.tag用于视频,sub);
}
...
//此方法将从视频url获取缩略图
私有可观察extractFrameAndDuration(字符串url,最终长度百分比){
返回可观察。创建(订户->{
final MediaMetadataRetriever MediaMetadataRetriever=新的MediaMetadataRetriever();
subscriber.add(新订阅(){
@凌驾
公开作废取消订阅(){
//这实际上将取消加载
可观察。从可调用(()->{
mediaMetadataRetriever.release();
返回true;
}).subscribeOn(Schedulers.io())
.subscribe();
}
@凌驾
公共布尔值isUnsubscribed(){
返回false;
}
});
试一试{
setDataSource(url,newHashMap());
String durationString=mediaMetadataRetriever.extractMetadata(mediaMetadataRetriever.METADATA\u KEY\u DURATION);
最终长持续时间=long.parseLong(TextUtils.isEmpty(durationString)?“0”:durationString);
//缓存持续时间
clipsDurations.put(url,duration);
订户.onNext(持续时间);
长时间US=(长)(持续时间/100.0*百分比);
如果(timeUs>持续时间)timeUs=持续时间;
位图Bitmap=mThumbnailsCache.get(url+缩略图的百分比);
如果(位图==null){
//1毫秒=1000微秒
位图=MediaUtils.getFrameFromVideoAt(mediaMetadataRetriever,timeUs*1000);
if(位图!=null){
位图=MediaUtils.resize(位图、拇指大小、拇指大小);
mThumbnailsCache.put(url+缩略图百分比,位图);
subscriber.onNext(位图);
}
}否则{
subscriber.onNext(位图);
}
}
捕获(例外e){
e、 printStackTrace();
}
最后{
if(mediaMetadataRetriever!=null){
mediaMetadataRetriever.release();
}
}
//删除项目