Video is not getting paused in ViewPager - android

I m using viewpager and its adapter i m displaying image and video as per condition.
I don't have fragment because i m using PagerAdapter.
Code:
pager.setOnPageChangeListener(pageChangeListener);
pager.post(new Runnable() {
#Override
public void run() {
pageChangeListener.onPageSelected(pager.getCurrentItem());
}
});
}
ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrollStateChanged(int arg0) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
#Override
public void onPageSelected(int position) {
View view = mediaFullScreenImageAdapter.getActiveView(pager);
if (selectedPhotosByDate.get(position).getMessagetype().equalsIgnoreCase("VIDEO")) {
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
if (video_player.isPlaying()) {
Log.v("THISCALLEDD", "Y" + " : " + position);
video_player.pause();
}
}
}
};
#Nullable
public View getActiveView(final ViewPager viewPager) {
final PagerAdapter adapter = viewPager.getAdapter();
if (null == adapter || adapter.getCount() == 0 || viewPager.getChildCount() == 0) {
return null;
}
int position;
final int currentPosition = viewPager.getCurrentItem();
for (int i = 0; i < viewPager.getChildCount(); i++) {
final View child = viewPager.getChildAt(i);
final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) child.getLayoutParams();
if (layoutParams.isDecor) {
continue;
}
final Field positionField;
try {
positionField = ViewPager.LayoutParams.class.getDeclaredField("position");
positionField.setAccessible(true);
position = positionField.getInt(layoutParams);
} catch (NoSuchFieldException e) {
break;
} catch (IllegalAccessException e) {
break;
}
if (position == currentPosition) {
return child;
}
}
return null;
}
Update:
selectedPhotosByDate = appDatabase.chatMessagesDao().getMediaByGroupId(topicid, "Y");
if (selectedPhotosByDate.size() > 0 && selectedPhotosByDate != null) {
mediaFullScreenImageAdapter = new MediaFullScreenImageAdapter(MediaFullScreenSlideActivity.this, selectedPhotosByDate);
pager.setAdapter(mediaFullScreenImageAdapter);
for (int i = 0; i < selectedPhotosByDate.size(); i++) {
if (messageid == selectedPhotosByDate.get(i).getMessageId()) {
position = i;
break;
}
}
pager.setCurrentItem(position);
pager.setOffscreenPageLimit(selectedPhotosByDate.size());
}
I am able to get logcat value . But my video doesn't get pause.
If my video is playing and user swipe for other item playing video must be paused.
Advanced help would be appreciated!

Based on the documentation here, onPageSelected is called when a new page is selected. That means, the active view that you are trying to get using the currentItem from the ViewPager will return you the current selected item rather than the previously selected item. So your reference to video_player is also wrong and hence it is not working.
A simple way to do this is to have a variable currentPosition. Update it in onPageSelected but before updating, get its view and pause the video. This way whenever you access it, you will first get the previous index and then you will update it to the current index for the next time.

As per my understanding ,you want to pause previous video when user swipe in viewpager .
#Override
public void onPageSelected(int position) {
View view = mediaFullScreenImageAdapter.getActiveView(pager);
if (selectedPhotosByDate.get(position).getMessagetype().equalsIgnoreCase("VIDEO")) {
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
if (video_player.isPlaying()) {
Log.v("THISCALLEDD", "Y" + " : " + position);
video_player.pause();
}
}
}
you are getting view object of current active position ,but you want to pause video of (position - 1 ),you need to have view object of previous position .

Finally resolved the issue.
I moved this code
View view = mediaFullScreenImageAdapter.getActiveView(pager);
CustomVideoPlayer video_player = (CustomVideoPlayer) view.findViewById(R.id.video_player);
video_player.pause();
to onPageScrolled() method instead of onPageSelected() method.

This worked for me with a Youtube video playing as an embedded iFrame in a WebView:
viewPager.addOnPageChangeListener(object : SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
// NOTE: this workaround pauses any playing Youtube video in the WebView, if the video screen is being switched out.
// This works by getting the ViewPager#focusedChild, which will be the WebView if that screen is currently in focus,
// before the next selected ViewPager screen gets switched-to/loaded.
viewPager.focusedChild?.findViewById<WebView>(R.id.video_view)?.onPause()
// NOTE: we do a postDelay below, to ensure the WebView gets put back into its resume state, if it being switched to.
// This is delayed, so that this happens after the ViewPager screen with the WebView, has time to load it into place.
postDelayed({ viewPager.focusedChild?.findViewById<WebView>(R.id.video_view)?.onResume() }, 200)
}
})

