web-dev-qa-db-ja.com

ViewPagerのスワイプでExoplayerを停止する

画像、ビデオ、オーディオなどのViewPagerファイルを表示している単一フラグメントインスタンスでMediaを使用しています。

ExoPlayerVideoファイルを処理するためにAudioを実装しました。そして、画像の場合はGlide

メモリリークを回避するために、_ItemViewerFragment.Java_で次のようなExoPlayerオブジェクトをリリースしています。

_ private void releasePlayer() {
        if (player != null) {
            player.release();
            player = null;
            trackSelector = null;
            simpleExoPlayerView.setPlayer(null);
        }
    }

    @Override
    public void onStart() {
        super.onStart();
        if (player == null && currentGalleryModel != null) {
            initializePlayer();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (player == null && currentGalleryModel != null) {
            initializePlayer();
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        releasePlayer();
    }

    @Override
    public void onStop() {
        super.onStop();
        releasePlayer();
    }
_

そしてonViewCreated()で私はこのようにビューを初期化しています:

_ @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        if (currentGalleryModel.isVideo() || currentGalleryModel.isAudio()) {

            simpleExoPlayerView.setVisibility(View.VISIBLE);
            imageView.setVisibility(View.GONE);

            initializePlayer();
        } else if (currentGalleryModel.isImage() || currentGalleryModel.isGif()) {
            simpleExoPlayerView.setVisibility(View.GONE);
            imageView.setVisibility(View.VISIBLE);


            Glide.with(this)
                    .load(currentGalleryModel.getFilePath())
                    .placeholder(Android.R.color.black)
                    .fitCenter()
                    .diskCacheStrategy(DiskCacheStrategy.NONE)
                    .into(imageView);

        }
    }
_

FragmentStatePagerAdapeterを使用しています。これはgetItemメソッドです:

_@Override
public Fragment getItem(int position) {
    return ItemViewerFragment.newInstance(mItems.get(position));
}
_

onPauseを最初にスワイプしたときにフラグメントのViewpagerを検出できません。 2回目のスワイプで、_video/audio_ファイルの再生が停止します。

アクティビティでは、_.addOnPageChangeListener_を追加してみました:

_@Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

     try {
        ((ItemViewerFragment)mAdapter.getItem(mPreviousPos)).imHiddenNow();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mPreviousPos = position;
    }
_

そして_ItemViewerFragment.Java_で:

_public void imHiddenNow(){
      releasePlayer();
    }
_

それでも_video/audio_は再生を続けます。

これが ビデオリンク スクリーンキャストへのリンクです。

デモプロジェクトGitHubリンク

15
Nilesh Deokar

HashMap内のフラグメントオブジェクトのPagerAdapterを維持するアプローチに従いました

  1. インターフェイスを宣言します:
interface FragmentLifecycle {
    void onPauseFragment()
}
  1. Fragmentにインターフェースを実装します。
public void onPauseFragment() {
    if (simpleExoPlayer != null){
        simpleExoPlayer.setPlayWhenReady(false);
    }
}
  1. すべてのフラグメントオブジェクトをHashMap<Integer,Fragment>に保存し、それぞれの位置をキーとして使用します。 PagerAdapter内でハッシュマップを宣言します。また、ハッシュマップからフラグメントオブジェクトにアクセスするための1つのgetterメソッドを宣言します。例えば.

    @Override
    public Fragment getItem(int position) {
        ItemViewerFragment fragment = ItemViewerFragment.newInstance(mItems.get(position));
        mFragments.put(position,fragment);
        return fragment;
    }
    

    public ItemViewerFragment getMapItem(int position){return mFragments.get(position); }

  2. viewPagerを宣言したアクティビティでは、1つの変数currentPositionを保持し、ViewPager.OnPageChangeListenerを実装します。

  3. onPageSelectedメソッド内では、

        @Override
        public void onPageSelected(int position) {
            if(mAdapter.getMapItem(currentPosition) != null) (mAdapter.getMapItem(currentPosition)).onPauseFragment();
            currentPosition = position;
        }
    
4
Nilesh Deokar

ページャアダプタのコードは次のとおりです。

 class ViewPagerAdapter extends FragmentPagerAdapter {
    private final List<Fragment> mFragmentList = new ArrayList<>();
    private final List<String> mFragmentTitleList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager manager) {
        super(manager);
    }

    @Override
    public Fragment getItem(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getCount() {
        return mFragmentList.size();
    }

    public void addFragment(Fragment fragment, String title) {
        mFragmentList.add(fragment);
        mFragmentTitleList.add(title);
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return mFragmentTitleList.get(position);
    }
}

スクロールリスナーは次のとおりです。

  viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
          //Stop media here.
        }

        @Override
        public void onPageSelected(int position) {
          //Save your previous position here.
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

メディアの場合、forループを使用して、すべてのフラグメントを一度にリストに追加し、効率を上げるためにこれを使用できます。

viewPager.setOffscreenPageLimit(3);

これにより、フラグメントの3つのインスタンスのみが使用可能になります。これで十分です。

単一のフラグメントを使用する場合は、次のようにすることをお勧めします。

 public MyFragment() {

}

//This is to send a file to the fragment if you need it.
public static MyFragment newInstance(File file) {
    MyFragment fragment = new MyFragment();
    Bundle bundle = new Bundle();
    bundle.putSerializable("file", file);
    fragment.setArguments(bundle);
    return fragment;
}

次に、onCreate of Fragmentで、次のようにファイルを取得できます。

File file;
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    file = getArguments().getSerializable("file");

}

