如何只加载片段一次并保存其状态?

时间:2013-12-20 08:28:17

标签: android android-viewpager fragment

我有一个mainActivity,我从中调用片段列表。

现在,在此列表中,我有一个名为MyAccount的片段,它使用webservice显示帐户详细信息列表。

我想要的是我想加载myAccount Details只加载一次(第一次)片段,而不是每次都加载。(现在正在发生)。另外,我想在操作栏中设置一个刷新按钮,所以点击该刷新按钮/图像,将加载并显示帐户详细信息。

这是我的实现::

主要活动中的

getFragement()::

private List<Fragment> getFragments()
    {
        List<Fragment> fList = new ArrayList<Fragment>();


            fList.add(Fragment.instantiate(this,Fragment1.class.getName()));


            fList.add(Fragment.instantiate(this,Fragment2.class.getName()));



            fList.add(Fragment.instantiate(this,Fragment3.class.getName()));



        fList.add(MyAccountFragment.newInstance(this,"My Account"));
        fList.add(ReportFragment.newInstance(this,"Reports"));
        fList.add(SettingsListFragment.newInstance(this,"Settings"));

        return fList;
    }

调用适配器::

actionbartabmenuAdapter = new ActionBarTabMenuAdapter(getSupportFragmentManager(), fragments,this);
awesomePager.setAdapter(actionbartabmenuAdapter);

适配器::

private class ActionBarTabMenuAdapter extends FragmentPagerAdapter  {
        Activity context;
        Context ctx;
        private List<Fragment> fragments;

        public ActionBarTabMenuAdapter(FragmentManager fm, List<Fragment> fragments,Context ctx,)
        {
            super(fm);
            this.context=(Activity) ctx;

            this.fragments = fragments;
        }

        @Override
        public int getCount() 
        {
            return fragments.size();
        }
        @Override
        public Fragment getItem(int position) {

            System.out.println("position of fragment--"+position);
            return this.fragments.get(position);
        }
    }

onTabSelected / Reselected Method ::

@Override
    public void onTabReselected(Tab tabposition, FragmentTransaction fragmentposition) {
        System.out.println("Tab Reselected method");

    }

    @Override
    public void onTabSelected(Tab tabposition, FragmentTransaction fragmentposition) {

        awesomePager.setCurrentItem(tabposition.getPosition());
    }

    @Override
    public void onTabUnselected(Tab tabposition, FragmentTransaction fragmentposition) {
        System.out.println("Tab unselected method");

    }

MyAccountFragment ::

public class MyAccountFragment extends SherlockFragment{

    static MyAccountFragment f ;
    ListView list_subscriberInfo;
    ProgressDialog pd = null;
    MyAccountInfo myAccountInfo = new MyAccountInfo();
    private MyApplication appContext;
    static Context context;

    public static MyAccountFragment newInstance(Activity ctx,String string)
    {
        f = new MyAccountFragment();
        context=ctx;
        return f;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSherlockActivity().supportInvalidateOptionsMenu(); // now onCreateOptionsMenu(...) is called again
        this.setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) 
    {

        View v = inflater.inflate(R.layout.my_account, container, false);
        list_subscriberInfo = (ListView)v.findViewById(R.id.list_subscriberInfo);

        return v;
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) 
    {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.menu_new, menu);
    }

    public void onPrepareOptionsMenu(Menu menu) 
    {
        super.onPrepareOptionsMenu(menu);
    }
    public void setUserVisibleHint(boolean isVisibleToUser) 
    {
        super.setUserVisibleHint(isVisibleToUser);
        pd=new ProgressDialog(context);
        if (isVisibleToUser) 
        {
            pd =ProgressDialog.show(context,null, "Please Wait..", true);
            pd.setContentView(R.layout.progress);
            Thread thread = new Thread(getPersonalInfo);
            thread.start();
        }
        else
        {
            if(pd.isShowing())
            {
                pd.dismiss();
            }
        }
    }
}

请注意,在myAccountFragment中,我设置了setUserVisibleHint(),只有当此片段的可见性为真时才会取消帐户信息。

我知道我的问题的解决方案是setOffScreenLimit(),但我不知道在哪里/如何将其设置为我的实现。

但如何使用这两种方法只有在片段可见时才会显示我的帐户,并且每次都不会加载片段。仅在操作栏中单击刷新按钮时加载(第二次)。

希望我很清楚。

提前致谢...

修改::

应用LuksProg的逻辑......

MyContainerActivity ::

MyAccountFragment mSavedAccount;

public void cacheAccount(MyAccountFragment account) {
        mSavedAccount = account;
    }

    public Object getCachedAccount() {
        return mSavedAccount;
    }

MyAccountFragment ::

