如何处理Fragment中的网络调用

时间:2014-10-16 08:48:11

标签: android

我有以下情况:

我有Activity,其中有ViewPager,我有4 Fragments;

开头的ViewPager包含片段A

当用户在ViewPager 片段B 上滑动进入ViewPager,然后片段C 片段D ......等...

现在,只要FragmentPagerAdapter被实例化,就会创建至少2个片段。

这带来了两个问题:

  1. 每个Fragment都需要执行网络调用,但我不想做不必要的调用(我不想为片段B进行网络调用,如果用户从不切换到片段B );
  2. 类似于1.),我需要在片段执行网络调用时显示ProgessDialog,但如果用户从未访问过片段,我不想显示片段B中的对话框...
  3. 请在这种情况下使用哪种模式?

    活动

    public class PagerActivity extends ActionBarActivity {
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.viewpager_layout);
    
    ViewPager pager=(ViewPager)findViewById(R.id.pager);
    TabPageIndicator tabs=(TabPageIndicator)findViewById(R.id.titles);
    
    pager.setAdapter(buildAdapter());
    tabs.setViewPager(pager);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }
    }
    

    FragmentPagerAdapter

    public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
    
    
    @Override
    public int getCount() {
        return (4);
    }
    
    @Override
    public Fragment getItem(int position) {
    
    
        if (position == 1) {
            if (dashbardFragment == null)
                dashbardFragment = DashBoardFragment.newInstance(position);
            return dashbardFragment;
        }
        if (position == 0) {
            if (listOfParticipantFragment == null)
                listOfParticipantFragment = ListOfParicipantsFragment
                .newInstance(position);
            return listOfParticipantFragment;
        }
    
    }
    

    1片段

    public class ListOfParicipantsFragment extends Fragment {
    
    public static ListOfParicipantsFragment newInstance(int position) {
        ListOfParicipantsFragment frag = new ListOfParicipantsFragment();
        return (frag);
    }
    
    public static String getTitle(Context ctxt, int position) {
        return myApplication.getContext().getResources().getString(R.string.list_of_participants_fragment_title);
    }
    
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View result = inflater.inflate(R.layout.guest_list_fragment_layout,
                container, false);
    
        return (result);
    }
    

7 个答案:

答案 0 :(得分:7)

在下面的每个fragment override方法中尝试使用此功能,并在可见时调用您的函数:

@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
    super.setUserVisibleHint(isVisibleToUser);
    if(isVisible()){
        if(isVisibleToUser){
            Log.d("MyTag","My Fragment is visible");
        }else{
            Log.d("MyTag","My Fragment is not visible");
        }
    }
}

修改

注意:仅在使用FragmentPagerAdapterFragmentStatePagerAdapter

时才有用

答案 1 :(得分:1)

基本上你想要做的是,当你滑动时,找到当前正在查看的片段。然后,进行网络通话。

当用户滑动到新页面时,您可以利用ViewPager侦听器收到通知。文档:http://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html#onPageSelected(int)

这将为您提供View的位置。但我假设你想要的是实际的片段,这有点棘手。

但是,这已经在这里得到了回答:Is it possible to access the current Fragment being viewed by a ViewPager?

希望有所帮助

答案 2 :(得分:1)

让我向您介绍我的想法:

  • getCurrentItem()
    ViewPager
  • 的方法
  • getItem(int position)
    方法FragmentPagerAdapter返回与指定位置关联的片段。

您可以定义一个包含网络I / O方法的接口,如

public Interface INetworkOnFragment{
 void handle(){
         //...
           }  
}

在片段上实现它并处理自己的业务逻辑(网络调用)。

在主Activity中,在ViewPager对象上设置ViewPager.OnPageChangeListener,如下所示:

    pager.setOnPageChangeListener(new ViewPager.OnPageChangeListener(){
public void onPageScrollStateChanged(int state){
//donothing
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
//donothing
}
public void onPageSelected(int position){
       INetworkOnFragment interface =(INetworkOnFragment) (pager.getAdapter().getItem(position));//get the current fragment and call handle method on it,dont need to care about whichever fragment it is . 
interface.handle()
}
});

