diff --git a/app/src/main/java/com/github/tvbox/osc/ui/adapter/GridAdapter.java b/app/src/main/java/com/github/tvbox/osc/ui/adapter/GridAdapter.java index 4207d695..317d8071 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/adapter/GridAdapter.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/adapter/GridAdapter.java @@ -1,10 +1,15 @@ package com.github.tvbox.osc.ui.adapter; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.text.TextUtils; +import android.util.Base64; import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.collection.LruCache; + import com.chad.library.adapter.base.BaseQuickAdapter; import com.chad.library.adapter.base.BaseViewHolder; import com.github.tvbox.osc.R; @@ -12,51 +17,71 @@ import com.github.tvbox.osc.bean.Movie; import com.github.tvbox.osc.picasso.RoundTransformation; import com.github.tvbox.osc.util.DefaultConfig; import com.github.tvbox.osc.util.MD5; -import com.squareup.picasso.MemoryPolicy; import com.squareup.picasso.Picasso; import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import me.jessyan.autosize.utils.AutoSizeUtils; -/** - * @author pj567 - * @date :2020/12/21 - * @description: - */ public class GridAdapter extends BaseQuickAdapter { private boolean mShowList = false; + // 内存缓存 + private LruCache bitmapCache; + // 线程池 + private ExecutorService executorService; + public GridAdapter(boolean l) { - super( l ? R.layout.item_list:R.layout.item_grid, new ArrayList<>()); + super(l ? R.layout.item_list : R.layout.item_grid, new ArrayList<>()); this.mShowList = l; + + // 初始化内存缓存,缓存大小为运行内存的 1/8 + int cacheSize = (int) (Runtime.getRuntime().maxMemory() / 8); + bitmapCache = new LruCache(cacheSize) { + @Override + protected int sizeOf(String key, Bitmap value) { + return value.getByteCount(); + } + }; + + // 初始化线程池 + executorService = Executors.newFixedThreadPool(5); // 可根据需要调整线程数量 } @Override protected void convert(BaseViewHolder helper, Movie.Video item) { - if(this.mShowList) { + if (this.mShowList) { helper.setText(R.id.tvNote, item.note); helper.setText(R.id.tvName, item.name); ImageView ivThumb = helper.getView(R.id.ivThumb); - //由于部分电视机使用glide报错 + if (!TextUtils.isEmpty(item.pic)) { - item.pic=item.pic.trim(); - Picasso.get() - .load(DefaultConfig.checkReplaceProxy(item.pic)) - .transform(new RoundTransformation(MD5.string2MD5(item.pic)) - .centerCorp(true) - .override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320)) - .roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL)) - .placeholder(R.drawable.img_loading_placeholder) - .noFade() - .error(R.drawable.img_loading_placeholder) - .into(ivThumb); + item.pic = item.pic.trim(); + if (isBase64Image(item.pic)) { + // 异步加载 Base64 图片 + loadBase64ImageAsync(item.pic, ivThumb); + } else { + // 加载网络图片 + Picasso.get() + .load(DefaultConfig.checkReplaceProxy(item.pic)) + .transform(new RoundTransformation(MD5.string2MD5(item.pic)) + .centerCorp(true) + .override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320)) + .roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL)) + .placeholder(R.drawable.img_loading_placeholder) + .noFade() + .error(R.drawable.img_loading_placeholder) + .into(ivThumb); + } } else { ivThumb.setImageResource(R.drawable.img_loading_placeholder); } return; } + // 处理列表模式的其他逻辑 TextView tvYear = helper.getView(R.id.tvYear); if (item.year <= 0) { tvYear.setVisibility(View.GONE); @@ -66,20 +91,9 @@ public class GridAdapter extends BaseQuickAdapter { } TextView tvLang = helper.getView(R.id.tvLang); tvLang.setVisibility(View.GONE); - /*if (TextUtils.isEmpty(item.lang)) { - tvLang.setVisibility(View.GONE); - } else { - tvLang.setText(item.lang); - tvLang.setVisibility(View.VISIBLE); - }*/ TextView tvArea = helper.getView(R.id.tvArea); tvArea.setVisibility(View.GONE); - /*if (TextUtils.isEmpty(item.area)) { - tvArea.setVisibility(View.GONE); - } else { - tvArea.setText(item.area); - tvArea.setVisibility(View.VISIBLE); - }*/ + if (TextUtils.isEmpty(item.note)) { helper.setVisible(R.id.tvNote, false); } else { @@ -89,21 +103,84 @@ public class GridAdapter extends BaseQuickAdapter { helper.setText(R.id.tvName, item.name); helper.setText(R.id.tvActor, item.actor); ImageView ivThumb = helper.getView(R.id.ivThumb); - //由于部分电视机使用glide报错 + if (!TextUtils.isEmpty(item.pic)) { - item.pic=item.pic.trim(); - Picasso.get() - .load(DefaultConfig.checkReplaceProxy(item.pic)) - .transform(new RoundTransformation(MD5.string2MD5(item.pic)) - .centerCorp(true) - .override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320)) - .roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL)) - .placeholder(R.drawable.img_loading_placeholder) - .noFade() - .error(R.drawable.img_loading_placeholder) - .into(ivThumb); + item.pic = item.pic.trim(); + if (isBase64Image(item.pic)) { + loadBase64ImageAsync(item.pic, ivThumb); + } else { + Picasso.get() + .load(DefaultConfig.checkReplaceProxy(item.pic)) + .transform(new RoundTransformation(MD5.string2MD5(item.pic)) + .centerCorp(true) + .override(AutoSizeUtils.mm2px(mContext, 240), AutoSizeUtils.mm2px(mContext, 320)) + .roundRadius(AutoSizeUtils.mm2px(mContext, 10), RoundTransformation.RoundType.ALL)) + .placeholder(R.drawable.img_loading_placeholder) + .noFade() + .error(R.drawable.img_loading_placeholder) + .into(ivThumb); + } } else { ivThumb.setImageResource(R.drawable.img_loading_placeholder); } } -} \ No newline at end of file + + private boolean isBase64Image(String picUrl) { + return picUrl.startsWith("data:image"); + } + + private void loadBase64ImageAsync(String base64Str, ImageView imageView) { + Bitmap cachedBitmap = bitmapCache.get(base64Str); + if (cachedBitmap != null) { + // 如果缓存中有,直接加载 + imageView.setImageBitmap(cachedBitmap); + } else { + // 异步加载 + executorService.execute(() -> { + Bitmap bitmap = decodeBase64ToBitmap(base64Str); + if (bitmap != null) { + // 存入缓存 + bitmapCache.put(base64Str, bitmap); + // 更新 UI + imageView.post(() -> imageView.setImageBitmap(bitmap)); + } + }); + } + } + + private Bitmap decodeBase64ToBitmap(String base64Str) { + try { + // 提取 Base64 数据部分 + String base64Data = base64Str.substring(base64Str.indexOf(",") + 1); + byte[] decodedBytes = Base64.decode(base64Data, Base64.DEFAULT); + + // 限制解码图片尺寸,防止内存过高 + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; // 只解析尺寸 + BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length, options); + + options.inSampleSize = calculateInSampleSize(options, 180, 260); // 设置缩放比例 + options.inJustDecodeBounds = false; + return BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length, options); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + int height = options.outHeight; + int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + + while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + return inSampleSize; + } +} diff --git a/app/src/main/java/com/github/tvbox/osc/ui/adapter/HomeHotVodAdapter.java b/app/src/main/java/com/github/tvbox/osc/ui/adapter/HomeHotVodAdapter.java index a420bb38..f44e9e40 100644 --- a/app/src/main/java/com/github/tvbox/osc/ui/adapter/HomeHotVodAdapter.java +++ b/app/src/main/java/com/github/tvbox/osc/ui/adapter/HomeHotVodAdapter.java @@ -1,6 +1,9 @@ package com.github.tvbox.osc.ui.adapter; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.text.TextUtils; +import android.util.Base64; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; @@ -59,18 +62,33 @@ public class HomeHotVodAdapter extends BaseQuickAdapter urls; try { BufferedReader bufferedReader = new BufferedReader(new StringReader(str)); - LinkedHashMap> channel = new LinkedHashMap<>(); - LinkedHashMap> channelTemp = channel; + LinkedHashMap> linkedHashMap2 = new LinkedHashMap<>(); + LinkedHashMap> channelTemp = linkedHashMap2; String line; while ((line = bufferedReader.readLine()) != null) { if (line.equals("")) continue; if (line.startsWith("#EXTM3U")) continue; - if (line.startsWith("#EXTINF")) { + if (isSetting(line)) continue; + if (line.startsWith("#EXTINF") || line.contains("#EXTINF")) { String name = getStrByRegex(NAME_PATTERN, line); String group = getStrByRegex(GROUP_PATTERN, line); String url = bufferedReader.readLine().trim(); - if (linkedHashMap.containsKey(group)) { - channelTemp = linkedHashMap.get(group); - } else { - channelTemp = new LinkedHashMap<>(); - linkedHashMap.put(group, channelTemp); - } - if (null != channelTemp && channelTemp.containsKey(name)) { - urls = channelTemp.get(name); - } else { - urls = new ArrayList<>(); - channelTemp.put(name, urls); + if (isUrl(url)) { + if (linkedHashMap.containsKey(group)) { + channelTemp = linkedHashMap.get(group); + } else { + channelTemp = new LinkedHashMap<>(); + linkedHashMap.put(group, channelTemp); + } + if (null != channelTemp && channelTemp.containsKey(name)) { + urls = channelTemp.get(name); + } else { + urls = new ArrayList<>(); + channelTemp.put(name, urls); + } + if (null != urls && !urls.contains(url)) urls.add(url); } - if (null != urls && !urls.contains(url)) urls.add(url); } } bufferedReader.close(); - if (channel.isEmpty()) return; - linkedHashMap.put("未分组", channel); + if (linkedHashMap2.isEmpty()) return; + linkedHashMap.put("未分组", linkedHashMap2); } catch (Exception e) { e.printStackTrace(); } @@ -64,6 +67,14 @@ public class TxtSubscribe { return pattern.pattern().equals(GROUP_PATTERN.pattern()) ? "未分组" : "未命名"; } + private static boolean isUrl(String url) { + return !url.isEmpty() && (url.startsWith("http") || url.startsWith("rtp") || url.startsWith("rtsp") || url.startsWith("rtmp")); + } + + private static boolean isSetting(String line) { + return line.startsWith("ua") || line.startsWith("parse") || line.startsWith("click") || line.startsWith("player") || line.startsWith("header") || line.startsWith("format") || line.startsWith("origin") || line.startsWith("referer") || line.startsWith("#EXTHTTP:") || line.startsWith("#EXTVLCOPT:") || line.startsWith("#KODIPROP:"); + } + public static void parseTxt(LinkedHashMap>> linkedHashMap, String str) { ArrayList arrayList; try { @@ -91,7 +102,7 @@ public class TxtSubscribe { String trim2 = split[0].trim(); for (String str2 : split[1].trim().split("#")) { String trim3 = str2.trim(); - if (!trim3.isEmpty() && (trim3.startsWith("http") || trim3.startsWith("rtp") || trim3.startsWith("rtsp") || trim3.startsWith("rtmp"))) { + if (isUrl(trim3)) { if (!linkedHashMap3.containsKey(trim2)) { arrayList = new ArrayList<>(); linkedHashMap3.put(trim2, arrayList);