@Override
    public void onActivityCreated(Bundle savedInstanceState) 
    {
        super.onActivityCreated(savedInstanceState);
        containerActivity = (ButtonPayActivity) getActivity();
        pd=new ProgressDialog(context);

        if (containerActivity.getCachedAccount() != null)
        {
            //Do nothing
            if(pd.isShowing())
            {
                pd.dismiss();
            }
        }
        else
        {
            // the data isn't available so this must be a fresh start
            // start the thread, remember to use act.cacheAccount() when the thread finishes
            pd =ProgressDialog.show(context,null, "Please Wait..", true);
            pd.setContentView(R.layout.progress);
            Thread thread = new Thread(getPersonalInfo);
            thread.start();
        }
    }

编辑2 ::

在应用进度逻辑对话框后,我面临以下问题。

我所做的是显示并取消进度对话框,但在我移动到我的帐户的下一个标签后,我的应用程序崩溃...

awesomePager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {

            @Override
            public void onPageSelected(int position)
            {
                //supportInvalidateOptionsMenu();
                actionBar.setSelectedNavigationItem(position);
                 if (position == 4)
                 {
                        MyAccountFragment df = (MyAccountFragment) actionbartabmenuAdapter.getItem(position);
                    if (df.getThread() != null && df.getThread().isAlive()) 
                    {
                        df.showDialog();
                    }
                    else
                    {
                        df.cancelDialog();
                    }
                }
             }

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                super.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }

            @Override
            public void onPageScrollStateChanged(int state) {
                super.onPageScrollStateChanged(state);
            }
        });

myAccountFragment ::

@Override
    public void onActivityCreated(Bundle savedInstanceState) 
    {
        super.onActivityCreated(savedInstanceState);
        containerActivity = (ButtonPayActivity) getActivity();
        pd=new ProgressDialog(context);

        if (containerActivity.getCachedAccount() != null)
        {

            if(pd.isShowing())
            {
                pd.dismiss();
            }
        }
        else
        {

            pd =ProgressDialog.show(context,null, "Please Wait..", true);
            pd.setContentView(R.layout.progress);
            thread = new Thread(getPersonalInfo);
            thread.start();
        }
    }

    public void showDialog() 
    {
        if (pd != null) 
        {
            pd.show(); // the dialog will be started from the OnPageChangeListener only
        }
    }

    public void cancelDialog() 
    {
        if (pd != null) 
        {
            pd.dismiss();
        }
    }

    public Thread getThread() 
    {
        return thread;
    }

Logcat ::

12-24 20:31:20.076: E/AndroidRuntime(15596): FATAL EXCEPTION: main
12-24 20:31:20.076: E/AndroidRuntime(15596): java.lang.ClassCastException: com.example.app.home.ReportFragment
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.example.app.ContainerActivity$1.onPageSelected(ContainerActivity.java:151)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:438)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:405)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:386)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.example.app.ContainerActivity.onTabSelected(ContainerActivity)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.actionbarsherlock.internal.app.ActionBarImpl.selectTab(ActionBarImpl.java:531)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.actionbarsherlock.internal.app.ActionBarImpl$TabImpl.select(ActionBarImpl.java:912)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.actionbarsherlock.internal.widget.ScrollingTabContainerView$TabClickListener.onClick(ScrollingTabContainerView.java:504)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.view.View.performClick(View.java:2485)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.view.View$PerformClick.run(View.java:9080)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.os.Handler.handleCallback(Handler.java:587)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.os.Handler.dispatchMessage(Handler.java:92)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.os.Looper.loop(Looper.java:130)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at android.app.ActivityThread.main(ActivityThread.java:3683)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at java.lang.reflect.Method.invokeNative(Native Method)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at java.lang.reflect.Method.invoke(Method.java:507)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-24 20:31:20.076: E/AndroidRuntime(15596):    at dalvik.system.NativeStart.main(Native Method)

仍然存在问题,只是出于好奇,我在我的代码中应用以下内容但没有成功。 现在我在myAccount Fragment获得visibity之前获得了进度对话框,因此我将onActivityCreated()应用于setUserVisibleHint()并保留其余内容。

然后我的应用程序也崩溃了,我得到了跟踪日志..

Logcat ::

12-24 20:22:26.125: E/AndroidRuntime(14861): FATAL EXCEPTION: main
12-24 20:22:26.125: E/AndroidRuntime(14861): java.lang.NullPointerException
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.example.app.home.MyAccountFragment.setUserVisibleHint(MyAccountFragment.java:183)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.support.v4.app.FragmentPagerAdapter.instantiateItem(FragmentPagerAdapter.java:102)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.support.v4.view.ViewPager.addNewItem(ViewPager.java:649)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.support.v4.view.ViewPager.populate(ViewPager.java:783)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:433)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:405)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:386)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.example.app.ContainerActivity.onTabSelected(ContainerActivity.java:385)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.actionbarsherlock.internal.app.ActionBarImpl.selectTab(ActionBarImpl.java:531)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.actionbarsherlock.internal.app.ActionBarImpl$TabImpl.select(ActionBarImpl.java:912)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.actionbarsherlock.internal.widget.ScrollingTabContainerView$TabClickListener.onClick(ScrollingTabContainerView.java:504)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.view.View.performClick(View.java:2485)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.view.View$PerformClick.run(View.java:9080)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.os.Handler.handleCallback(Handler.java:587)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.os.Handler.dispatchMessage(Handler.java:92)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.os.Looper.loop(Looper.java:130)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at android.app.ActivityThread.main(ActivityThread.java:3683)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at java.lang.reflect.Method.invokeNative(Native Method)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at java.lang.reflect.Method.invoke(Method.java:507)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
12-24 20:22:26.125: E/AndroidRuntime(14861):    at dalvik.system.NativeStart.main(Native Method)