最重要的是onPageSelected(int position),在回调中它获取当前片段和调用句柄方法,不需要关心它是哪个片段。

请记住,handle方法在Activity中调用,而不是在片段中调用。所有网络调用都是Interface的实现,这样可以轻松处理Activity。

答案 3 :(得分:1)

从我的回答here

中查看解决方案

1)创建LifecycleManager界面界面将有两种方法(onPauseFragmentonResumeFragment),每个ViewPager的片段将实现它 2)让每个Fragment实现接口
3)在每个片段中实现接口方法 - 在AsyncTask中开始onResumeFragment 4)在ViewPager页面更改时调用界面方法您可以在OnPageChangeListener上设置ViewPager并在每次ViewPager显示另一页时进行回调 5)实施OnPageChangeListener以调用您的自定义生命周期方法

答案 4 :(得分:1)

为FragmentStatePagerAdapter的view方法创建一个页面,当片段进入视图时,该方法调用片段上的方法。

在片段中实现OnPageIntoView接口。

public class SomethingDifferent extends Fragment implements OnPageIntoView {
...
/*
 * Called when this page comes into view
 * 
 * @see com.gosylvester.bestrides.SettingFragmentPagerSupport.MyAdapter.
 * OnPageIntoView#onPageIntoView()
 */
@Override
public void onPageIntoView() {
    // this is just some random example code
    // that does some heavy lifting it only runs when the fragment
    // frist comes into view
    if (fragmentActivity != null) {
        if (lrc == null) {
            lrc = new ClientServiceLocationRecorder(
                    new WeakReference<Context>(
                            fragmentActivity.getApplicationContext()),
                    lrcCallback);
        }

        // get a status message from the location recorder
        lrc.sndMessageToLocationRecorder(ServiceLocationRecorder.MSG_RECORD_STATUS);
    }
}

创建自定义FragmentStatePagerAdapter覆盖setPrimaryItem方法,如果对象可以强制转换为接口,则只通过接口调用一次。

public static class MyAdapter extends FragmentStatePagerAdapter {

    public interface OnPageIntoView {
        public void onPageIntoView();
    }

    private Fragment mCurrentFragment;

    //bonus method to get the current fragment
    public Fragment getCurrentFragment() {
        return mCurrentFragment;
    }

    static int lastPosition = -1;

    @Override
    public void setPrimaryItem(ViewGroup container, int position,
            Object object) {
        //quickly determine if the primary item has changed
        //and one time only call through interface
        if (position != lastPosition) {
            lastPosition = position;
            //determine if this is fragment it should be but lets avoid 
            //class cast exceptions
            if (Fragment.class.isAssignableFrom(object.getClass())) {
                mCurrentFragment = ((Fragment) object);
                //determine if the onPageIntoView interface has
                //been implemented in the fragment
                //if so call the onPageIntoView
                if (OnPageIntoView.class.isAssignableFrom(mCurrentFragment
                        .getClass())) {
                    ((OnPageIntoView) mCurrentFragment).onPageIntoView();
                }
            }
        }
        super.setPrimaryItem(container, position, object);
    }
}

答案 5 :(得分:0)

对我来说似乎很容易,你需要的是Fragments onResume() method。只有当您的片段 VISIBLE 给用户时才会调用此方法。

您可以在此处添加逻辑以启动网络呼叫。 It guarantees that your fragment is in visible mode

请参阅

enter image description here

但是,您可以使用 LoaderManager AsyncTaskLoader 模式优化网络调用逻辑。

装载机负责屏幕方向更改&amp;他们缓存数据。因此,对于相同的操作,网络调用不会启动两次。

来自Android文档

  

在Android 3.0中引入,加载器可以轻松异步加载   活动或片段中的数据。装载机具有以下特点:

They are available to every Activity and Fragment.
They provide asynchronous loading of data.
They monitor the source of their data and deliver new results 
     

当内容发生变化时。       它们会自动重新连接到最后一个加载器的光标   在配置更改后重新创建。   因此,他们不需要重新查询他们的数据。

您可以使用任何异步HTTP 库进行网络调用,例如 Retrofit

我找到了AsyncTaskLoader&amp;的一个教程。 LoaderManager @ this link,下面是教程中的一些引用

  

装载机不是小事,所以为什么要先使用它们呢?好吧,在   大多数情况下,你会在你曾经去过的相同场景中使用它们   使用AsyncTasks;事实上,一些加载器子类扩展了AsyncTask。   就像AsyncTasks用于执行任何长时间运行的操作一样   将绑定用户线程并最终抛出可怕的   应用程序无响应(ANR),加载器以相同的方式执行   有着同样的目的。主要区别是装载机是专业的   用于加载数据。因此,装载机提供了许多效率和   便利性。

答案 6 :(得分:0)

@Andrew Carl提供了好主意。我也在我的项目中使用类似的方法。我认为这更为普遍。

创建一个界面:

public interface ViewPagerFragment {
    void onSelected();

