I have a problem in my code can anyone help me?
I need to make app play story like Messenger app
I want to display a list of images and videos in viewpager automatically or manually
I do it but I faced some problem
First:
when page of image is view and the next page play video the sound of video is playing when view the image because the pager load the next fragment i used
mViewPager.setOffscreenPageLimit(0); but i didn't do any thing
Second one:
when I move manually from video to image the video not stop playing when I search for a solution I found this:
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible())
{
if (!isVisibleToUser) // If we are becoming invisible, then...
{
//player.release();}}}}
it's stop the player but if there is a video in next page it doesn't play
How can I solve this problem?
My code:
public class PostsViews extends Activity {
ArrayList<Post> postsList;
Post postView;
Debate debate;
int position;
private ViewPager mViewPager;
private DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
private Timer t = new Timer();
private int mCurrentPagerIndex = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_posts_views);
position = 0;
ArrayList postList = new ArrayList<>();
postList.add(new Post("debate_112254", "post_123", 1, "https://firebasestorage.googleapis.com/v0/b/satol-19f92.appspot.com/o/UsersPost%2FImages%2FPhoto_96uMAYBw8b.jpg?alt=media&token=71a5fb9d-7a71-465b-b4e3-4ad2c7513bc5"));
postList.add(new Post("debate_112254", "post_111", 2, "https://firebasestorage.googleapis.com/v0/b/satol-19f92.appspot.com/o/UsersPost%2FVideo%2FVideo_ZVZFgP5JGT.mp4?alt=media&token=07ecb08f-950b-46e3-86aa-ea72e6ccf8d5"));
postList.add(new Post("debate_112254", "post_1563", 2, "https://firebasestorage.googleapis.com/v0/b/satol-19f92.appspot.com/o/UsersPost%2FImages%2FPhoto_mWB8XRF7m5.jpg?alt=media&token=85ca502a-09df-46ab-9b0f-218e28487513"));
postList.add(new Post("debate_112254", "post_189", 1, "https://firebasestorage.googleapis.com/v0/b/satol-19f92.appspot.com/o/UsersPost%2FImages%2FPhoto_qVxVgeqUmR.jpg?alt=media&token=8c079e15-4579-41ee-b373-f34dc23ad045"));
postList.add(new Post("debate_112254", "post_561", 1, "https://firebasestorage.googleapis.com/v0/b/satol-19f92.appspot.com/o/UsersPost%2FImages%2FPhoto_L4wKupgboV.jpg?alt=media&token=3f523167-426c-43bd-91df-b146ee8633db"));
postList.add(new Post("debate_112254", "post_56221", 2, "https://firebasestorage.googleapis.com/v0/b/satol-19f92.appspot.com/o/UsersPost%2FVideo%2FVideo_qS6dMVjMv0.mp4?alt=media&token=fca08c17-b4bb-46eb-a698-eef1f3df3980"));
debate = new Debate("debate_112254", postList, "2017-07-12 12:30");
postsList = debate.getPost();
Log.i("-----", debate.getKey());
mDemoCollectionPagerAdapter = new DemoCollectionPagerAdapter(getFragmentManager(), debate);
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
mViewPager.setCurrentItem(position);
mViewPager.setOffscreenPageLimit(0);
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
t.cancel();
t = new Timer();
snapImage();
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
snapImage();
}
public void snapImage() {
final int pos;
pos = mViewPager.getCurrentItem();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (debate.getPost().get(mViewPager.getCurrentItem()).getPostType() == 1) {
if (pos == debate.getPost().size() - 1) {
try {
t.cancel();
finish();
} catch (Exception e) {
}
} else {
runOnUiThread(new Runnable() {
#Override
public void run() {
mViewPager.setCurrentItem(pos + 1);
}
});
}
}
}
}, 10000, 10000);
}
#Override
public void onPause() {
super.onPause();
try {
if (t != null)
t.cancel();
} catch (Exception e) {
}
}
}
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
Depate depate;
public DemoCollectionPagerAdapter(FragmentManager fm, Depate depate) {
super(fm);
this.depate=depate;
}
#Override
public Fragment getItem(int i) {
Fragment fragment = new DemoObjectFragment();
Bundle args = new Bundle();
// Our object is just an integer :-P
args.putInt(DemoObjectFragment.ARG_OBJECT, i );
args.putSerializable("depate",depate);
fragment.setArguments(args);
return fragment;
}
#Override
public int getCount() {
return depate.getPost().size();
}
#Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
DemoObjectFragment.class
public class DemoObjectFragment extends Fragment implements SurfaceHolder.Callback,
MediaPlayer.OnPreparedListener, View.OnClickListener, MediaPlayer.OnCompletionListener {
public static final String ARG_OBJECT = "object";
private Depate depate;
private int position;
SurfaceView videoSurface;
MediaPlayer player;
VideoControllerView controller;
private ImageView postImage;
private Post postView;
private String filePath;
private String type;
private FrameLayout frameLayout;
private RelativeLayout rl_video;
private RelativeLayout activity_view_post;
private int mVideoWidth, mVideoHeight;
private Activity activity;
private String fileName;
private ProgressBar loading;
private LinearLayout ll_data;
private ImageView thumb;
private long POST_VIEW_COUNT = 1;
private String depateID;
private String postID;
long time;
private ProgressDialog pd;
private ArrayList<String> debateList = new ArrayList<>();
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View viewLayout = inflater.inflate(R.layout.fragment_demo_object, container, false);
Bundle args = getArguments();
depate = (Depate) (args.getSerializable("depate"));
position = args.getInt(ARG_OBJECT);
postView = depate.getPost().get(position);
activity = getActivity();
frameLayout = (FrameLayout) viewLayout.findViewById(R.id.videoSurfaceContainer);
rl_video = (RelativeLayout) viewLayout.findViewById(R.id.rl_video);
postImage = (ImageView) viewLayout.findViewById(R.id.postImage);
thumb = (ImageView) viewLayout.findViewById(R.id.thumb);
ll_data = (LinearLayout) viewLayout.findViewById(R.id.ll_data);
loading = (ProgressBar) viewLayout.findViewById(R.id.loading);
loading.getIndeterminateDrawable().setColorFilter(Color.parseColor("#6782fa"), android.graphics.PorterDuff.Mode.MULTIPLY);
loading.setVisibility(View.VISIBLE);
videoSurface = (SurfaceView) viewLayout.findViewById(R.id.videoSurface);
fillData(postView, depate);
return viewLayout;
}
private void fillData(final Post postView, Depate depate) {
filePath = postView.getFilePath();
type = (postView.getPostType() == 1 ? "image/jpeg" : "video/mp4");
if (type.equalsIgnoreCase("video/mp4")) {
SurfaceHolder videoHolder = videoSurface.getHolder();
videoHolder.addCallback(this);
player = new MediaPlayer();
try {
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDataSource(activity, Uri.parse(filePath));
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
thumb.setVisibility(View.VISIBLE);
loading.setVisibility(View.VISIBLE);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
rl_video.setVisibility(View.VISIBLE);
postImage.setVisibility(View.GONE);
} else {
thumb.setVisibility(View.GONE);
postImage.setVisibility(View.VISIBLE);
rl_video.setVisibility(View.GONE);
loading.setVisibility(View.VISIBLE);
Glide.with(activity)
.load(filePath).centerCrop().listener(new RequestListener<String, GlideDrawable>() {
#Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
postImage.setScaleType(ImageView.ScaleType.CENTER);
postImage.setImageResource(R.drawable.ic_avatar);
loading.setVisibility(View.GONE);
return false;
}
#Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
loading.setVisibility(View.GONE);
return false;
}
}).into(postImage);
}
}
#Override
public void onPrepared(MediaPlayer mp) {
player.start();
loading.setVisibility(View.GONE);
thumb.setVisibility(View.GONE);
}
#Override
public void onCompletion(MediaPlayer mp) {
mp.release();
try {
final ViewPager viewPager = (ViewPager) getActivity().findViewById(R.id.pager);
final int pos;
position = viewPager.getCurrentItem();
if (position == depate.getPost().size() - 1) {
try {
getActivity().finish();
} catch (Exception e) {
}
} else {
pos = position;
viewPager.setCurrentItem(pos + 1);
}
} catch (Exception e) {
}
}
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (this.isVisible()) {
if (!isVisibleToUser) {
if (player != null) {
player.release();
}
}else player.start();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
player.setDisplay(holder);
player.prepareAsync();
} catch (Exception e) {
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
activity_posts_views.xml
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000" />
fragment_demo_object.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_view_post"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ff000000"
android:fitsSystemWindows="true"
android:orientation="vertical">
<RelativeLayout
android:id="#+id/rl_media"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<RelativeLayout
android:id="#+id/rl_video"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
<FrameLayout
android:id="#+id/videoSurfaceContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="#+id/videoSurface"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
<ImageView
android:id="#+id/thumb"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerInParent="true"
android:background="#drawable/white_circle_opacity"
android:padding="5dp"
android:src="#drawable/evp_action_play" />
</RelativeLayout>
<ImageView
android:id="#+id/postImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="#000"
android:visibility="visible" />
<ProgressBar
android:id="#+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone" />
</RelativeLayout>
</RelativeLayout>
Debate.class
public class Debate implements Serializable {
String CreatedAt;
String key;
ArrayList<Post> Post;
public Debate(String key, ArrayList<Post> posts, String createdAt) {
this.key = key;
this.Post = posts;
this.CreatedAt = createdAt;
}
public ArrayList<Post> getPost() {
return Post;
}
public void setPost(ArrayList<Post> Post) {
this.Post = Post;
}
public String getCreatedAt() {
return CreatedAt;
}
public void setCreatedAt(String CreatedAt) {
this. CreatedAt = CreatedAt;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
Post.class
public class Post implements Serializable {
String DebateId;
String PostId;
int PostType;
String FilePath;
public Post(String debateId, String postId, int postType, String filePath) {
DebateId = debateId;
PostId = postId;
PostType = postType;
FilePath = filePath;
}
public String getPostId() {
return PostId;
}
public void setPostId(String postId) {
PostId = postId;
}
public String getDebateId() {
return DebateId;
}
public void setDebateId(String DebateId) {
this.DebateId = DebateId;
}
public int getPostType() {
return PostType;
}
public void setPostType(int PostType) {
this.PostType = PostType;
}
public String getFilePath() {
return FilePath;
}
public void setFilePath(String FilePath) {
this.FilePath = FilePath;
}
}
You can write your custom viewpager by copy the viewpager's source like below sample class:
https://gist.github.com/anonymous/24831ea667540ab6a43cc777b7e38a65
Let me know if it works for you.
Related
Hi all I am now integrating youtube API in my app where I have to parse the list of video id's from API then I have to show the videos in a list view when we click on it the video has to be played Until this works fine
There after when the user selects the full-screen mode that is landscape mode I get some errors
public final class VideoGallery extends Fragment implements OnFullscreenListener {
public static Context context;
public static final int ANIMATION_DURATION_MILLIS = 300;
public static final int LANDSCAPE_VIDEO_PADDING_DP = 5;
public final int RECOVERY_DIALOG_REQUEST = 1;
public static VideoListFragment listFragment;
public static VideoFragment videoFragment;
View videoBox;
View view;
View closeButton;
boolean isFullscreen;
public static YouTubePlayer.OnFullscreenListener onFullscreenListener;
static boolean back = false;
FrameLayout relativeLayout;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = getContext();
onFullscreenListener = this;
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
relativeLayout = new FrameLayout(getActivity());
inflater.inflate(R.layout.video_list_demo, relativeLayout, true);
MainActivity.headerText.setText("Video Gallery");
listFragment = (VideoGallery.VideoListFragment) getChildFragmentManager().findFragmentById(R.id.list_fragment);
videoFragment = (VideoGallery.VideoFragment) getActivity().getFragmentManager().findFragmentById(R.id.video_fragment_container);
videoBox = relativeLayout.findViewById(R.id.video_box);
closeButton = relativeLayout.findViewById(R.id.close_button);
closeButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
listFragment.getListView().clearChoices();
listFragment.getListView().requestLayout();
videoFragment.pause();
ViewPropertyAnimator animator = videoBox.animate()
.translationYBy(videoBox.getHeight())
.setDuration(ANIMATION_DURATION_MILLIS);
runOnAnimationEnd(animator, new Runnable() {
#Override
public void run() {
videoBox.setVisibility(View.INVISIBLE);
}
});
}
});
videoBox.setVisibility(View.INVISIBLE);
layout();
checkYouTubeApi();
return relativeLayout;
}
private void checkYouTubeApi() {
YouTubeInitializationResult errorReason =
YouTubeApiServiceUtil.isYouTubeApiServiceAvailable(context);
if (errorReason.isUserRecoverableError()) {
errorReason.getErrorDialog(getActivity(), RECOVERY_DIALOG_REQUEST).show();
} else if (errorReason != YouTubeInitializationResult.SUCCESS) {
String errorMessage =
String.format(getString(R.string.error_player), errorReason.toString());
Toast.makeText(context, errorMessage, Toast.LENGTH_LONG).show();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECOVERY_DIALOG_REQUEST) {
// Recreate the activity if user performed a recovery action
getActivity().recreate();
}
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
layout();
}
#Override
public void onFullscreen(boolean isFullscreen) {
this.isFullscreen = isFullscreen;
layout();
}
private void layout() {
boolean isPortrait = getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
listFragment.getView().setVisibility(isFullscreen ? View.GONE : View.VISIBLE);
listFragment.setLabelVisibility(isPortrait);
closeButton.setVisibility(isPortrait ? View.VISIBLE : View.GONE);
if (isFullscreen) {
videoBox.setTranslationY(0); // Reset any translation that was applied in portrait.
setLayoutSize(videoFragment.getView(), MATCH_PARENT, MATCH_PARENT);
setLayoutSizeAndGravity(videoBox, MATCH_PARENT, MATCH_PARENT, Gravity.TOP | Gravity.LEFT);
} else if (isPortrait) {
setLayoutSize(listFragment.getView(), MATCH_PARENT, MATCH_PARENT);
setLayoutSize(videoFragment.getView(), MATCH_PARENT, WRAP_CONTENT);
setLayoutSizeAndGravity(videoBox, MATCH_PARENT, WRAP_CONTENT, Gravity.BOTTOM);
} else {
videoBox.setTranslationY(0); // Reset any translation that was applied in portrait.
int screenWidth = dpToPx(getResources().getConfiguration().screenWidthDp);
setLayoutSize(listFragment.getView(), screenWidth / 4, MATCH_PARENT);
int videoWidth = screenWidth - screenWidth / 4;
setLayoutSize(videoFragment.getView(), videoWidth, WRAP_CONTENT);
setLayoutSizeAndGravity(videoBox, videoWidth, WRAP_CONTENT,
Gravity.RIGHT | Gravity.CENTER_VERTICAL);
}
}
#TargetApi(16)
private void runOnAnimationEnd(ViewPropertyAnimator animator, final Runnable runnable) {
if (Build.VERSION.SDK_INT >= 16) {
animator.withEndAction(runnable);
} else {
animator.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
runnable.run();
}
});
}
}
public static final class VideoListFragment extends ListFragment {
private static List<VideoEntry> VIDEO_LIST;
private PageAdapter adapter;
private View videoBox;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
callApi();
}
private void callApi() {
new DoGet(this, "videogallery").execute(WebserviceEndpoints.VIDEO_GALLERY);
}
public void handleVideoGalleryResponse(String response) {
try {
List<VideoEntry> list = new ArrayList<VideoEntry>();
if (response.length() > 0) {
JSONObject jsonObject = new JSONObject(response);
JSONArray array = jsonObject.optJSONArray("items");
for (int i = 0; i < array.length(); i++) {
JSONObject data = array.optJSONObject(i);
JSONObject obj = data.optJSONObject("id");
JSONObject obj1 = data.optJSONObject("snippet");
String videoId = obj.optString("videoId");
String videoTitle = obj1.getString("title");
if (!videoId.equals("")) {
list.add(new VideoEntry(videoTitle, videoId));
}
}
VIDEO_LIST = Collections.unmodifiableList(list);
adapter = new PageAdapter(getActivity(), VIDEO_LIST);
setListAdapter(adapter);
}
} catch (Exception e) {
Log.d("", "handleResponse: ", e);
}
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
videoBox = getActivity().findViewById(R.id.video_box);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
String videoId = VIDEO_LIST.get(position).videoId;
back = false;
VideoFragment videoFragment = (VideoFragment) getActivity().getFragmentManager().findFragmentById(R.id.video_fragment_container);
videoFragment.setVideoId(videoId);
if (videoBox.getVisibility() != View.VISIBLE) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
videoBox.setTranslationY(videoBox.getHeight());
}
videoBox.setVisibility(View.VISIBLE);
}
if (videoBox.getTranslationY() > 0) {
videoBox.animate().translationY(0).setDuration(ANIMATION_DURATION_MILLIS);
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
VideoFragment f = (VideoFragment) getActivity().getFragmentManager().findFragmentById(R.id.video_fragment_container);
if (f != null)
getActivity().getFragmentManager().beginTransaction().remove(f).commit();
if (adapter != null)
adapter.releaseLoaders();
}
public void setLabelVisibility(boolean visible) {
if (adapter != null)
adapter.setLabelVisibility(visible);
}
}
private static final class PageAdapter extends BaseAdapter {
private final List<VideoEntry> entries;
private final List<View> entryViews;
private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> thumbnailViewToLoaderMap;
private final LayoutInflater inflater;
private final ThumbnailListener thumbnailListener;
private boolean labelsVisible;
public PageAdapter(Context context, List<VideoEntry> entries) {
this.entries = entries;
entryViews = new ArrayList<View>();
thumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
inflater = LayoutInflater.from(context);
thumbnailListener = new ThumbnailListener();
labelsVisible = true;
}
public void releaseLoaders() {
for (YouTubeThumbnailLoader loader : thumbnailViewToLoaderMap.values()) {
loader.release();
}
}
public void setLabelVisibility(boolean visible) {
labelsVisible = visible;
for (View view : entryViews) {
view.findViewById(R.id.text).setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
#Override
public int getCount() {
return entries.size();
}
#Override
public VideoEntry getItem(int position) {
return entries.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
VideoEntry entry = entries.get(position);
// There are three cases here
if (view == null) {
// 1) The view has not yet been created - we need to initialize the YouTubeThumbnailView.
view = inflater.inflate(R.layout.video_list_item, parent, false);
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
thumbnail.setTag(entry.videoId);
thumbnail.initialize("AIzaSyB8BPeIbu5T1-flG4tpEdrHDPI3Rk2VTDY", thumbnailListener);
} else {
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
YouTubeThumbnailLoader loader = thumbnailViewToLoaderMap.get(thumbnail);
if (loader == null) {
// 2) The view is already created, and is currently being initialized. We store the
// current videoId in the tag.
thumbnail.setTag(entry.videoId);
} else {
// 3) The view is already created and already initialized. Simply set the right videoId
// on the loader.
thumbnail.setImageResource(R.drawable.no_thumbnail);
loader.setVideo(entry.videoId);
}
}
TextView label = ((TextView) view.findViewById(R.id.text));
label.setText(entry.text);
label.setVisibility(labelsVisible ? View.VISIBLE : View.GONE);
return view;
}
private final class ThumbnailListener implements
YouTubeThumbnailView.OnInitializedListener,
YouTubeThumbnailLoader.OnThumbnailLoadedListener {
#Override
public void onInitializationSuccess(
YouTubeThumbnailView view, YouTubeThumbnailLoader loader) {
loader.setOnThumbnailLoadedListener(this);
thumbnailViewToLoaderMap.put(view, loader);
view.setImageResource(R.drawable.no_thumbnail);
String videoId = (String) view.getTag();
loader.setVideo(videoId);
}
#Override
public void onInitializationFailure(
YouTubeThumbnailView view, YouTubeInitializationResult loader) {
view.setImageResource(R.drawable.no_thumbnail);
}
#Override
public void onThumbnailLoaded(YouTubeThumbnailView view, String videoId) {
}
#Override
public void onThumbnailError(YouTubeThumbnailView view, YouTubeThumbnailLoader.ErrorReason errorReason) {
view.setImageResource(R.drawable.no_thumbnail);
}
}
}
public static final class VideoFragment extends YouTubePlayerFragment
implements YouTubePlayer.OnInitializedListener {
private YouTubePlayer player;
private String videoId;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialize("AIzaSyB8BPeIbu5T1-flG4tpEdrHDPI3Rk2VTDY", this);
}
#Override
public void onDestroy() {
if (player != null) {
player.release();
}
super.onDestroy();
}
public void setVideoId(String videoId) {
if (videoId != null && !videoId.equals(this.videoId)) {
this.videoId = videoId;
if (player != null) {
player.cueVideo(videoId);
}
}
}
public void pause() {
if (player != null) {
player.pause();
}
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean restored) {
this.player = player;
player.addFullscreenControlFlag(YouTubePlayer.FULLSCREEN_FLAG_CUSTOM_LAYOUT);
player.setOnFullscreenListener(onFullscreenListener);
if (!restored && videoId != null) {
player.cueVideo(videoId);
}
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult result) {
this.player = null;
}
}
private static final class VideoEntry {
private final String text;
private final String videoId;
public VideoEntry(String text, String videoId) {
this.text = text;
this.videoId = videoId;
}
}
private int dpToPx(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
private static void setLayoutSize(View view, int width, int height) {
ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = width;
params.height = height;
view.setLayoutParams(params);
}
private static void setLayoutSizeAndGravity(View view, int width, int height, int gravity) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) view.getLayoutParams();
params.width = width;
params.height = height;
params.gravity = gravity;
view.setLayoutParams(params);
}
}
This is my fragment
The layout file is
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="#+id/list_fragment"
class="com.mycristoparish.Fragments.VideoGallery$VideoListFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?attr/actionBarSize" />
<LinearLayout
android:id="#+id/video_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<ImageButton
android:id="#+id/close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="#android:drawable/btn_dialog" />
<fragment
android:id="#+id/video_fragment_container"
class="com.mycristoparish.Fragments.VideoGallery$VideoFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</merge>
When I try to play the video in full-screen mode I get the following error
java.lang.IllegalArgumentException: Binary XML file line #42: Duplicate id 0x7f0d0117, tag null, or parent id 0x7f0d0115 with another fragment for com.mycristoparish.Fragments.VideoGallery$VideoFragment
Please guide me how can I move further.
Thanks in advance.
The problem is that you are inflating a layout with a fragment inside a fragment.You cannot do it and so you get the error.However you can dynamically add them.
More details
Note: You cannot inflate a layout into a fragment when that layout includes a . Nested fragments are only supported when added to a fragment dynamically.
OK, this is my last try of to know why the mp.setVolume() does not work, after that I'll throw in the towel. I already asked this to half world and seems that no one know. Ok, this time I'll post the whole code, if anyone know why the mp.setVolume() method does not work anyway, PLEASE, let me know. I really thank.
Note - the sounds are stored in the raw folder
Code:
class to store constants
public abstract class Constantes {
public static String[] labels = {
"Som 1",
"Som 2",
"Som 3",
"Som 4",
"Som 5"
};
public static int[] rawIds = {
R.raw.alarm,
R.raw.battery_caution,
R.raw.beep_beep,
R.raw.call_connect,
R.raw.camera_focus
};
}
mediaPlayer class
public class LoopMediaPlayer {
private Context ctx = null;
private int rawId = 0;
private MediaPlayer currentPlayer = null;
private MediaPlayer nextPlayer = null;
public static LoopMediaPlayer create(Context ctx, int rawId) {
return new LoopMediaPlayer(ctx, rawId);
}
private LoopMediaPlayer(Context ctx, int rawId) {
this.ctx = ctx;
this.rawId = rawId;
currentPlayer = MediaPlayer.create(this.ctx, this.rawId);
currentPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
currentPlayer.start();
}
});
createNextMediaPlayer();
}
private void createNextMediaPlayer() {
nextPlayer = MediaPlayer.create(ctx, rawId);
currentPlayer.setNextMediaPlayer(nextPlayer);
currentPlayer.setOnCompletionListener(onCompletionListener);
}
private MediaPlayer.OnCompletionListener onCompletionListener = new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
mediaPlayer.release();
currentPlayer = nextPlayer;
createNextMediaPlayer();
}
};
public void stopPlayer() {
if (currentPlayer != null && currentPlayer.isPlaying()) {
currentPlayer.stop();
currentPlayer.release();
}
if (nextPlayer != null && nextPlayer.isPlaying()) {
nextPlayer.stop();
nextPlayer.release();
}
}
public void setPlayerVolume(float volume) {
//I already tried this
// float finalV = (float) (1 - (Math.log(MainActivity.mxVol - volume) / Math.log(MainActivity.mxVol)));
// currentPlayer.setVolume(1- finalV, 1- finalV);
// nextPlayer.setVolume(1- finalV, 1- finalV);
//
//and this too
//// float finalV = ((volume * 100) / MainActivity.mxVol) / 100;
currentPlayer.setVolume(volume, volume);
nextPlayer.setVolume(volume, volume);
}
}
main activity
#SuppressLint("SetTextI18n")
public class MainActivity extends AppCompatActivity {
private TextView tvCurVol;
private SeekBar skVol;
private int iniVol = -1;
private SonsAdapter adapter;
private SparseArray<LoopMediaPlayer> players = new SparseArray<>();
private int pos = -1;
public static int mxVol = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
inits();
}
private AdapterView.OnItemClickListener onItemClick() {
return new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (players.get(i) == null) {
LoopMediaPlayer player = LoopMediaPlayer.create(MainActivity.this, Constantes.rawIds[i]);
players.put(i, player);
} else {
LoopMediaPlayer player = players.get(i);
player.stopPlayer();
players.remove(i);
}
}
};
}
private AdapterView.OnItemLongClickListener onItemLongClick() {
return new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
if (players.get(i) != null) {
SonsModel model = (SonsModel) adapter.getItem(i);
pos = i;
int curVol = model.getVolume();
skVol.setProgress(curVol);
skVol.setEnabled(true);
skVol.setOnSeekBarChangeListener(onProgressChange());
return true;
}
return false;
}
};
}
private SeekBar.OnSeekBarChangeListener onProgressChange() {
return new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
LoopMediaPlayer player = players.get(pos);
SonsModel model = (SonsModel) adapter.getItem(pos);
/* I tried change volume this way and so how on method
setPlayerVolume() of LoopMediaPlayer class */
float volume = ((i * 100) / mxVol) / 100;
player.setPlayerVolume(volume);
model.setVolume(i);
tvCurVol.setText("Volume Atual - " + i);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
seekBar.setEnabled(false);
}
};
}
private void inits() {
AudioManager audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
ListView lvSons = (ListView) findViewById(R.id.lvSons);
tvCurVol = (TextView) findViewById(R.id.tvCurVol);
skVol = (SeekBar) findViewById(R.id.skVol);
mxVol = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
TextView tvMxVol = (TextView) findViewById(R.id.tvMxVol);
tvMxVol.setText("Volume Maximo - " + mxVol);
skVol.setMax(mxVol);
skVol.setEnabled(false);
iniVol = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
tvCurVol.setText("Volume Atual - " + iniVol);
adapter = new SonsAdapter(this, createModelList());
lvSons.setAdapter(adapter);
lvSons.setOnItemClickListener(onItemClick());
lvSons.setOnItemLongClickListener(onItemLongClick());
}
private List<SonsModel> createModelList() {
List<SonsModel> modelList = new ArrayList<>();
for (int i = 0; i < Constantes.labels.length; i++) {
modelList.add(new SonsModel(Constantes.labels[i], Constantes.rawIds[i], iniVol));
}
return modelList;
}
}
adapter
public class SonsAdapter extends BaseAdapter {
private Context ctx;
private List<SonsModel> sonsList;
public SonsAdapter(Context ctx, List<SonsModel> sonsList) {
this.ctx = ctx;
this.sonsList = sonsList;
}
#Override
public int getCount() {
return sonsList.size();
}
#Override
public Object getItem(int i) {
return sonsList.get(i);
}
#Override
public long getItemId(int i) {
return i;
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
holder = new ViewHolder();
view = LayoutInflater.from(ctx).inflate(R.layout.adapter_row, viewGroup, false);
holder.tvRow = (TextView) view.findViewById(R.id.tvRow);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
SonsModel model = sonsList.get(i);
holder.tvRow.setText(model.getLabel());
return view;
}
private class ViewHolder {
TextView tvRow;
}
}
finally last class: som model
public class SonsModel {
private String label;
private int rawId;
private int volume;
public SonsModel(String label, int rawId, int volume) {
this.label = label;
this.rawId = rawId;
this.volume = volume;
}
public String getLabel() {
return label;
}
public int getRawId() {
return rawId;
}
public int getVolume() {
return volume;
}
public void setVolume(int volume) {
this.volume = volume;
}
}
Layouts
main activity layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.seekbarmediavolume.MainActivity"
tools:ignore="HardcodedText">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16sp"
android:gravity="center_horizontal"
android:text="Sons"
android:textSize="22sp" />
<TextView
android:id="#+id/tvMxVol"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16sp"
android:gravity="center_horizontal"
android:textSize="22sp" />
<ListView
android:id="#+id/lvSons"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="#+id/tvCurVol"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16sp"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:textSize="22sp" />
<SeekBar
android:id="#+id/skVol"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
adapter row layout
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/tvRow"
android:layout_width="match_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical"
android:textColor="#f00"
android:textSize="16sp" />
I have a Fragment with RecyclerView, which holds items with ImageView (basically like gallery app). Images are displayed using async task to do the work in separate thread. Images are displayed from base64 encoded string. Images are also cached with lrucache.
Problem
Everything works fine until i rotate the device 3rd or 4th time. The device crashes with out of memory error in onSaveInstanceState method.
Question
Any ideas how to prevent the OutOfMemory error? Thanks in advance
Code
Activity
public class TabsActivity extends BaseActivity implements ViewPager.OnPageChangeListener,
ActivityActions, TabLayout.OnTabSelectedListener {
private static final String TAG = TabsActivity.class.getSimpleName();
private static final String STATE_TAB_LAYOUT = "STATE_TAB_LAYOUT";
private static final String STATE_TOOLBAR = "STATE_TOOLBAR";
public static final String ACTION_TASKS = "ACTION_TASKS";
public static final String ACTION_MESSAGES = "ACTION_MESSAGES";
public static final int REQUEST_TASK_UPDATE = 1;
public static final int REQUEST_MESSAGE_UPDATE = 2;
private Toolbar toolbar;
private TabLayout tabLayout;
private ViewPager viewPager;
private FloatingActionButton createButton;
private PrefsManager prefsManager;
private ViewPagerAdapter adapter;
private LocalBroadcastManager broadcastManager;
private NotificationReceiver notificationReceiver;
private FragmentManager.OnBackStackChangedListener backStackChangedListener;
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tabs);
prefsManager = PrefsManager.getInstance(this);
notificationReceiver = new NotificationReceiver();
backStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
onSettingsFragmentStateChanged(false);
}
}
};
tabLayout = (TabLayout) findViewById(R.id.tab_layout);
toolbar = (Toolbar) findViewById(R.id.toolbar);
viewPager = (ViewPager) findViewById(R.id.view_pager);
createButton = (FloatingActionButton) findViewById(R.id.floating_action_button);
createButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
KeyboardUtils.hideSoftwareInput(TabsActivity.this);
if (adapter.getCurrentTab(viewPager.getCurrentItem()) == Tab.TASKS) {
createNewTask();
} else {
createNewConversation();
}
}
});
setSupportActionBar(toolbar);
toolbar.setNavigationIcon(R.drawable.ic_action_back);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
final String action = getIntent().getAction();
adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.setAdapterListener(new ExtendedPagerAdapter.AdapterListener() {
#Override
public void onAdapterInstantiated() {
if (savedInstanceState == null && action != null) {
if (action.equals(ACTION_TASKS)) {
onPageSelected(viewPager.getCurrentItem());
} else {
viewPager.setCurrentItem(1);
}
}
}
});
viewPager.addOnPageChangeListener(this);
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
tabLayout.setOnTabSelectedListener(this);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_TASK_UPDATE) {
if (resultCode == Activity.RESULT_OK) {
((TasksFragment) adapter.getFragment(Tab.TASKS)).onTasksUpdated();
}
} else if (requestCode == REQUEST_MESSAGE_UPDATE) {
TabFragment tabFragment = adapter.getFragment(Tab.MESSAGES);
if (resultCode == Activity.RESULT_OK) {
if (tabFragment != null) {
((MessagesFragment) tabFragment).onNewMessagesReceived();
}
} else {
((MessagesFragment) tabFragment).initData();
}
}
super.onActivityResult(requestCode, resultCode, data);
}
#Override
protected void onResume() {
broadcastManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BroadcastConfig.ACTION_NEW_MESSAGE);
intentFilter.addAction(BroadcastConfig.ACTION_USER_STATUS);
broadcastManager.registerReceiver(notificationReceiver, intentFilter);
getSupportFragmentManager().addOnBackStackChangedListener(backStackChangedListener);
super.onResume();
}
#Override
protected void onPause() {
broadcastManager.unregisterReceiver(notificationReceiver);
getSupportFragmentManager().removeOnBackStackChangedListener(backStackChangedListener);
super.onPause();
}
#Override
protected void onRestoreInstanceState(Bundle inState) {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(inState.getString(STATE_TOOLBAR));
}
if (!inState.getBoolean(STATE_TAB_LAYOUT)) {
onSettingsFragmentStateChanged(true);
}
super.onRestoreInstanceState(inState);
}
#Override
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(STATE_TAB_LAYOUT, tabLayout.getVisibility() == View.VISIBLE);
outState.putString(STATE_TOOLBAR, toolbar.getTitle().toString());
super.onSaveInstanceState(outState);
}
#Override
public void onBackPressed() {
MenuItem menuItem = toolbar.getMenu().findItem(R.id.action_search);
if (menuItem != null && !((SearchView) menuItem.getActionView()).isIconified()) {
((SearchView) menuItem.getActionView()).onActionViewCollapsed();
return;
}
if (popSupportBackStack(SettingsFragment.class.getSimpleName())) {
return;
}
setResult(RESULT_OK);
finish();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_contacts, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
#Override
public boolean onQueryTextSubmit(String query) {
return false;
}
#Override
public boolean onQueryTextChange(String newText) {
adapter.getFragment(viewPager.getCurrentItem()).onSearchPhraseChanged(newText);
return true;
}
});
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
onSettingsClick();
break;
case R.id.action_refresh:
onRefreshClick();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onPageSelected(int position) {
if (adapter.isInstantiated()) {
onToolbarTitleChanged(adapter.getPageTitle(position).toString());
onToolbarSubtitleChanged(UserStatus.NONE);
}
}
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageScrollStateChanged(int state) {
}
#Override
public void onTabSelected(TabLayout.Tab tab) {
if (adapter.getCurrentTab(tab.getPosition()).getFragmentTitle()
== Tab.ATTACHMENT_HISTORY.getFragmentTitle()) {
createButton.hide();
}
viewPager.setCurrentItem(tab.getPosition());
}
#Override
public void onTabUnselected(final TabLayout.Tab tab) {
createButton.hide(new FloatingActionButton.OnVisibilityChangedListener() {
#Override
public void onHidden(FloatingActionButton fab) {
fab.show();
}
});
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
#Override
public void requestDisplayDetails(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode);
}
#Override
public void refreshTasks() {
adapter.getFragment(Tab.TASKS).onRefresh();
}
#Override
public void refreshMessages() {
adapter.getFragment(Tab.MESSAGES).onRefresh();
}
#Override
public boolean isNetworkAvailable() {
return checkNetworkAvailability();
}
private void createNewTask() {
startActivityForResult(new Intent(this, CreateTaskActivity.class), REQUEST_TASK_UPDATE);
}
private void createNewConversation() {
MessagesFragment fragment = (MessagesFragment) adapter.getFragment(Tab.MESSAGES);
startActivityForResult(new Intent(TabsActivity.this, MessageDetailsActivity.class)
.setAction(MessageDetailsActivity.ACTION_CREATE_MESSAGE)
.putExtra(MessageDetailsActivity.EXTRA_EXIST_CONV,
fragment.getCreatedConversations()), REQUEST_MESSAGE_UPDATE);
}
private void setTabLayoutVisible(boolean visible) {
int visibility = visible ? View.VISIBLE : View.GONE;
tabLayout.setVisibility(visibility);
}
private void onRefreshClick() {
if (checkNetworkAvailability()) {
adapter.getFragment(viewPager.getCurrentItem()).onRefresh();
}
}
private void onSettingsClick() {
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, new SettingsFragment(), SettingsFragment.class.getSimpleName())
.addToBackStack(SettingsFragment.class.getSimpleName())
.commit();
onSettingsFragmentStateChanged(true);
}
private void onSettingsFragmentStateChanged(boolean visibleState) {
if (visibleState) {
isFragmentDialog = true;
onToolbarTitleChanged(getString(R.string.title_settings));
setTabLayoutVisible(false);
createButton.hide();
} else {
onPageSelected(viewPager.getCurrentItem());
setTabLayoutVisible(true);
if (adapter.getCurrentTab(viewPager.getCurrentItem()) != Tab.ATTACHMENT_HISTORY) {
createButton.show();
}
}
}
public void onToolbarTitleChanged(String title) {
toolbar.setTitle(title);
}
public void onToolbarSubtitleChanged(UserStatus userStatus) {
if (userStatus != null) {
toolbar.setSubtitle(userStatus.getText());
toolbar.setSubtitleTextColor(userStatus.getColor());
}
}
public void onLogoutConfirmed() {
HttpRequestManager.logout(prefsManager.getPhpSessId(), App.getPhoneId(this), prefsManager.getUserId(),
new HttpCallback<LogoutResponse>() {
#Override
public void onResponse(LogoutResponse logoutResponse) {
prefsManager.reset();
DBManager.delete(TabsActivity.this, DeleteTask.DeleteType.ALL, new Callback<Boolean>() {
#Override
public void onResponseReceived(Boolean params) {
startActivity(new Intent(TabsActivity.this, LoginActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
finish();
}
});
}
});
}
private class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(BroadcastConfig.ACTION_NEW_MESSAGE) || action.equals(BroadcastConfig.ACTION_USER_STATUS)) {
TabFragment childFragment = adapter.getFragment(Tab.MESSAGES);
if (childFragment != null) {
((MessagesFragment) childFragment).onNewMessagesReceived();
}
}
}
}
private class ViewPagerAdapter extends ExtendedPagerAdapter {
private final List<Tab> tabs = Tab.getAllTabs();
private final List<TabFragment> fragments = new ArrayList<>();
public ViewPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
fragments.add((TabFragment) super.instantiateItem(container, position));
return fragments.get(fragments.size() - 1);
}
#Override
public Fragment getItem(int position) {
Log.e(TAG, "CreatingFragment: " + tabs.get(position).getFragmentClass().getCanonicalName());
return Fragment.instantiate(TabsActivity.this, tabs.get(position).getFragmentClass().getCanonicalName());
}
#Override
public CharSequence getPageTitle(int position) {
return getString(tabs.get(position).getFragmentTitle());
}
#Override
public int getCount() {
return tabs.size();
}
public Tab getCurrentTab(int position) {
return tabs.get(position);
}
public TabFragment getFragment(int position) {
if (getCount() > position) {
return fragments.get(position);
}
return null;
}
public TabFragment getFragment(Tab tab) {
for (TabFragment tabFragment : fragments) {
if (tab.getFragmentClass() == tabFragment.getClass()) {
return tabFragment;
}
}
return null;
}
}
}
Fragment
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
swipeRefresh = (SwipeRefresh) inflater.inflate(R.layout.fragment_recycler_view, container, false);
galleryView = (RecyclerView) swipeRefresh.findViewById(R.id.recycler_view);
return swipeRefresh;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
swipeRefresh.setOnRefreshListener(this);
galleryView.setHasFixedSize(true);
galleryView.setLayoutManager(new GridLayoutManager(getContext(), getSpanCount()));
galleryView.setAdapter(adapter = new Adapter(attachments));
if (savedInstanceState == null) {
onRefresh();
} else {
onRestoreInstanceState(savedInstanceState);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
try {
outState.putString(STATE_ATTACHMENTS, Json.fromObject(attachments)); //Crashes here after 3rd or 4th rotate
} catch (JsonProcessingException e) {
Log.e(TAG, "Error while saving attachments", e);
}
super.onSaveInstanceState(outState);
}
#Override
public void onSearchPhraseChanged(String phrase) {
}
#Override
public void onRefresh() {
swipeRefresh.setRefreshing(true);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
initSampleData();
}
}, 3000);
}
private void onRestoreInstanceState(Bundle savedInstanceState) {
try {
attachments = Json.toCollection(savedInstanceState.getString(STATE_ATTACHMENTS),
ArrayList.class, Attachment.class);
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.e(TAG, "Error while restoring attachments", e);
}
}
private void initSampleData() {
swipeRefresh.setRefreshing(false);
String image = "";
File path = new File(Environment.getExternalStorageDirectory(), "image.txt");
byte[] bytes = new byte[(int) path.length()];
try {
FileInputStream fileInputStream = new FileInputStream(path);
fileInputStream.read(bytes);
image = new String(bytes);
} catch (FileNotFoundException e) {
Log.e(TAG, "Error while finding file to read from", e);
} catch (IOException e) {
Log.e(TAG, "Error while writing from file to string", e);
}
Attachment attachment = new Attachment(image);
attachments.clear();
for (int i = 0; i < 100; i++) {
attachment.setFileName(String.valueOf(i));
attachments.add(attachment);
}
adapter.notifyDataSetChanged();
}
private int getSpanCount() {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
float width = displayMetrics.widthPixels / displayMetrics.density;
float height = displayMetrics.heightPixels / displayMetrics.density;
int size;
if (Math.min(width, height) >= 600) {
size = Math.round(width / THUMBNAIL_SIZE_TABLET);
} else {
size = Math.round(width / THUMBNAIL_SIZE_PHONE);
}
return size < 7 ? size : 6;
}
private class ViewHolder extends BaseHolder<Attachment> implements View.OnClickListener {
private ImageView imageView;
public ViewHolder(ViewGroup viewGroup, int layoutRes) {
super(viewGroup, layoutRes);
imageView = (ImageView) itemView;
}
#Override
public void bind(Attachment attachment) {
itemView.setOnClickListener(this);
if (attachment.getImage() != null && !attachment.getImage().isEmpty()) {
DisplayThumbnailRequest.loadBitmap(attachment, imageView);
}
}
#Override
public void onClick(View v) {
// TODO: 2016-01-15 Open image in fullscreen
}
}
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
private List<Attachment> attachments;
public Adapter(List<Attachment> attachments) {
this.attachments = attachments;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewHolder(parent, R.layout.adapter_item_attachment_history);
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.bind(attachments.get(position));
}
#Override
public int getItemCount() {
return attachments.size();
}
}
AsyncTask
public class DisplayThumbnailRequest extends AsyncHttpTask<Attachment, Void, Bitmap> {
private static final String TAG = DisplayThumbnailRequest.class.getSimpleName();
private WeakReference<ImageView> imageViewRef;
private Attachment attachment;
public DisplayThumbnailRequest(ImageView imageView) {
this.imageViewRef = new WeakReference<>(imageView);
}
#Override
protected void onPreExecute() {
if (imageViewRef != null) {
ImageView imageView = imageViewRef.get();
if (imageView != null) {
if (imageView.getVisibility() != View.VISIBLE) {
imageView.setVisibility(View.VISIBLE);
}
imageView.setImageResource(R.mipmap.ic_launcher);
}
}
}
#Override
protected Bitmap doInBackground(Attachment... params) {
attachment = params[0];
Bitmap bitmap = BitmapCache.getBitmap(attachment.getFileName());
if (bitmap == null) {
bitmap = BitmapUtils.fromBase64(attachment.getImage());
BitmapCache.addBitmap(attachment.getFileName(), bitmap);
}
return bitmap;
}
#Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewRef != null && bitmap != null) {
ImageView imageView = imageViewRef.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
#Override
protected void onResponseReceived() {
}
public Attachment getAttachment() {
return attachment;
}
public static void loadBitmap(Attachment attachment, ImageView imageView) {
if (cancelDownloadRequest(attachment, imageView)) {
DisplayThumbnailRequest request = new DisplayThumbnailRequest(imageView);
AsyncBitmapDrawable drawable = new AsyncBitmapDrawable(App.getRes(), null, request);
imageView.setImageDrawable(drawable);
request.execute(attachment);
}
}
private static boolean cancelDownloadRequest(Attachment attachment, ImageView imageView) {
DisplayThumbnailRequest request = getDownloadTask(imageView);
if (request != null) {
String filePath = request.getAttachment().getFileName();
if (filePath == null || filePath.isEmpty() || !filePath.equals(attachment.getFileName())) {
request.cancel(true);
} else {
return false;
}
}
return true;
}
private static DisplayThumbnailRequest getDownloadTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof AsyncBitmapDrawable) {
return ((AsyncBitmapDrawable) drawable).getDisplayThumbnailRequest();
}
}
return null;
}
}
BitmapCache
public class BitmapCache {
private static final String TAG = BitmapCache.class.getSimpleName();
private static final int MAX_MEMORY = (int)((Runtime.getRuntime().maxMemory() / 1024) / 4);
private static LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(MAX_MEMORY) {
#Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount() / 1024;
}
};
public static void addBitmap(String key, Bitmap bitmap) {
if (getBitmap(key) == null) {
lruCache.put(key, bitmap);
}
}
public static Bitmap getBitmap(String key) {
return lruCache.get(key);
}
}
BitmapUtils.fromBase64
public static Bitmap fromBase64(String string) {
if (string != null && !string.isEmpty()) {
byte[] decodedString = Base64.decode(string, Base64.DEFAULT);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length, options);
options.inSampleSize = getInSampleSize(options, Metrics.dp2px(100), Metrics.dp2px(100));
options.inJustDecodeBounds = false;
return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length, options);
}
return null;
}
EDIT
I tried reducing arraylist size which is saved in onSavedInstanceState from 100 to 50 and OOM error is not being displayed (despite how many times you rotate the device). Can it be, that saved instance is too long (if it list has 100 items) and it floods the memory?
The problem is located in your
onRefresh() method.
Your should remove all calbacks from handler if activity is beeing stopped.
Try this:
private Handler handler = new Handler();
#Override
public void onRefresh() {
swipeRefresh.setRefreshing(true);
handler.postDelayed(new Runnable() {
#Override
public void run() {
initSampleData();
}
}, 3000);
}
#Override
protected void onStop() {
super.onStop();
handler.removeCallbacksAndMessages(null);
}
I have an app which loads feeds from a webservice. Uuntil the feed is loaded I show a Dialog saying "please wait...".
I want to show a Circle ProgressBar instead.
What I am showing
What I want to show
public class M {
static ProgressDialog pDialog;
private static SharedPreferences mSharedPreferences;
public static void showLoadingDialog(Context mContext) {
pDialog = new ProgressDialog(mContext);
pDialog.setMessage(mContext.getString(R.string.please_wait));
pDialog.setIndeterminate(true);
pDialog.setCancelable(true);
pDialog.show();
}
}
Activity that shows that Progress Dialog
public class HomeFragment extends Fragment implements OnClickListener {
public RecyclerView postsList;
public View mView;
public FloatingActionButton mFabButton;
public Toolbar toolbar;
public Intent mIntent;
public LinearLayoutManager layoutManager;
int currentPage = 1;
private HomeListAdapter mHomeListAdapter;
private SwipeRefreshLayout mSwipeRefreshLayout;
private CacheManager mCacheManager;
private Gson mGson;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mCacheManager = CacheManager.getInstance(getActivity().getApplicationContext());
mGson = new Gson();
mView = inflater.inflate(R.layout.fragment_home, container, false);
initializeView();
((AppCompatActivity) getActivity()).getSupportActionBar().setTitle(R.string.title_home);
((AppCompatActivity) getActivity()).getSupportActionBar().setShowHideAnimationEnabled(true);
getPosts(true);
return mView;
}
private void initializeView() {
postsList = (RecyclerView) mView.findViewById(R.id.postsList);
mFabButton = (FloatingActionButton) mView.findViewById(R.id.fabButton);
mFabButton.setOnClickListener(this);
mFabButton.setRippleColor(getActivity().getResources().getColor(R.color.accentColor));
//layout manager
layoutManager = new LinearLayoutManager(getActivity().getApplicationContext());
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
postsList.setLayoutManager(layoutManager);
mHomeListAdapter = new HomeListAdapter(getActivity(), new ArrayList<PostsItem>());
postsList.setAdapter(mHomeListAdapter);
mSwipeRefreshLayout = (SwipeRefreshLayout) mView.findViewById(R.id.swipeHome);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
setCurrentPage(1);
getPosts(false);
}
});
//setting up our OnScrollListener
postsList.addOnScrollListener(new HidingScrollListener(layoutManager) {
#Override
public void onHide() {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mFabButton.getLayoutParams();
int fabBottomMargin = lp.bottomMargin;
mFabButton.animate().translationY(mFabButton.getHeight() + fabBottomMargin).setInterpolator(new AccelerateInterpolator(2)).start();
}
#Override
public void onShow() {
mFabButton.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2)).start();
}
#Override
public void onLoadMore(int currentPage) {
setCurrentPage(currentPage);
getPosts(false);
}
});
}
#Override
public void onDestroy() {
super.onResume();
M.hideLoadingDialog();
}
public void getPosts(boolean isMain) {
if (M.isNetworkAvailable(getActivity().getApplicationContext())) {
if (isMain) {
M.showLoadingDialog(getActivity());
}
PostsAPI mPostsAPI = APIService.createService(PostsAPI.class, M.getToken(getActivity()));
mPostsAPI.getPosts(getCurrentPage(), new Callback<List<PostsItem>>() {
#Override
public void success(List<PostsItem> postsItems, retrofit.client.Response response) {
if (postsItems.size() == 0) {
} else {
try {
mCacheManager.write(mGson.toJson(postsItems), "Posts-" + getCurrentPage() + ".json");
} catch (Exception e) {
e.printStackTrace();
}
}
updateView(postsItems);
}
#Override
public void failure(RetrofitError error) {
M.T(getActivity(), getString(R.string.ServerError));
M.hideLoadingDialog();
}
});
} else {
try {
String Posts = mCacheManager.readString("Posts-" + getCurrentPage() + ".json");
Gson mgson = new Gson();
updateView((List<PostsItem>) mgson.fromJson(Posts, new TypeToken<List<PostsItem>>() {
}.getType()));
} catch (Exception e) {
// M.L(e.getMessage());
}
}
}
private void showWelcomeMessage() {
mView.findViewById(R.id.welcomePanel).setVisibility(View.VISIBLE);
postsList.setVisibility(View.GONE);
}
private void updateView(List<PostsItem> postsItems) {
if (getCurrentPage() != 1) {
List<PostsItem> oldItems = mHomeListAdapter.getPosts();
if (oldItems.size() == 0 && postsItems.size() == 0) {
showWelcomeMessage();
}
oldItems.addAll(postsItems);
mHomeListAdapter.setPosts(oldItems);
} else {
if (postsItems.size() == 0) {
showWelcomeMessage();
}
mHomeListAdapter.setPosts(postsItems);
}
if (mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(false);
}
M.hideLoadingDialog();
}
#Override
public void onClick(View v) {
if (v.getId() == R.id.fabButton) {
mIntent = new Intent(getActivity(), PublishActivity.class);
startActivity(mIntent);
}
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
}
the one you are showing is a ProgressDialog and one you want to show is a ProgressBar.
you need to include a progressbar in your layout something like this:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ProgressBar
android:id="#+id/progressbar"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<!-- your entire layout here -->
</LinearLayout>
</RelativeLayout>
then you can show or hide the progress bar and/or rest of your layout from java like this:
show:
findViewById(R.id.progressbar).setVisibility(View.VISIBLE);
hide:
findViewById(R.id.progressbar).setVisibility(View.GONE);
I am trying to implement a list with videos like vine or Instagram app. Where they play video plays when list item is shown or fully visible and video pauses when list item gets hided. I am using textureview with media player to play a video from url and added it as list item in recyclerview. Following is my code.
VideosAdapter Class:
public class VideosAdapter extends RecyclerView.Adapter<VideosAdapter.ViewHolder> {
Context context;
private ArrayList<String> urls;
public static class ViewHolder extends RecyclerView.ViewHolder {
public LinearLayout layout;
public TextView textView;
public ViewHolder(View v) {
super(v);
layout = (LinearLayout) v.findViewById(R.id.linearLayout);
textView = (TextView) v.findViewById(R.id.textView);
}
}
public VideosAdapter(Context context, ArrayList<String> urls) {
this.context = context;
this.urls = urls;
}
// Create new views (invoked by the layout manager)
#Override
public VideosAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_main, parent, false);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String url = urls.get(position);
holder.textView.setText(url);
playVideo(holder, url);
}
#Override
public int getItemCount() {
return urls.size();
}
private void playVideo(ViewHolder holder, String url)
{
final CustomVideoPlayer vid = new CustomVideoPlayer(String.valueOf(url), context);
holder.layout.addView(vid);
holder.layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
vid.changePlayState();
}
});
}
}
CustomVideoPlayer Class:
public class CustomVideoPlayer extends TextureView implements TextureView.SurfaceTextureListener
{
Context context;
String url;
MediaPlayer mp;
Surface surface;
SurfaceTexture s;
public CustomVideoPlayer(Context context, AttributeSet attrs)
{
super(context, attrs);
this.context = context;
}
public CustomVideoPlayer(String ur, Context context)
{
super(context);
this.setSurfaceTextureListener(this);
this.url = ur;
this.context = context;
}
#Override
public void onSurfaceTextureAvailable(final SurfaceTexture surface, int arg1, int arg2) {
this.s = surface;
Log.d("url", this.url);
startVideo(surface);
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture arg0) {
return true;
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture arg0, int arg1,int arg2) {
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture arg0) {
}
public void setVideo(String url)
{
this.url = url;
}
public void startVideo(SurfaceTexture t)
{
this.surface = new Surface(t);
this.mp = new MediaPlayer();
this.mp.setSurface(this.surface);
try {
Uri uri = Uri.parse(this.url);
this.mp.setDataSource(url);
this.mp.prepareAsync();
this.mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
mp.setLooping(true);
mp.start();
}
});
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (IllegalStateException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
try {
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public void changePlayState()
{
if(this.mp.isPlaying())
this.mp.pause();
else
this.mp.start();
}
}
When i run this code there are multiple issues in it.
1) First two items/videos buffers and play fine. But when i scroll it does not load third video and first video also gets removed from the list.
2) On scroll videos/list items starts buffering again for the item that was already buffered.
3) On fast scroll list gets too laggy and get stuck and crashes.
Attached is the image of logcat that i get while list scroll and video playing.
Can anyone guide me through this? What is the right way to create a list like vine app?
I was able to achieve that by first downloading the videos from url and then playing it with custom player. Here is how i did in case if anyone else needed that:
1) Get all url's need to be played
2) Start downloading videos (in queue) from urls in local storage and keep a flag in preferences (that a video is already downloaded or not)
3) Assign urls to Adapter in which initialize object of video player controller that handles video playbacks
4) Set addOnScrollListener to check which position/video is currently visible and check if video is already downloaded or not if yes then play it.
Following is complete code:
MainActivity
public class MainActivity extends ActionBarActivity implements IVideoDownloadListener {
private static String TAG = "MainActivity";
private Context context;
private RecyclerView mRecyclerView;
private ProgressBar progressBar;
private VideosAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private ArrayList<Video> urls;
VideosDownloader videosDownloader;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = MainActivity.this;
mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
progressBar = (ProgressBar) findViewById(R.id.progressBar);
urls = new ArrayList<Video>();
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
mAdapter = new VideosAdapter(MainActivity.this, urls);
mRecyclerView.setAdapter(mAdapter);
videosDownloader = new VideosDownloader(context);
videosDownloader.setOnVideoDownloadListener(this);
if(Utils.hasConnection(context))
{
getVideoUrls();
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
#Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
LinearLayoutManager layoutManager = ((LinearLayoutManager) recyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition = layoutManager.findFirstCompletelyVisibleItemPosition();
Video video;
if (urls != null && urls.size() > 0)
{
if (findFirstCompletelyVisibleItemPosition >= 0) {
video = urls.get(findFirstCompletelyVisibleItemPosition);
mAdapter.videoPlayerController.setcurrentPositionOfItemToPlay(findFirstCompletelyVisibleItemPosition);
mAdapter.videoPlayerController.handlePlayBack(video);
}
else
{
video = urls.get(firstVisiblePosition);
mAdapter.videoPlayerController.setcurrentPositionOfItemToPlay(firstVisiblePosition);
mAdapter.videoPlayerController.handlePlayBack(video);
}
}
}
}
});
}
else
Toast.makeText(context, "No internet available", Toast.LENGTH_LONG).show();
}
#Override
public void onVideoDownloaded(Video video) {
mAdapter.videoPlayerController.handlePlayBack(video);
}
private void getVideoUrls()
{
Video video1 = new Video("0", "1", "http://techslides.com/demos/sample-videos/small.mp4");
urls.add(video1);
Video video2 = new Video("1", "2", "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4");
urls.add(video2);
Video video3 = new Video("2", "3", "http://sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4");
urls.add(video3);
Video video4 = new Video("3", "4", "http://dev.exiv2.org/attachments/341/video-2012-07-05-02-29-27.mp4");
urls.add(video4);
Video video5 = new Video("4", "5", "http://techslides.com/demos/sample-videos/small.mp4");
urls.add(video5);
Video video6 = new Video("5", "6", "http://www.quirksmode.org/html5/videos/big_buck_bunny.mp4");
urls.add(video6);
Video video7 = new Video("6", "7", "http://sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4");
urls.add(video7);
mAdapter.notifyDataSetChanged();
progressBar.setVisibility(View.GONE);
videosDownloader.startVideosDownloading(urls);
}
}
VideosAdapter
public class VideosAdapter extends RecyclerView.Adapter<VideosAdapter.ViewHolder> {
private static String TAG = "VideosAdapter";
Context context;
private ArrayList<Video> urls;
public VideoPlayerController videoPlayerController;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public ProgressBar progressBar;
public RelativeLayout layout;
public ViewHolder(View v) {
super(v);
layout = (RelativeLayout) v.findViewById(R.id.layout);
textView = (TextView) v.findViewById(R.id.textView);
progressBar = (ProgressBar) v.findViewById(R.id.progressBar);
}
}
public VideosAdapter(Context context, final ArrayList<Video> urls) {
this.context = context;
this.urls = urls;
videoPlayerController = new VideoPlayerController(context);
}
// Create new views (invoked by the layout manager)
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_main, parent, false);
Configuration configuration = context.getResources().getConfiguration();
int screenWidthDp = configuration.screenWidthDp; //The current width of the available screen space, in dp units, corresponding to screen width resource qualifier.
int smallestScreenWidthDp = configuration.smallestScreenWidthDp; //The smallest screen size an application will see in normal operation, corresponding to smallest screen width resource qualifier.
ViewHolder viewHolder = new ViewHolder(v);
int screenWidthPixels = Utils.convertDpToPixel(screenWidthDp, context);
RelativeLayout.LayoutParams rel_btn = new RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, screenWidthPixels);
viewHolder.layout.setLayoutParams(rel_btn);
return viewHolder;
}
// Replace the contents of a view (invoked by the layout manager)
#Override
public void onBindViewHolder(final ViewHolder holder, int position) {
Video video = urls.get(position);
holder.textView.setText("Video " + video.getId());
final VideoPlayer videoPlayer = new VideoPlayer(context);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
videoPlayer.setLayoutParams(params);
holder.layout.addView(videoPlayer);
videoPlayerController.loadVideo(video, videoPlayer, holder.progressBar);
videoPlayer.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
videoPlayer.changePlayState();
}
});
}
#Override
public void onViewRecycled(ViewHolder holder) {
super.onViewRecycled(holder);
Log.d(TAG, "onViewRecycledCalled");
holder.layout.removeAllViews();
}
#Override
public int getItemCount() {
return urls.size();
}
}
VideosDownloader
public class VideosDownloader {
private static String TAG = "VideosDownloader";
Context context;
FileCache fileCache;
IVideoDownloadListener iVideoDownloadListener;
public VideosDownloader(Context context) {
this.context = context;
fileCache = new FileCache(context);
}
/////////////////////////////////////////////////////////////////
// Start downloading all videos from given urls
public void startVideosDownloading(final ArrayList<Video> videosList)
{
Thread thread = new Thread(new Runnable() {
#Override
public void run()
{
for(int i=0; i<videosList.size(); i++)
{
final Video video = videosList.get(i);
String id = video.getId();
String url = video.getUrl();
String isVideoDownloaded = Utils.readPreferences(context, video.getUrl(), "false");
boolean isVideoAvailable = Boolean.valueOf(isVideoDownloaded);
if(!isVideoAvailable)
{
//Download video from url
String downloadedPath = downloadVideo(url);
//Log.i(TAG, "Vides downloaded at: " + downloadedPath);
Activity activity = (Activity) context;
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
Utils.savePreferences(context, video.getUrl(), "true");
iVideoDownloadListener.onVideoDownloaded(video);
}
});
}
}
}
});
thread.start();
}
/////////////////////////////////////////////////////////////////
private String downloadVideo(String urlStr)
{
URL url = null;
File file = null;
try
{
file = fileCache.getFile(urlStr);
url = new URL(urlStr);
long startTime = System.currentTimeMillis();
URLConnection ucon = null;
ucon = url.openConnection();
InputStream is = ucon.getInputStream();
BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);
FileOutputStream outStream = new FileOutputStream(file);
byte[] buff = new byte[5 * 1024];
//Read bytes (and store them) until there is nothing more to read(-1)
int len;
while ((len = inStream.read(buff)) != -1) {
outStream.write(buff, 0, len);
}
//clean up
outStream.flush();
outStream.close();
inStream.close();
}
catch (MalformedURLException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return file.getAbsolutePath();
}
public void setOnVideoDownloadListener(IVideoDownloadListener iVideoDownloadListener) {
this.iVideoDownloadListener = iVideoDownloadListener;
}
}
VideoPlayerController
public class VideoPlayerController {
private static String TAG = "VideoPlayerController";
Context context;
FileCache fileCache;
int currentPositionOfItemToPlay = 0;
Video currentPlayingVideo;
private Map<String, VideoPlayer> videos = Collections.synchronizedMap(new WeakHashMap<String, VideoPlayer>());
private Map<String, ProgressBar> videosSpinner = Collections.synchronizedMap(new WeakHashMap<String, ProgressBar>());
public VideoPlayerController(Context context) {
this.context = context;
fileCache = new FileCache(context);
}
public void loadVideo(Video video, VideoPlayer videoPlayer, ProgressBar progressBar) {
//Add video to map
videos.put(video.getIndexPosition(), videoPlayer);
videosSpinner.put(video.getIndexPosition(), progressBar);
handlePlayBack(video);
}
//This method would check two things
//First if video is downloaded or its local path exist
//Second if the videoplayer of this video is currently showing in the list or visible
public void handlePlayBack(Video video)
{
//Check if video is available
if(isVideoDownloaded(video))
{
// then check if it is currently at a visible or playable position in the listview
if(isVideoVisible(video))
{
//IF yes then playvideo
playVideo(video);
}
}
}
private void playVideo(final Video video)
{
//Before playing it check if this video is already playing
if(currentPlayingVideo != video)
{
//Start playing new url
if(videos.containsKey(video.getIndexPosition()))
{
final VideoPlayer videoPlayer2 = videos.get(video.getIndexPosition());
String localPath = fileCache.getFile(video.getUrl()).getAbsolutePath();
if(!videoPlayer2.isLoaded)
{
videoPlayer2.loadVideo(localPath, video);
videoPlayer2.setOnVideoPreparedListener(new IVideoPreparedListener() {
#Override
public void onVideoPrepared(Video mVideo) {
//Pause current playing video if any
if(video.getIndexPosition() == mVideo.getIndexPosition())
{
if(currentPlayingVideo!=null)
{
VideoPlayer videoPlayer1 = videos.get(currentPlayingVideo.getIndexPosition());
videoPlayer1.pausePlay();
}
videoPlayer2.mp.start();
currentPlayingVideo = mVideo;
}
}
});
}
else
{
//Pause current playing video if any
if(currentPlayingVideo!=null)
{
VideoPlayer videoPlayer1 = videos.get(currentPlayingVideo.getIndexPosition());
videoPlayer1.pausePlay();
}
boolean isStarted = videoPlayer2.startPlay();
{
//Log.i(TAG, "Started playing Video Index: " + video.getIndexPosition());
//Log.i(TAG, "Started playing Video: " + video.getUrl());
}
currentPlayingVideo = video;
}
}
}
else
{
//Log.i(TAG, "Already playing Video: " + video.getUrl());
}
}
private boolean isVideoVisible(Video video) {
//To check if the video is visible in the listview or it is currently at a playable position
//we need the position of this video in listview and current scroll position of the listview
int positionOfVideo = Integer.valueOf(video.getIndexPosition());
if(currentPositionOfItemToPlay == positionOfVideo)
return true;
return false;
}
private boolean isVideoDownloaded(Video video) {
String isVideoDownloaded = Utils.readPreferences(context, video.getUrl(), "false");
boolean isVideoAvailable = Boolean.valueOf(isVideoDownloaded);
if(isVideoAvailable)
{
//If video is downloaded then hide its progress
hideProgressSpinner(video);
return true;
}
showProgressSpinner(video);
return false;
}
private void showProgressSpinner(Video video) {
ProgressBar progressBar = videosSpinner.get(video.getIndexPosition());
if(progressBar!=null)
progressBar.setVisibility(View.VISIBLE);
}
private void hideProgressSpinner(Video video) {
ProgressBar progressBar = videosSpinner.get(video.getIndexPosition());
if(progressBar!=null && progressBar.isShown())
{
progressBar.setVisibility(View.GONE);
Log.i(TAG, "ProgressSpinner Hided Index: " + video.getIndexPosition());
}
}
public void setcurrentPositionOfItemToPlay(int mCurrentPositionOfItemToPlay) {
currentPositionOfItemToPlay = mCurrentPositionOfItemToPlay;
}
}
VideoPlayer
public class VideoPlayer extends TextureView implements TextureView.SurfaceTextureListener {
private static String TAG = "VideoPlayer";
/**This flag determines that if current VideoPlayer object is first item of the list if it is first item of list*/
boolean isFirstListItem;
boolean isLoaded;
boolean isMpPrepared;
IVideoPreparedListener iVideoPreparedListener;
Video video;
String url;
MediaPlayer mp;
Surface surface;
SurfaceTexture s;
public VideoPlayer(Context context) {
super(context);
}
public VideoPlayer(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public void loadVideo(String localPath, Video video) {
this.url = localPath;
this.video = video;
isLoaded = true;
if (this.isAvailable()) {
prepareVideo(getSurfaceTexture());
}
setSurfaceTextureListener(this);
}
#Override
public void onSurfaceTextureAvailable(final SurfaceTexture surface, int width, int height) {
isMpPrepared = false;
prepareVideo(surface);
}
#Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
#Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if(mp!=null)
{
mp.stop();
mp.reset();
mp.release();
mp = null;
}
return false;
}
#Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
public void prepareVideo(SurfaceTexture t)
{
this.surface = new Surface(t);
mp = new MediaPlayer();
mp.setSurface(this.surface);
try {
mp.setDataSource(url);
mp.prepareAsync();
mp.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mp) {
isMpPrepared = true;
mp.setLooping(true);
iVideoPreparedListener.onVideoPrepared(video);
}
});
} catch (IllegalArgumentException e1) {
e1.printStackTrace();
} catch (SecurityException e1) {
e1.printStackTrace();
} catch (IllegalStateException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
try {
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
try {
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
#Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
}
#Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
}
public boolean startPlay()
{
if(mp!=null)
if(!mp.isPlaying())
{
mp.start();
return true;
}
return false;
}
public void pausePlay()
{
if(mp!=null)
mp.pause();
}
public void stopPlay()
{
if(mp!=null)
mp.stop();
}
public void changePlayState()
{
if(mp!=null)
{
if(mp.isPlaying())
mp.pause();
else
mp.start();
}
}
public void setOnVideoPreparedListener(IVideoPreparedListener iVideoPreparedListener) {
this.iVideoPreparedListener = iVideoPreparedListener;
}
}
IVideoDownloadListener
public interface IVideoDownloadListener {
public void onVideoDownloaded(Video video);
}
IVideoPreparedListener
public interface IVideoPreparedListener {
public void onVideoPrepared(Video video);
}
Why don't you add the custom video view in the layout file 'view_main' itself.
Check the visibility of the video view and play only if the view is visible.
public static boolean isViewVisible(View subView, View parentView) {
Rect scrollBounds = new Rect();
parentView.getHitRect(scrollBounds);
if (subView.getLocalVisibleRect(scrollBounds)) {
return true;
}
return false;
}
Code for checking visiblity. Call this in scroll state changed listener when the scroll state is idle.
Also you will have to use an AsyncTask for downloading videos ,but only download one video at a time or you might get out of memory error.
You should maintain a cache of videos locally by downloading them at backend and play one video at a time from local memory to keep the list scroll smooth.