ViewPager+Fragment取消预加载以及禁止滑动

2017-04-15 23:54:49

取消预加载

网上了解了很多取消预加载的方法,里面提到了使用一个viewpager的public方法setOffscreenPageLimit 经过查看源码以及验证发现该方法是管理Viewpager预加载的页数,最低也是默认为一页(例如ViewPager一共有4页,当前手机屏幕显示第一页,那么第二页已经被缓存了)。如果你想多缓存几页可以通过该方法进行设置;所以想要完全取消预加载(一页都不缓存,只加载当前页),通过这个方法是行不通的(通过其他的方法能不能行就不知道了)。

但是在细想之后发现我们取消预加载大多无非是取消掉我们放在这个fragment中的异步操作(我的是放在OnCreate或者OnCreateView方法里加载数据源的),那我们把这个异步操作的方法提取出来,然后在这个fragment的view每次显示的时候调用,不就达到了取消预加载的效果了。所以Fragment的public方法setUserVisibleHint (设置fragment的可见状态)恰好是我们所需要的,我们可以重写他然后在里面获取到fragment的显示状态实现我们的方法回调,这样就大功告成了,下面给出我写的几个重要类以及方法原型。

  • 以下是重写setUserVisibleHint方法的基础类,在用到Fragment的时候继承该类然后将你的异步加载操作方法放入相应的回调方法就能够实现需要的效果:

public abstract class BaseFragment extends Fragment {
    /** Fragment当前状态是否可见 */
    protected boolean isVisible;    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {        super.setUserVisibleHint(isVisibleToUser);        if(getUserVisibleHint()) {
            isVisible = true;
            onVisible();
        } else {
            isVisible = false;
            onInvisible();
        }
    }    /**
     * 可见时的回调方法
     */
    protected abstract void onVisible();    /**
     * 不可见时的回调方法
     */
    protected abstract void onInvisible();
}123456789101112131415161718192021222324252627
  • 以下是setOffscreenPageLimit方法原型(里面的常量DEFAULT_OFFSCREEN_PAGES为整形1):

/**
     * Set the number of pages that should be retained to either side of the
     * current page in the view hierarchy in an idle state. Pages beyond this
     * limit will be recreated from the adapter when needed.
     *
     * <p>This is offered as an optimization. If you know in advance the number
     * of pages you will need to support or have lazy-loading mechanisms in place
     * on your pages, tweaking this setting can have benefits in perceived smoothness
     * of paging animations and interaction. If you have a small number of pages (3-4)
     * that you can keep active all at once, less time will be spent in layout for
     * newly created view subtrees as the user pages back and forth.</p>
     *
     * <p>You should keep this limit low, especially if your pages have complex layouts.
     * This setting defaults to 1.</p>
     *
     * @param limit How many pages will be kept offscreen in an idle state.
     */
    public void setOffscreenPageLimit(int limit) {        if (limit < DEFAULT_OFFSCREEN_PAGES) {
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +
                    DEFAULT_OFFSCREEN_PAGES);
            limit = DEFAULT_OFFSCREEN_PAGES;
        }        if (limit != mOffscreenPageLimit) {
            mOffscreenPageLimit = limit;
            populate();
        }
    }12345678910111213141516171819202122232425262728
  • 以下是setUserVisibleHint方法的原型

/**
     * Set a hint to the system about whether this fragment's UI is currently visible
     * to the user. This hint defaults to true and is persistent across fragment instance
     * state save and restore.
     *
     * <p>An app may set this to false to indicate that the fragment's UI is
     * scrolled out of visibility or is otherwise not directly visible to the user.
     * This may be used by the system to prioritize operations such as fragment lifecycle updates
     * or loader ordering behavior.</p>
     *
     * @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
     *                        false if it is not.
     */
    public void setUserVisibleHint(boolean isVisibleToUser) {        if (!mUserVisibleHint && isVisibleToUser && mState < STARTED) {
            mFragmentManager.performPendingDeferredStart(this);
        }
        mUserVisibleHint = isVisibleToUser;
        mDeferStart = !isVisibleToUser;
    }1234567891011121314151617181920

小结一下:取消预加载不需要任何额外的ViewPager属性配置操作,只需要在构建类Fragment的时候继承BaseFragment实现两个抽象方法,然后将异步操作方法放入相应的回调方法即可。

禁止滑动

在布局中引用以下重写的ViewPager CustomViewPager 类,然后再调用其中的public方法setScanScroll 设置(如在Activity的onCreate方法中:

CustomViewPager viewPager = (CustomViewPager) findViewById(R.id.viewpager);viewPager.setScanScroll(false);12

)调用即可。 
以下给出重要的类以及重要注释。

public class CustomViewPager extends ViewPager {