Related

Change every image view resources inside listview with one click

I have a list view of songs with play and pause button in every row..
I can't have two pause Icon(two playing song) in my list view So I need to first reset all of them to play Icon then set the selected view to pause Icon..
How can I do this ? Or can you offer a better solution for this ?
This is my code :
In model class ( Product ) :
public int currentPosition= -1;
in Adapter:
public interface PlayPauseClick {
void playPauseOnClick(int position);
}
private PlayPauseClick callback;
public void setPlayPauseClickListener(PlayPauseClick listener) {
this.callback = listener;
}
.
.
.
holder.playPauseHive.setImageResource(product.getPlayPauseId());
holder.playPauseHive.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (callback != null) {
callback.playPauseOnClick(position);
if (position == product.currentPosition) {
product.setPlayPauseId(R.drawable.ic_pause);
//set the image to pause icon
}else{
//set the image to play icon
product.setPlayPauseId(R.drawable.ic_play);
}
notifyDataSetChanged();
}
}
});
my Callback inside my Activity:
#Override
public void playPauseOnClick(int position) {
final Product product = songList.get(position);
if(product.currentPosition == position){
product.currentPosition = -1; //pause the currently playing item
}else{
product.currentPosition = position; //play the item
}
this.adapter.notifyDataSetChanged();
}
For my case I use a variable to store the current playing item position. Let say
int x = -1; //-1 can indicate nothing was currently playing
So in the playPauseOnClick() you can do something like this
#Override
public void playPauseOnClick(int position) {
if(x == position){
x = -1; //pause the currently playing item
}else{
x = position; //play the item
}
this.adapter.notifyDataSetChanged();
}
The reason i remove product.setPlayPauseId() is because you really don't need them. You just need to set the play or pause icon based on your x varible which I created earlier. Do Something like this in your getView()
Product product = songList.get(position);
if (position == x) {
//set the image to pause icon
}else{
//set the image to play icon
}
So once you call adapter.notifyDataSetChanged() your adapter will do all the work for you. Whenever the x variable having the value -1 none of the icon will be display the pause icon, this can also make sure only one position will showing the pause icon as well.
Hope it help you.

ImageView Button Toggle inside listview

I have a List view of ringtones with a play image view in each row for each ringtone.
This is the view of it.
Now obviously when a user clicks on a play button it should switch to pause button.
Now I have a problem :
I click on a play button and it will turn into pause button, but in the meantime when I click on a play button from another row it takes two clicks until the second one turns into the pause button.
This is my code :
Adapter
Product product = (Product) mDataItems.get(position);
holder.playPause=(ImageView)v.findViewById(R.id.playPause);
holder.playPause.setImageResource(product.getPlayPauseId());
holder.playPause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (callback != null) {
callback.playPauseOnClick(position);
}
}
});
Activity
#Override
public void playPauseOnClick(int position) {
final Product product = productList.get(position);
if (paused) {
product.setPlayPauseId(R.drawable.ic_pause);
paused=false;
}else {
product.setPlayPauseId(R.drawable.ic_play);
paused = true;
}
adapter.notifyDataSetChanged();
};
I am already guessing the problem is in my condition
if(paused){
}
I would be grateful if you can offer me a better logic
you are using one pause field for all the rows so the first tap changes its status to true the second tap on the other row changes it to false and the sets the drawable
product.setPlayPauseId(R.drawable.ic_pause)
on the first row and the third tap works correctly.
you can define pause field for every product and inside if clause check the products pause filed
if(product.pause){
...
product.paused = false;
}else{
product.paused = true;
}
Here's a slimier case in this what i did is i stream audio ringtones from url in a RecyclerView .. make a class variable as
private int oldPosition = -1; , with this variable you'll keep track of which row is currently playing audio in RecyclerView
#Override
public void onRecyclerViewChildItemClick(BaseRecyclerViewHolder holder, int resourceId) {
super.onRecyclerViewChildItemClick(holder, resourceId);
switch (resourceId) {
case R.id.media_play_container:
int position = holder.getAdapterPosition();
if (oldPosition != -1)
resetResources();
if (oldPosition == position) {
resetResources();
oldPosition = -1;
return;
}
updateViewAtPosition(false, false); // update old selected view
oldPosition = position; // update position
BaseRecyclerViewAdapter adapter = (BaseRecyclerViewAdapter) getRecyclerView().getAdapter();
AudioItem item = (AudioItem) adapter.getItemAt(oldPosition);
String url = item.getAudioPreviewUrl();
// if url is valid show progress and play
if (AppUtils.ifNotNullEmpty(url)) {
updateViewAtPosition(true, false);
playRingtone(url);
}
break;
case R.id.iv_media_favorite:
break;
}
}
This method updates old row that is playing
updateViewAtPosition(false, false);
private void updateViewAtPosition(boolean isLoading, boolean isPlaying) {
RecyclerView recyclerView = getRecyclerView();
if (recyclerView == null || oldPosition == -1)
return;
BaseRecyclerViewAdapter adapter = (BaseRecyclerViewAdapter) recyclerView.getAdapter();
if (adapter == null)
return;
AudioItem item = (AudioItem) adapter.getItemAt(oldPosition);
item.setPlaying(isPlaying);
item.setLoading(isLoading);
adapter.update(oldPosition, item);
adapter.notifyItemChanged(oldPosition);
}
// reset media player
resetResources();
private void resetResources() {
resetMediaPlayer();
resetViewResources();
}
private void resetMediaPlayer() {
try {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.reset();
}
} catch (Exception e) {
Logger.caughtException(e);
}
}
private void resetViewResources() {
if (oldPosition == -1)
return;
updateViewAtPosition(false, false);
}

