android - 在 GridView 中显示在线视频时长
问题描述
我正在使用 FTP 客户端从服务器获取视频并在 gridview 上显示它们。我也想显示每个 gridview 项目(视频)的持续时间。
我尝试在 gridview 适配器之外使用此代码:
for (FTPFile file : files) {
if (file.isFile())
{
//GetDuration
try{
//NOTE: must not use https
mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(myDomain+skyVideos+"/"+username+"/"+file.getName());
long duration =Long.parseLong(mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_DURATION));
duration=duration/1000;
long minute=duration/(60);
long second=duration-(minute*60);
mmr.release();
strDuration = String.format("%02d:%02d" , minute, second);
//ALL VIEWS
for (int j = 0; j < gv.getChildCount(); j++) {
View child = gv.getChildAt(j);
holder.tvDuration = child.findViewById(R.id.tvDuration);
runOnUiThread(new Runnable() {
@Override
public void run() {
holder.tvDuration.setText(strDuration);
}
});
}
arrListStr_Duration.add(strDuration);
stringArr_Duration = new String[arrListStr_Duration.size()];
stringArr_Duration = arrListStr_Duration.toArray(stringArr_Duration);
} catch (IllegalStateException e) {
//
}catch (IllegalArgumentException e)
{
//
}
}
//SORT BY TIMESTAMP
Arrays.sort(files, Comparator.comparing((FTPFile remoteFile) -> remoteFile.getTimestamp()).reversed());
}
client.disconnect();
这工作正常,即使它holder.tvDuration.setText(strDuration);
一个接一个地设置视频的持续时间()而不是同时设置(因为 for 循环如何工作?)即使我在后台运行此方法:不过有这个)
new Thread(new Runnable() {
@Override
public void run() {
//code in background here
getFTP_Duration();
getFTP_SizeArray();
}
}).start();
无论如何,这一切都很好,直到用户在 arrListStr_Duration 完全填充之前开始滚动,然后持续时间将设置在错误的视频上,因为视图被回收。
现在在 GridView 适配器中,我尝试了以下View getView
方法:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
holder = new Holder();
if (convertView == null)
{
convertView = inflater.inflate(R.layout.activity_video_gridview_single_checkbox, null);
}
holder.ivImage = convertView.findViewById(R.id.ivImage);
holder.tvInvisibleDate = convertView.findViewById(R.id.tvInvisibleDate);
holder.ivCheckbox = convertView.findViewById(R.id.ivCheckbox);
holder.tvDuration = convertView.findViewById(R.id.tvDuration);
holder.ibDots = convertView.findViewById(R.id.ibDots);
holder.mypopupWindow = null;
if (arrListStr_File.size() == arrListStr_Duration.size())
{
//Duration finished populating
holder.tvDuration.setText(stringArr_Duration[position]);
}
else
{
//user scrolling while duration is still being populated
try {
for (int i = 0; i < gv.getChildCount(); i++) {
if (arrListStr_Duration.size() != 0)
{
View child = gv.getChildAt(i);
holder.tvDuration = child.findViewById(R.id.tvDuration);
try {
holder.tvDuration.setText(stringArr_Duration[i]);
}catch (IndexOutOfBoundsException e)
{
//
}
}
}
}catch (NullPointerException e)
{
//
}
}
...
这也会混淆持续时间和视频,因为gv.getChildCount()
只返回可以在屏幕上看到的内容的计数,并且当用户滚动时,由于回收,这个计数会被重置。当用户在持续时间完全填充后滚动时,没有问题,但由于这种情况发生在后台,用户应该能够随时滚动并且仍然在正确的视频上设置正确的持续时间,我该怎么做实现这个?我想过根本不使用回收,但我知道这对性能不利。希望我说得通。
解决方案
适配器的 getView() 文档
* @param position The position of the item within the adapter's data set of the item whose view we want.
* @return A View corresponding to the data at the specified position.
View getView(int position, View convertView, ViewGroup parent);
当用户在持续时间完全填充后滚动时,就没有问题了。>
这是因为您position
在这种情况下正确使用,而在其他情况下您正在使用子索引,这GridView
就是混合视频的原因。
getView()
您可以通过创建一种获取视频持续时间的方法来简化您的整个过程。
private String getVideoDuration(int index){
if(index <= stringArr_Duration.length)
return stringArr_Duration[index];
return null; // can return empty string also here.
}
然后调用它getView()
并传递@param : position
给它,而不是子索引。
推荐阅读
- bash - Bash 提示 (PS1) 未按预期工作
- asp.net - asp.net webapp bundleconfig 从 bootstrap 4.6 切换到 5.0 导致参考错误
- elasticsearch - elasticsearch java stats_buckets
- json - List 类的自定义 KotlinX 序列化器
- javascript - 画布html上的范围滑块
- android - 如何在 WebView 上请求麦克风、摄像头权限?
- java - 如何等待动态加载元素列表
- expo - 如果应用程序未在后台运行,则 Expo-notifications 通知事件不起作用
- sql - 用于连接等价行的 SQL 查询对列求和
- r - 通过在 dplyr 中求和来创建“其他”类别