次に、フラグメントを次のようにページャーに追加します。

 for (int i = 0; i < totalFiles; i++) {
            viewPagerAdapter.addFragment(MyFragment.newInstance(fileList.get(i));
        }

お役に立てれば。

3
Sarthak Gandhi

Exoplayerを使ってから1年以上経ちましたが、似たような問題に取り組みました。 APIが少し変更されていることに注意してください。次のコードを使用して、潜在的なソリューションを実装する方法を理解してください。動作しない場合はお知らせください。APIをさらに詳しく調べて、折り返しご連絡いたします。

解決策に来る:

private int mPlayerCurrentPosition;

private int getCurrentPlayerPosition() {
     return mExoPlayer.getCurrentPosition();
}

// call this from onPause
private void releaseExoplayer() {
     mPlayerCurrentPosition = getPlayerCurrentPosition();
     mExoPlayer.setPlayWhenReady(false);
     mExoPlayer.release(); // this will make the player object eligible for GC
}

private void resumePlaybackFromPreviousPosition(int prevPosition) {
    mExoPlayer.seekTo(mPlayerCurrentPosition );
}
2
Umer Farooq

問題は、ViewPagerでフラグメントの可視性が変更されたときに、onPauseonResumeが呼び出されないことです。解決策は、losingVisibilitygainVisibilityの2つの可視性イベントを追加することです。

なぜそれが素晴らしい解決策なのですか?

フレームワークがフラグメントキャッシュとライフサイクルを管理し続けるためです。メディアを一時停止および再開するために必要なコールバックをフラグメントに追加するだけです。

ステップバイステップ:

以下のコードは私のコードの説明にすぎません。 Step * .Java クラスをチェックして、完全な実装を確認してください。

  1. YourFragment.JavalosingVisibilityおよびgainVisibilityメソッドを作成します。

    public class YourFragment extends Fragment {
    
        /**
          * This method is only used by viewpager because the viewpager doesn't call onPause after
          * changing the fragment
          */
        public void losingVisibility() {
            // IMPLEMENT YOUR PAUSE CODE HERE
            savePlayerState();
            releasePlayer();
        }
    
        /**
          * This method is only used by viewpager because the viewpager doesn't call onPause after
          * changing the fragment
        */
        public void gainVisibility() {
            // IMPLEMENT YOUR RESUME CODE HERE
            loadVideo();
        }
    }
    
  2. YourActivity.Java で新しいページが選択されるたびに(losingVisibilitygainVisibilityonPageSelectedを呼び出します。

    mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        }
    
        @Override
        public void onPageSelected(int position) {
            YourFragment cachedFragmentLeaving = mYourPagerAdapter.getCachedItem(mCurrentItem);
            if (cachedFragmentLeaving != null) {
                cachedFragmentLeaving.losingVisibility();
            }
            mCurrentItem = position;
            YourFragment cachedFragmentEntering = mYourPagerAdapter.getCachedItem(mCurrentItem);
            if (cachedFragmentEntering != null) {
                cachedFragmentEntering.gainVisibility();
            }
        }
    
        @Override
        public void onPageScrollStateChanged(int state) {
        }
    });
    
  3. getCachedItemYourPagerAdapter.Java に追加します:

3番目のステップは、キャッシュされたフラグメントを取得するメソッドを追加することです。これを行うには、作成されたフラグメントへの参照をキャッシュし(instantiateItemをオーバーライド)、同じ参照を解放する(destroyItemをオーバーライドする)必要があります。

    public class YourPagerAdapter extends FragmentStatePagerAdapter {

            private SparseArray<YourFragment> mFragmentsHolded = new SparseArray<>();


        @NonNull
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Object fragment = super.instantiateItem(container, position);
            if(fragment instanceof StepFragment) {
                mFragmentsHolded.append(position, (StepFragment) fragment);
            }
            return fragment;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            mFragmentsHolded.delete(position);
            super.destroyItem(container, position, object);
        }

        public YourFragment getCachedItem(int position) {
            return mFragmentsHolded.get(position, null);
        }
    }
1

私はそれがとても遅いことを知っていますが、それが誰かに役立つことを願っています...
viewPagerはオフスクリーンフラグメントの開始を維持します..
つまり、次のようになります。
前のオフスクリーンフラグメント(開始)->表示フラグメント(動作中)->次のオフスクリーンフラグメント(開始)
解決策は、Fragment.setUserVisibleHint()をオーバーライドして、ビデオの再生/一時停止を処理できることです。

0
Seif E. Attia