    private boolean isCanScroll = true;    public CustomViewPager(Context context) {        super(context);
    }    public CustomViewPager(Context context, AttributeSet attrs) {        super(context, attrs);
    }    /**
     * 设置其是否能滑动换页
     * @param isCanScroll false 不能换页, true 可以滑动换页
     */
    public void setScanScroll(boolean isCanScroll) {        this.isCanScroll = isCanScroll;
    }    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {        return isCanScroll && super.onInterceptTouchEvent(ev);
    }    @Override
    public boolean onTouchEvent(MotionEvent ev) {        return isCanScroll && super.onTouchEvent(ev);

    }
}1234567891011121314151617181920212223242526272829303132

方法onInterceptTouchEvent API注释:

android.support.v4.view.ViewPager
public boolean onInterceptTouchEvent(@NotNull MotionEvent ev)
Description copied from class: ViewGroup Implement this method to intercept all touch screen motion events. This allows you to watch events as they are dispatched to your children, and take ownership of the current gesture at any point.

实现此方法可拦截所有触摸屏幕事件。这允许您监听事件传递给你的子类,并且在任何点取得当前手势的所有权。

Using this function takes some care, as it has a fairly complicated interaction with View.onTouchEvent(MotionEvent), and using it requires implementing that method as well as this one in the correct way. Events will be received in the following order:
You will receive the down event here.
The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.
For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
If you return true from here, you will not receive any following events: the target view will receive the same event but with the action MotionEvent.ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.
Overrides:
onInterceptTouchEvent in class ViewGroup
Parameters:
ev - The motion event being dispatched down the hierarchy.
Returns:
Return true to steal motion events from the children and have them dispatched to this ViewGroup through onTouchEvent(). The current target will receive an ACTION_CANCEL event, and no further messages will be delivered here.

从子类中拦截到移动事件并将事件传递到了ViewGroup则返回true


  • 2019-08-14 09:01:18

    linux下高并发服务器实现

    在做网络服务的时候tcp并发服务端程序的编写必不可少。tcp并发通常有几种固定的设计模式套路,他们各有优点,也各有应用之处。下面就简单的讨论下这几种模式的差异:

  • 2019-08-14 13:18:59

    Linux系统下CPU使用(load average)梳理

    在平时的运维工作中,当一台服务器的性能出现问题时,通常会去看当前的CPU使用情况,尤其是看下CPU的负载情况(load average)。对一般的系统来说,根据cpu数量去判断。比如有2颗cup的机器。如果平均负载始终在1.2以下,那么基本不会出现cpu不够用的情况。也就是Load平均要小于Cpu的数量。

  • 2019-08-14 14:27:35

    计算密集型和IO密集型

    在进行I/O操作的时候,是将任务交给DMA来处理,请求发出后CPU就不管了,在DMA处理完后通过中断通知CPU处理完成了。I/O操作消耗的cpu时间很少.

  • 2019-08-14 14:29:12

    浅谈nodejs和php

    现在,Web开发公司和开发人员可以选择多种技术栈来构建Web应用程序。早期网络发展,不同的技术被用于前端和后端开发。但是,随着Node.js的发布,布局发生了变化,因为它允许开发人员使用 JavaScript 编写后端代码。这最终催生了MEAN(MongoDB + Express +AngularJS + NodeJS )堆栈 web 开发框架,从前端到后端甚至是数据库(MongoDB -JSON)都使用 JavaScript。在 Node.js 之前,Web 开发通常是在 PHP 的帮助下完成的,因为它很容易与 HTML 集成,帮助开发人员立即构建动态网站。在这篇文章中,我们将比较 Node.js 和 PHP,看哪一个最适合当前的行业需求。

  • 2019-08-15 13:32:18

    Node.js是如何解决服务器高性能瓶颈问题的

    在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。

  • 2019-08-15 13:33:53

    nodejs的10个性能优化技巧

    在我接触JavaScript(无论浏览器还是NodeJS)的时间里,总是遇到有朋友有多线程的需求。而在NodeJS方面,有朋友甚至直接说到,NodeJS是单线程的,无法很好的利用多核CPU。那么我们在使用过程中,就要非常注意性能优化了

  • 2019-08-16 13:18:48

    使用ffmpeg进行ts切片并AES-128加密

    由于解密的key文件都是公开的,所以并不能算上完全加密,用户只要把你的key+m3u8里的ts切片文件全部下载,用ffmpeg还是能解,这时就要考虑url的key防止用户直接下载和盗链。 ​

  • 2019-08-18 22:22:54

    Error:error: unable to remove file: Permission denied

    JNI里写的C++增加了函数或修改了,如果此时是Debug模式下,而且还没退出程序,就出现这个Permission denied的提示。解决也很简单:就是退出App即可。如果退出无响应,直接拔usb,重新插上也可以

  • 2019-08-19 10:24:29

    浅析Express中的路由与应用模式

    Express是一个基于Node.js的轻量级web开发框架,具有体积小,使用灵活等特点。查看Express的源码,如果不计供使用的中间件,主体框架只有一千余行代码,非常简练。