mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-30 23:03:00 +00:00 
			
		
		
		
	-Added serialized cache for transferring serializable objects too large for intent transactions.
-Fixed potential transaction too large exceptions for player intents.
This commit is contained in:
		| @@ -65,8 +65,8 @@ import org.schabi.newpipe.player.playback.PlaybackListener; | ||||
| import org.schabi.newpipe.playlist.PlayQueue; | ||||
| import org.schabi.newpipe.playlist.PlayQueueAdapter; | ||||
| import org.schabi.newpipe.playlist.PlayQueueItem; | ||||
| import org.schabi.newpipe.util.SerializedCache; | ||||
|  | ||||
| import java.io.Serializable; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| import io.reactivex.Observable; | ||||
| @@ -106,7 +106,7 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen | ||||
|     public static final String PLAYBACK_PITCH = "playback_pitch"; | ||||
|     public static final String PLAYBACK_SPEED = "playback_speed"; | ||||
|     public static final String PLAYBACK_QUALITY = "playback_quality"; | ||||
|     public static final String PLAY_QUEUE = "play_queue"; | ||||
|     public static final String PLAY_QUEUE_KEY = "play_queue_key"; | ||||
|     public static final String APPEND_ONLY = "append_only"; | ||||
|     public static final String SELECT_ON_APPEND = "select_on_append"; | ||||
|  | ||||
| @@ -207,10 +207,10 @@ public abstract class BasePlayer implements Player.EventListener, PlaybackListen | ||||
|         if (intent == null) return; | ||||
|  | ||||
|         // Resolve play queue | ||||
|         if (!intent.hasExtra(PLAY_QUEUE)) return; | ||||
|         final Serializable playQueueCandidate = intent.getSerializableExtra(PLAY_QUEUE); | ||||
|         if (!(playQueueCandidate instanceof PlayQueue)) return; | ||||
|         final PlayQueue queue = (PlayQueue) playQueueCandidate; | ||||
|         if (!intent.hasExtra(PLAY_QUEUE_KEY)) return; | ||||
|         final String intentCacheKey = intent.getStringExtra(PLAY_QUEUE_KEY); | ||||
|         final PlayQueue queue = SerializedCache.getInstance().take(intentCacheKey, PlayQueue.class); | ||||
|         if (queue == null) return; | ||||
|  | ||||
|         // Resolve append intents | ||||
|         if (intent.getBooleanExtra(APPEND_ONLY, false) && playQueue != null) { | ||||
|   | ||||
| @@ -118,6 +118,7 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext | ||||
|     public void dispose() { | ||||
|         super.dispose(); | ||||
|         if (fetchReactor != null) fetchReactor.dispose(); | ||||
|         fetchReactor = null; | ||||
|     } | ||||
|  | ||||
|     private static List<PlayQueueItem> extractListItems(final List<InfoItem> infos) { | ||||
|   | ||||
| @@ -84,6 +84,7 @@ public abstract class PlayQueue implements Serializable { | ||||
|         if (eventBroadcast != null) eventBroadcast.onComplete(); | ||||
|         if (reportingReactor != null) reportingReactor.cancel(); | ||||
|  | ||||
|         eventBroadcast = null; | ||||
|         broadcastReceiver = null; | ||||
|         reportingReactor = null; | ||||
|     } | ||||
|   | ||||
| @@ -7,6 +7,8 @@ import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.app.Fragment; | ||||
| import android.support.v4.app.FragmentManager; | ||||
| import android.support.v7.app.AlertDialog; | ||||
| @@ -33,9 +35,9 @@ import org.schabi.newpipe.fragments.list.feed.FeedFragment; | ||||
| import org.schabi.newpipe.fragments.list.kiosk.KioskFragment; | ||||
| import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment; | ||||
| import org.schabi.newpipe.fragments.list.search.SearchFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.LastPlayedFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.LocalPlaylistFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.MostPlayedFragment; | ||||
| import org.schabi.newpipe.fragments.local.bookmark.LastPlayedFragment; | ||||
| import org.schabi.newpipe.history.HistoryActivity; | ||||
| import org.schabi.newpipe.player.BackgroundPlayer; | ||||
| import org.schabi.newpipe.player.BackgroundPlayerActivity; | ||||
| @@ -59,39 +61,41 @@ public class NavigationHelper { | ||||
|     // Players | ||||
|     //////////////////////////////////////////////////////////////////////////*/ | ||||
|  | ||||
|     public static Intent getPlayerIntent(final Context context, | ||||
|                                          final Class targetClazz, | ||||
|                                          final PlayQueue playQueue, | ||||
|                                          final String quality) { | ||||
|         Intent intent = new Intent(context, targetClazz) | ||||
|                 .putExtra(VideoPlayer.PLAY_QUEUE, playQueue); | ||||
|     public static Intent getPlayerIntent(@NonNull final Context context, | ||||
|                                          @NonNull final Class targetClazz, | ||||
|                                          @NonNull final PlayQueue playQueue, | ||||
|                                          @Nullable final String quality) { | ||||
|         Intent intent = new Intent(context, targetClazz); | ||||
|  | ||||
|         final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); | ||||
|         if (cacheKey != null) intent.putExtra(VideoPlayer.PLAY_QUEUE_KEY, cacheKey); | ||||
|         if (quality != null) intent.putExtra(VideoPlayer.PLAYBACK_QUALITY, quality); | ||||
|  | ||||
|         return intent; | ||||
|     } | ||||
|  | ||||
|     public static Intent getPlayerIntent(final Context context, | ||||
|                                          final Class targetClazz, | ||||
|                                          final PlayQueue playQueue) { | ||||
|     public static Intent getPlayerIntent(@NonNull final Context context, | ||||
|                                          @NonNull final Class targetClazz, | ||||
|                                          @NonNull final PlayQueue playQueue) { | ||||
|         return getPlayerIntent(context, targetClazz, playQueue, null); | ||||
|     } | ||||
|  | ||||
|     public static Intent getPlayerEnqueueIntent(final Context context, | ||||
|                                                 final Class targetClazz, | ||||
|                                                 final PlayQueue playQueue, | ||||
|     public static Intent getPlayerEnqueueIntent(@NonNull final Context context, | ||||
|                                                 @NonNull final Class targetClazz, | ||||
|                                                 @NonNull final PlayQueue playQueue, | ||||
|                                                 final boolean selectOnAppend) { | ||||
|         return getPlayerIntent(context, targetClazz, playQueue) | ||||
|                 .putExtra(BasePlayer.APPEND_ONLY, true) | ||||
|                 .putExtra(BasePlayer.SELECT_ON_APPEND, selectOnAppend); | ||||
|     } | ||||
|  | ||||
|     public static Intent getPlayerIntent(final Context context, | ||||
|                                          final Class targetClazz, | ||||
|                                          final PlayQueue playQueue, | ||||
|     public static Intent getPlayerIntent(@NonNull final Context context, | ||||
|                                          @NonNull final Class targetClazz, | ||||
|                                          @NonNull final PlayQueue playQueue, | ||||
|                                          final int repeatMode, | ||||
|                                          final float playbackSpeed, | ||||
|                                          final float playbackPitch, | ||||
|                                          final String playbackQuality) { | ||||
|                                          @Nullable final String playbackQuality) { | ||||
|         return getPlayerIntent(context, targetClazz, playQueue, playbackQuality) | ||||
|                 .putExtra(BasePlayer.REPEAT_MODE, repeatMode) | ||||
|                 .putExtra(BasePlayer.PLAYBACK_SPEED, playbackSpeed) | ||||
|   | ||||
							
								
								
									
										112
									
								
								app/src/main/java/org/schabi/newpipe/util/SerializedCache.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								app/src/main/java/org/schabi/newpipe/util/SerializedCache.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| package org.schabi.newpipe.util; | ||||
|  | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import android.support.v4.util.LruCache; | ||||
| import android.util.Log; | ||||
|  | ||||
| import org.schabi.newpipe.MainActivity; | ||||
|  | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.ObjectInputStream; | ||||
| import java.io.ObjectOutputStream; | ||||
| import java.io.Serializable; | ||||
| import java.util.UUID; | ||||
|  | ||||
| public class SerializedCache { | ||||
|     private static final boolean DEBUG = MainActivity.DEBUG; | ||||
|     private final String TAG = getClass().getSimpleName(); | ||||
|  | ||||
|     private static final SerializedCache instance = new SerializedCache(); | ||||
|     private static final int MAX_ITEMS_ON_CACHE = 5; | ||||
|  | ||||
|     private static final LruCache<String, CacheData> lruCache = | ||||
|             new LruCache<>(MAX_ITEMS_ON_CACHE); | ||||
|  | ||||
|     private SerializedCache() { | ||||
|         //no instance | ||||
|     } | ||||
|  | ||||
|     public static SerializedCache getInstance() { | ||||
|         return instance; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public <T> T take(@NonNull final String key, @NonNull final Class<T> type) { | ||||
|         if (DEBUG) Log.d(TAG, "take() called with: key = [" + key + "]"); | ||||
|         synchronized (lruCache) { | ||||
|             return lruCache.get(key) != null ? getItem(lruCache.remove(key), type) : null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public <T> T get(@NonNull final String key, @NonNull final Class<T> type) { | ||||
|         if (DEBUG) Log.d(TAG, "get() called with: key = [" + key + "]"); | ||||
|         synchronized (lruCache) { | ||||
|             final CacheData data = lruCache.get(key); | ||||
|             return data != null ? getItem(data, type) : null; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public <T extends Serializable> String put(@NonNull T item, @NonNull final Class<T> type) { | ||||
|         final String key = UUID.randomUUID().toString(); | ||||
|         return put(key, item, type) ? key : null; | ||||
|     } | ||||
|  | ||||
|     public <T extends Serializable> boolean put(@NonNull final String key, @NonNull T item, | ||||
|                                                 @NonNull final Class<T> type) { | ||||
|         if (DEBUG) Log.d(TAG, "put() called with: key = [" + key + "], item = [" + item + "]"); | ||||
|         synchronized (lruCache) { | ||||
|             try { | ||||
|                 lruCache.put(key, new CacheData<>(clone(item, type), type)); | ||||
|                 return true; | ||||
|             } catch (final Exception error) { | ||||
|                 Log.e(TAG, "Serialization failed for: ", error); | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public void clear() { | ||||
|         if (DEBUG) Log.d(TAG, "clear() called"); | ||||
|         synchronized (lruCache) { | ||||
|             lruCache.evictAll(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public long size() { | ||||
|         synchronized (lruCache) { | ||||
|             return lruCache.size(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     private <T> T getItem(@NonNull final CacheData data, @NonNull final Class<T> type) { | ||||
|         return type.isAssignableFrom(data.type) ? type.cast(data.item) : null; | ||||
|     } | ||||
|  | ||||
|     @NonNull | ||||
|     private <T extends Serializable> T clone(@NonNull T item, | ||||
|                                              @NonNull final Class<T> type) throws Exception { | ||||
|         final ByteArrayOutputStream bytesOutput = new ByteArrayOutputStream(); | ||||
|         try (final ObjectOutputStream objectOutput = new ObjectOutputStream(bytesOutput)) { | ||||
|             objectOutput.writeObject(item); | ||||
|             objectOutput.flush(); | ||||
|         } | ||||
|         final Object clone = new ObjectInputStream( | ||||
|                 new ByteArrayInputStream(bytesOutput.toByteArray())).readObject(); | ||||
|         return type.cast(clone); | ||||
|     } | ||||
|  | ||||
|     final private static class CacheData<T> { | ||||
|         private final T item; | ||||
|         private final Class<T> type; | ||||
|  | ||||
|         private CacheData(@NonNull final T item, @NonNull Class<T> type) { | ||||
|             this.item = item; | ||||
|             this.type = type; | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 John Zhen Mo
					John Zhen Mo