RecyclerView changing position randomly while scrolling

I have made a chat app where I have used a RecyclerView. Messages can be either text messages or audio messages. Everything is working fine except when I change the timer text on the TextView (for audio player layout I have made) , of how long has the song been played. I do this in a Runnable. But when I scroll the RecyclerView, the timer TextView changes text at random position.
Here is how I am changing the TextView text:
public void updateTimer(final int position) {
View view = mRecyclerViewChat.getLayoutManager().findViewByPosition(position);
timer = (TextView) view.findViewById(R.id.timer);
r = new Runnable() {
public void run() {
int currentDuration;
if (player.isPlaying()) {
currentDuration = player.getCurrentPosition();
timer.setText("" + milliSecondsToTimer((long) currentDuration));
timer.postDelayed(this, 1000);
} else {
timer.removeCallbacks(this);
}
}
};
timer.post(r);
}
Here position is the position value I am getting from the onBindViewHolder.
EDIT
Here is the onBindViewHolder
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (TextUtils.equals(mChats.get(position).senderUid,
FirebaseAuth.getInstance().getCurrentUser().getUid())) {
if (mChats.get(position).mediaUrlLocal == null) {
configureMyChatViewHolder((MyChatViewHolder) holder, position);
} else {
configureMyChatMediaViewHolder((MyChatMediaViewHolder) holder, position);
}
} else {
if (mChats.get(position).mediaUrlLocal == null) {
configureOtherChatViewHolder((OtherChatViewHolder) holder, position);
} else {
configureOtherChatMediaViewHolder((OtherChatMediaViewHolder) holder, position);
}
}
}
and here is the playMedia method which is called from configureMyChatMediaViewHolder method:
private void playMyMedia(final MyChatMediaViewHolder myChatViewHolder, final Chat chat, final int position) {
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(chat.mediaUrlLocal);
String duration =
metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
long dur = Long.parseLong(duration);
String seconds = String.valueOf((dur % 60000) / 1000);
String minutes = String.valueOf(dur / 60000);
String out = minutes + ":" + seconds;
myChatViewHolder.timer.setText(out);
if (chat.isPlay) {
myChatViewHolder.play.setVisibility(View.GONE);
myChatViewHolder.pause.setVisibility(View.VISIBLE);
} else {
myChatViewHolder.play.setVisibility(View.VISIBLE);
myChatViewHolder.pause.setVisibility(View.GONE);
}
myChatViewHolder.play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chat.isPlay = !chat.isPlay;
if (previousChat != position && previousChat != -1) {
previousChatObj = mChats.get(previousChat);
}
previousChat = position;
myChatViewHolder.play.setVisibility(View.GONE);
myChatViewHolder.pause.setVisibility(View.VISIBLE);
callback.onPlayClickListener(chat, previousChatObj, position);
}
});
myChatViewHolder.pause.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
chat.isPlay = !chat.isPlay;
myChatViewHolder.play.setVisibility(View.VISIBLE);
myChatViewHolder.pause.setVisibility(View.GONE);
callback.onPauseClickListener(chat, position);
}
});
}
I have only one media player instance in the fragment from which the adapter for chat is set.
Recycler view is re-using the views that are not currently visible. So if your audio player starts updating one Text View , when you scroll that textview is the same reference but with different text ( song ), but your runnable instance is still active and doing its job to update the Text View with same reference.
You should create a custom Runnable class which
will hold a position value and will be only responsible for the
TextView it should update.
Other approach ( less efficient ) is to use ListView and not to re-use the cells to create new one for each item. This will cause performance issues
If you can send some code i would like to help you out.
*** EDITED ****
Here is some code part that can make things more clear
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.songDurationView.setTag(position);
//TODO: implement some more logic here and start the MusicSongRunnable
}
class MusicSongRunnable implements Runnable {
int positionOfSong;
TextView textView;
public MusicSongRunnable(int positionOfSong, TextView textView) {
this.positionOfSong = positionOfSong;
this.textView = textView;
}
#Override
public void run() {
if (player.isPlaying() && positionOfSong == textView.getTag()) {
//TODO: update the song;
}
}
It is not clear where you call updateTimer, but I assume that you call it from within callback.onPlayClickListener(..) and callback.onPauseClickListener(..).
First, do not pass it the position you've got as a parameter in click listeners, but as documentation states you should use ViewHolder.getAdapterPosition() method. Note, that when you use the value of the position you should also check that it is different from RecuclerView.NO_POSITION each time and only then use it. Make your position parameter not final in all methods. It will prevent you from making mistakes. Each time you want to use position in click listeners use myChatViewHolder.getAdapterPosition()
Second, since you cache position value in the Runnable anyway, this is probably not enough. So you should pass myChatViewHolder.timer as a parameter to updateTimer and get rid of first two lines. In the end you call updateTimer like this:
updateTimer(myChatViewHolder.timer);
and your 'updateTimer' now is:
public void updateTimer(final TextView timer) {
r = new Runnable() {
public void run() {
int currentDuration;
if (player.isPlaying()) {
currentDuration = player.getCurrentPosition();
timer.setText("" + milliSecondsToTimer((long) currentDuration));
timer.postDelayed(this, 1000);
} else {
timer.removeCallbacks(this);
}
}
};
timer.post(r);
}
More from the documentation on this matter:
RecyclerView will not call onBindViewHolder() method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method and should not keep a copy of it.

MainActivity Get Position Of Item From PagerAdapter [duplicate]

I want to know the current page position of the ViewPager. I create an adapter and set this adapter to the ViewPager. Now I want to know the current page number or position of the current view, because I want to start some extra events on that particular page.
I used viewPager.setCurrentItem(1); for setting the first item.
Is there a similar method for getting the current page?
in the latest packages you can also use
vp.getCurrentItem()
or
vp is the viewPager ,
pageListener = new PageListener();
vp.setOnPageChangeListener(pageListener);
you have to put a page change listener for your viewPager. There is no method on viewPager to get the current page.
private int currentPage;
private static class PageListener extends SimpleOnPageChangeListener{
public void onPageSelected(int position) {
Log.i(TAG, "page selected " + position);
currentPage = position;
}
}
There is a method object_of_ViewPager.getCurrentItem() which returns the position of currently Viewed page of view pager
If you only want the position, vp.getCurrentItem() will give it to you, no need to apply the onPageChangeListener() for that purpose alone.
You will figure out that setOnPageChangeListener is deprecated, use addOnPageChangeListener, as below:
ViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
if(position == 1){ // if you want the second page, for example
//Your code here
}
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
For this problem Onpagechange listener is the best one But it will also have one small mistake that is it will not detect the starting time time of 0th position Once you will change the page it will starts to detect the Page selected position...For this problem I fount the easiest solution
1.You have to maintain the selected position value then use it....
2. Case 1: At the starting of the position is always Zero....
Case 2: Suppose if you set the current item means you will set that value into maintain position
3.Then do your action with the use of that maintain in your activity...
Public int maintain=0;
myViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int i, float v, int i2) {
//Toast.makeText(MyActivity.this, i+" Is Selected "+data.size(), Toast.LENGTH_SHORT).show();
}
#Override
public void onPageSelected( int i) {
// here you will get the position of selected page
maintain = i;
}
#Override
public void onPageScrollStateChanged(int i) {
}
});
updateButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MyActivity.this, i+" Is Selected "+data.size(), Toast.LENGTH_SHORT).show();
data.set(maintain, "Replaced "+maintain);
myViewPager.getAdapter().notifyDataSetChanged();
}
});
getCurrentItem(), doesn't actually give the right position for the first and the last page I fixed it adding this code:
public void CalcPostion() {
current = viewPager.getCurrentItem();
if ((last == current) && (current != 1) && (current != 0)) {
current = current + 1;
viewPager.setCurrentItem(current);
}
if ((last == 1) && (current == 1)) {
last = 0;
current = 0;
}
display();
last = current;
}
The setOnPageChangeListener() method is deprecated. Use
addOnPageChangeListener(OnPageChangeListener) instead.
You can use OnPageChangeListener and getting the position inside onPageSelected() method, this is an example:
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
#Override
public void onPageSelected(int position) {
Log.d(TAG, "my position is : " + position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
Or just use getCurrentItem() to get the real position:
viewPager.getCurrentItem();
There is no any method getCurrentItem() in viewpager.i already checked the API

On touch listener and update other row item in recyclerView

Hi i have recyclerView row item consists of a play Button(Which change to stop and Play as toggle) and a play seek bar and TextView.
The each row plays different audios .
When i click on play button of respective row i am able to stop the other row audio ..
Addressing to the problem ..
When i am playing a audio of a respective row, the button of earlier row has to stow a play symbol (in the sense it has to change the state ) please help me how to update the other rows of recyclerView when the other item is clicked
#Override
public void onBindViewHolder(final ViewHolder holder, final int i) {
if (holder.viewType == ROW_TYPE){
// holder.play_button.setImageResource(R.drawable.play_button);
if(i == selected_item){
}
else {
// holder.play_button.setImageResource();
}
JSONObject obj;
String mp3_url = null, caption = null, thumbnail_url = null;
try {
obj = voicesArray.getJSONObject(i);
mp3_url = obj.getString("mp3_url");
caption = obj.getString("caption");
thumbnail_url = obj.getString("thumbnail_url");
} catch (JSONException e) {
e.printStackTrace();
}
holder.list_text.setText(caption);
imageLoader.DisplayImage(thumbnail_url, holder.list_image);
final String finalMp3_url = mp3_url;
holder.play_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
selected_item = i;
int ii = holder.getOldPosition();
// holder.play_button.setImageResource();
// updateItem(ii);
if(player != null){
player.reset();
holder.play_button.setImageResource(R.drawable.play_button);
myAudioPlay(holder, finalMp3_url);
}
else {
myAudioPlay(holder,finalMp3_url);
/*if (player == null) {
player = new MediaPlayer();
playAudiFile(finalMp3_url);
holder.play_button.setImageResource(R.drawable.pause_button);
} else if (player.isPlaying()) {
holder.play_button.setImageResource(R.drawable.play_button);
player.stop();
Log.d("player", "" + player);
player.reset();
} else {
holder.play_button.setImageResource(R.drawable.pause_button);
playAudiFile(finalMp3_url);
}*/
}
}
});
}
}
Apparently the purpose of a recyclerView is to recycle the views to minimize memory usage required for rendering view so setting an image in the view is not an apt solution,Their are many solutions for your problem the One i would pick(Pseudo code) is given below
Step 1. Create a Boolean value in your model class
bool isPlay=true;
Step 2. When you are playing an audio loop through your Model for the recycler adapter and set the value for isPlay accourdingly
for(object obj in listOfModels)
if(obj.Id!=idOfthePlayingView)
obj.isPlay=false;
Then notify your adapter
yourRecyclerAdapterObject.notifyDatasetChanged()

Categories

Resources