1 个答案:

答案 0 :(得分:2)

  

我想只加载一次(第一次)片段的myAccount Details   加载,而不是每次都加载。(现在正在发生)。

如果您只想加载一次数据,那么在第一次检索数据时,您需要将其缓存在活动/片段级别。因此,您需要在Activity中实现包含要设置和获取数据的片段的两个方法:

public void cacheAccount(Object account) {
    mSavedAccount = account;
}

public Object getCachedAccount() {
    return mSavedAccount;
}

然后在MyAccountFragment片段中,您将实现以下逻辑:

  • 使用其中一种生命周期方法来放置用于检索数据的代码(因此,请勿使用setUserVisibleHint()),例如onActivityCreated()
  • 在那里,您需要使用上述方法首先查看数据是否已经可用(如果片段先前已加载且数据已保存)。如果数据可用,则直接使用它,不要启动检索步骤,否则启动线程
  • 如果线程已启动,则完成后您需要设置数据,但也将其保存在活动中,以便将来可以使用MyAccountFragment片段

模拟实施:

// in the onActivityCreated() method:
// cast the activity
YourActivity act = (YourActivity) getActivity();
// check if the data isn't by any chance already available
if (act.getCachedAccount() != null) {
     // the data is already available so use it
} else {
     // the data isn't available so this must be a fresh start
     // start the thread, remember to use act.cacheAccount() when the thread finishes
}

此外,如果要在配置更改中保存数据,可能需要使用上述方法的片段,该片段设置为保留配置(为此调用setRetainInstance(true))。

  

此外,我想在操作栏中设置一个刷新按钮,依次点击   该刷新按钮/图像将加载帐户详细信息   显示。

这不应该是一个问题,只要你记得在检索线程完成时调用activity.cacheAccount(),这样你就可以将数据用于将来的使用。

  

我知道我的问题的解决方案是setOffScreenLimit(),但我不知道   知道在哪里/如何设置我的实现。

setOffScreenLimit()将增加适配器在内存中保留的片段数。根据你的碎片有多重,它可能会起作用,但一般来说你应该避免使用更大的值(在你的情况下,你基本上会把所有ViewPager的碎片保存在内存中。)

另外请注意,您在ViewPager的适配器的当前实现(传递预先构建的片段列表)将在某些情况下失败,因为您构建的片段列表将不会保留ViewPager实际使用的片段。

编辑 实现:

private SparseArray<Fragment> getFragments() {
     // I used a SparseArray but a list will also do
     SparseArray<Fragment> fList = new SparseArray<Fragment>();
     fList.put(Fragment.instantiate(this,Fragment1.class.getName()));
     fList.put(Fragment.instantiate(this,Fragment2.class.getName()));
     fList.put(Fragment.instantiate(this,Fragment3.class.getName()));
     fList.put(MyAccountFragment.newInstance(this,"My Account"));
     fList.put(ReportFragment.newInstance(this,"Reports"));
     fList.put(SettingsListFragment.newInstance(this,"Settings"));
     return fList;
}

// the adapter
private class ActionBarTabMenuAdapter extends FragmentPagerAdapter  {
        Activity context;
        Context ctx;
        private SparseArray<Fragment> fragments;

        public ActionBarTabMenuAdapter(FragmentManager fm, SparseArray<Fragment> fragments,Context ctx) {
            super(fm);
            this.context=(Activity) ctx;
            this.fragments = fragments;
        }

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

        @Override
        public Fragment getItem(int position) {
            System.out.println("position of fragment--"+position);
            return this.fragments.get(position);
        }

        @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        fragments.put(position, null);
        super.destroyItem(container, position, object);
    } 

        @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment f = (Fragment) super.instantiateItem(container, position);
        fragments.put(position, f);
        return f;
    }
    }

第二次编辑: 仅在您处于MyAccountFragment片段时显示对话框:

 mViewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int position) {
    if (position == 3) {
                MyAccountFragment df = (MyAccountFragment) adapter.getItem(position);
            if (df.getThread() != null && df.getThread().isAlive()) {
                df.showDialog();
            } else {
                df.cancelDialog();
            }
        }
     }

// rest of the methods
 }

这些方法是在MyAccountFragment

中实现的
  public void showDialog() {
        if (pd != null) {
            pd.show(); // the dialog will be started from the OnPageChangeListener only
        }
    }

    public void cancelDialog() {
        if (pd != null) {
            pd.dismiss(); // remeber to call this when the thread finishes
        }
    }

    public Thread getThread() {
        return mThread; // this will be the reference to the started thread
    }