diff --git a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java index ffe40e501..099d060b0 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/LiveViewModel.java @@ -20,48 +20,58 @@ import com.github.catvod.net.OkHttp; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.Iterator; +import java.util.EnumMap; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.TimeZone; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; public class LiveViewModel extends ViewModel { - private static final int LIVE = 0; - private static final int EPG = 1; - private static final int URL = 2; - private static final int XML = 3; + private enum TaskType { + + LIVE(Constant.TIMEOUT_LIVE), + EPG(Constant.TIMEOUT_EPG), + XML(Constant.TIMEOUT_XML), + URL(Constant.TIMEOUT_PARSE_LIVE); + + final long timeout; + + TaskType(long timeout) { + this.timeout = timeout; + } + } private final List formatTime; + private final Map> futures; private final SimpleDateFormat formatDate; + private final ExecutorService executor; - public MutableLiveData url; - public MutableLiveData xml; - public MutableLiveData live; - public MutableLiveData epg; - - private ExecutorService executor1; - private ExecutorService executor2; - private ExecutorService executor3; - private ExecutorService executor4; + public final MutableLiveData url; + public final MutableLiveData xml; + public final MutableLiveData live; + public final MutableLiveData epg; public LiveViewModel() { this.live = new MutableLiveData<>(); this.epg = new MutableLiveData<>(); - this.url = new MutableLiveData<>(); this.xml = new MutableLiveData<>(); + this.url = new MutableLiveData<>(); this.formatTime = new ArrayList<>(); + this.futures = new EnumMap<>(TaskType.class); + this.executor = Executors.newFixedThreadPool(4); this.formatDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); this.formatTime.add(new SimpleDateFormat("yyyy-MM-ddHH:mm", Locale.getDefault())); this.formatTime.add(new SimpleDateFormat("yyyy-MM-ddHH:mm:ss", Locale.getDefault())); } public void getLive(Live item) { - execute(LIVE, () -> { + execute(TaskType.LIVE, () -> { LiveParser.start(item.recent()); setTimeZone(item); verify(item); @@ -70,7 +80,7 @@ public class LiveViewModel extends ViewModel { } public void getXml(Live item) { - execute(XML, () -> { + execute(TaskType.XML, () -> { boolean result = false; for (String url : item.getEpgXml()) if (parseXml(item, url)) result = true; return result; @@ -88,14 +98,14 @@ public class LiveViewModel extends ViewModel { public void getEpg(Channel item) { String date = formatDate.format(new Date()); String url = item.getEpg().replace("{date}", date); - execute(EPG, () -> { + execute(TaskType.EPG, () -> { if (url.startsWith("http") && !item.getData().equal(date)) item.setData(Epg.objectFrom(OkHttp.string(url), item.getTvgId(), formatTime)); return item.getData().selected(); }); } public void getUrl(Channel item) { - execute(URL, () -> { + execute(TaskType.URL, () -> { item.setMsg(null); Source.get().stop(); item.setUrl(Source.get().fetch(item)); @@ -104,7 +114,7 @@ public class LiveViewModel extends ViewModel { } public void getUrl(Channel item, EpgData data) { - execute(URL, () -> { + execute(TaskType.URL, () -> { item.setMsg(null); Source.get().stop(); item.setUrl(item.getCatchup().format(Source.get().fetch(item), data)); @@ -122,63 +132,43 @@ public class LiveViewModel extends ViewModel { } private void verify(Live item) { - Iterator iterator = item.getGroups().iterator(); - while (iterator.hasNext()) if (iterator.next().isEmpty()) iterator.remove(); + item.getGroups().removeIf(Group::isEmpty); if (item.getGroups().isEmpty() || item.getGroups().get(0).isKeep()) return; item.getGroups().add(0, Group.create(R.string.keep)); LiveConfig.get().setKeep(item.getGroups()); } - private void execute(int type, Callable callable) { - switch (type) { - case LIVE: - if (executor1 != null) executor1.shutdownNow(); - executor1 = Executors.newFixedThreadPool(2); - executor1.execute(runnable(type, callable, executor1)); - break; - case EPG: - if (executor2 != null) executor2.shutdownNow(); - executor2 = Executors.newFixedThreadPool(2); - executor2.execute(runnable(type, callable, executor2)); - break; - case URL: - if (executor3 != null) executor3.shutdownNow(); - executor3 = Executors.newFixedThreadPool(2); - executor3.execute(runnable(type, callable, executor3)); - break; - case XML: - if (executor4 != null) executor4.shutdownNow(); - executor4 = Executors.newFixedThreadPool(2); - executor4.execute(runnable(type, callable, executor4)); - break; - } - } - - private Runnable runnable(int type, Callable callable, ExecutorService executor) { - return () -> { + private void execute(TaskType type, Callable callable) { + Future oldFuture = futures.get(type); + if (oldFuture != null && !oldFuture.isDone()) oldFuture.cancel(true); + final Future newFuture = executor.submit(callable); + futures.put(type, newFuture); + executor.execute(() -> { try { - if (Thread.interrupted()) return; - if (type == EPG) epg.postValue((Epg) executor.submit(callable).get(Constant.TIMEOUT_EPG, TimeUnit.MILLISECONDS)); - if (type == LIVE) live.postValue((Live) executor.submit(callable).get(Constant.TIMEOUT_LIVE, TimeUnit.MILLISECONDS)); - if (type == XML) xml.postValue((Boolean) executor.submit(callable).get(Constant.TIMEOUT_XML, TimeUnit.MILLISECONDS)); - if (type == URL) url.postValue((Channel) executor.submit(callable).get(Constant.TIMEOUT_PARSE_LIVE, TimeUnit.MILLISECONDS)); + T result = newFuture.get(type.timeout, TimeUnit.MILLISECONDS); + if (newFuture.isCancelled()) return; + if (type == TaskType.EPG) epg.postValue((Epg) result); + else if (type == TaskType.LIVE) live.postValue((Live) result); + else if (type == TaskType.XML) xml.postValue((Boolean) result); + else if (type == TaskType.URL) url.postValue((Channel) result); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); } catch (Throwable e) { - if (e instanceof InterruptedException || Thread.interrupted()) return; + if (newFuture.isCancelled()) return; if (e.getCause() instanceof ExtractException) url.postValue(Channel.error(e.getCause().getMessage())); - else if (type == URL) url.postValue(new Channel()); - if (type == LIVE) live.postValue(new Live()); - if (type == EPG) epg.postValue(new Epg()); - if (type == XML) xml.postValue(false); + else if (type == TaskType.URL) url.postValue(new Channel()); + else if (type == TaskType.LIVE) live.postValue(new Live()); + else if (type == TaskType.EPG) epg.postValue(new Epg()); + else if (type == TaskType.XML) xml.postValue(false); e.printStackTrace(); } - }; + }); } @Override protected void onCleared() { - if (executor1 != null) executor1.shutdownNow(); - if (executor2 != null) executor2.shutdownNow(); - if (executor3 != null) executor3.shutdownNow(); - if (executor4 != null) executor4.shutdownNow(); + super.onCleared(); + for (Future future : futures.values()) if (future != null) future.cancel(true); + if (executor != null) executor.shutdownNow(); } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java index 7e108cd58..2fd0b198f 100644 --- a/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java +++ b/app/src/main/java/com/fongmi/android/tv/model/SiteViewModel.java @@ -291,10 +291,12 @@ public class SiteViewModel extends ViewModel { executor.execute(() -> { try { Result taskResult = future.get(Constant.TIMEOUT_VOD, TimeUnit.MILLISECONDS); - if (!future.isCancelled()) result.postValue(taskResult); + if (future.isCancelled()) return; + result.postValue(taskResult); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (Throwable e) { + if (future.isCancelled()) return; if (e.getCause() instanceof ExtractException) result.postValue(Result.error(e.getCause().getMessage())); else result.postValue(Result.empty()); e.printStackTrace(); @@ -304,7 +306,8 @@ public class SiteViewModel extends ViewModel { @Override protected void onCleared() { - if (executor != null) executor.shutdownNow(); super.onCleared(); + if (future != null) future.cancel(true); + if (executor != null) executor.shutdownNow(); } }