    void onDeselected();
}

这个共同帮手:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;

public class ViewPagerHelper implements ViewPager.OnPageChangeListener {
    private final FragmentManager mFragmentManager;
    private final ViewPager mViewPager;
    private int mSelectedPage;

    public ViewPagerHelper(FragmentManager fragmentManager, ViewPager viewPager) {
        mFragmentManager = fragmentManager;
        mViewPager = viewPager;
        mSelectedPage = -1;
    }

    @Override
    public void onPageSelected(int position) {
        Fragment previous = findViewPagerChildFragment(mFragmentManager, mViewPager, mSelectedPage);
        if (previous instanceof ViewPagerFragment) {
            ((ViewPagerFragment) previous).onDeselected();
        }

        Fragment current = findViewPagerChildFragment(mFragmentManager, mViewPager, position);
        if (current instanceof ViewPagerFragment) {
            ((ViewPagerFragment) current).onSelected();
        }

        mSelectedPage = position;
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        // empty
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        // empty
    }

    public static Fragment findViewPagerChildFragment(FragmentManager manager, ViewPager pager, int position) {
        if (pager == null) {
            return null;
        }

        String tag = "android:switcher:" + pager.getId() + ":" + position;
        return manager.findFragmentByTag(tag);
    }
}

现在您可以将它们用于任何目的:

片段:

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;

public class MyFragment extends Fragment implements ViewPagerFragment {
    private boolean mSelected;

    public static MyFragment newInstance(int position) {
        Bundle args = new Bundle();
        args.putInt("position", position);

        MyFragment result = new MyFragment();
        result.setArguments(args);
        return result;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        TextView result = new TextView(inflater.getContext());
        result.setText("Position: " + getPosition());
        return result;
    }

    private int getPosition() {
        return getArguments().getInt("position");
    }

    @Override
    public void onSelected() {
        mSelected = true;
        start();
    }

    @Override
    public void onDeselected() {
        mSelected = false;
    }

    private void start() {
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                Activity activity = getActivity();
                if (activity == null) {
                    return;
                }

                if (!mSelected) {
                    Toast.makeText(activity, "Fragment #" + getPosition() + " stopped", Toast.LENGTH_SHORT).show();
                    return;
                }

                TextView textView = (TextView) activity.findViewById(R.id.text);
                if (textView != null) {
                    textView.setText("Fragment #" + getPosition() + " works: " + System.nanoTime() % 10000);
                }

                handler.postDelayed(this, 150);
            }
        }, 150);
    }
}

的活动:

import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.support.v7.app.ActionBarActivity;

public class MainActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager);
        viewPager.setOnPageChangeListener(new ViewPagerHelper(getSupportFragmentManager(), viewPager));
        viewPager.setAdapter(new MyAdapter(getSupportFragmentManager()));
    }
}

适配器:

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class MyAdapter extends FragmentPagerAdapter {
    public MyAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return MyFragment.newInstance(position);
    }

    @Override
    public int getCount() {
        return 42;
    }
}

检查github上的完整演示。