简体   繁体   English

ViewPager 和更新片段

[英]ViewPager and updating Fragments

In my app's activity, I have a ViewPager implementation which loads a Map fragment (FragmentA) on launch and then there are 2 other fragments showing content based on the latitude and longitude selected in FragmentA.在我的应用程序的活动中,我有一个 ViewPager 实现,它在启动时加载一个地图片段 (FragmentA),然后还有 2 个其他片段显示基于 FragmentA 中选择的纬度和经度的内容。

I am unable to get the behavior where upon launch, the latitude/longitude from FragmentA, should be provided to the 2 other fragments and continue to provide whenever user clicks on the map in FragmentA.我无法获得这样的行为:在启动时,FragmentA 的纬度/经度应提供给其他 2 个片段,并在用户单击 FragmentA 中的地图时继续提供。

Here are the approaches I tried:以下是我尝试过的方法:

  1. using interface to communicate between fragment -> activity -> fragment ( sticking with this approach )使用接口在片段 -> 活动 -> 片段之间进行通信(坚持这种方法
  2. using bundle to pass information between fragments when the fragments are getting initialized当片段被初始化时,使用 bundle 在片段之间传递信息

However, neither of these approaches have worked for me.但是,这两种方法都不适合我。

MyActivity.java //update to show Daniel's suggestion MyActivity.java //更新以显示丹尼尔的建议

public class MyDemoActivity extends FragmentActivity
                implements FragmentA.OnFragmentInteractionListener,
                    FragmentB.OnFragmentInteractionListener, IUserLatLong  {

    private MyPagerAdapter pagerAdapter;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.map_in_pager_demo);

        ViewPager mPager = (ViewPager) findViewById(R.id.pager);
        pagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), getApplicationContext());
        mPager.setAdapter(pagerAdapter);

        //always start w/ Maps View, FragmentA
        mPager.setCurrentItem(1);

        //
        mPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
           @Override
           public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            //do something
           }

           @Override
           public void onPageSelected(int position) {
             // do this instead of calling, notifyDataSetChanged()
            Fragment frag = pagerAdapter.fragments[position];
            if (frag != null && frag instanceof FragmentB) {
                Log.i(TAG, "::FragmentB:: Fetching data from Activity");
                //here is my confusion, calling FragmentB with latlong from FragmentA
                ((FragmentB) frag).setNewLatLong(newUserLatLong);
            }
           }

           @Override
           public void onPageScrollStateChanged(int state) {
             //do something
           }
       });
    }

    @Override
    public void onFragmentInteraction(Uri uri) {
        //do something
    }

    @Override
    public void makeUseOfNewLocation(UserLatLong userLatLong) {
       newUserLatLong = userLatLong;
       Log.i(TAG, "LatLong from FragmentA is: " + newUserLatLong.getLat()
                + " and long is: " + newUserLatLong.getLng());
    }

/**
 * Used for fetching data from activity
 * @return
 */
public UserLatLong getLLFromActivity() {
      if(newUserLatLong == null) {
        Log.e(TAG, "LatLong from FragmentA came up empty");
      } else {

        Log.i(TAG, "LatLong from FragmentA IS NOT empty: " + newUserLatLong.getLat()
                + " and long is: " + newUserLatLong.getLng());
      }
      return newUserLatLong;
    }

}

MyPagerAdapter.java MyPagerAdapter.java

public class MyPagerAdapter extends FragmentPagerAdapter {

    private static int NUM_ITEMS = 3;
    public MyPagerAdapter(FragmentManager fm, Context context) {
       super(fm);
       this.context = context; 
    }

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

    // not sure if this is really helping
    @Override
    public int getItemPosition(Object object) {
        // POSITION_NONE makes it possible to reload the PagerAdapter
        return POSITION_NONE;
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                //uses location from FragmentA to get data
                return new FragmentB();
            case 1:
                //loads map and gets location
                return new FragmentA();
            case 2:
                //uses location from FragmentA to get data
                return new FragmentC();
            default:
                return null;
        }
    }

   //This populates your Fragment reference array:
   @Override
   public Object instantiateItem(ViewGroup container, int position) {
       Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
       fragments[position]  = createdFragment;
       Log.i(TAG, "::instantiateItem:: " + position + " " + createdFragment.toString());
       return createdFragment;
    }

}

FragmentA.java /**left out most of map specific code, but I am interested in getting latitude/longitude whenever onConnected() or onMapClick() gets called*/ FragmentA.java /**省略了大部分地图特定代码,但我有兴趣在onConnected()onMapClick()被调用时获取纬度/经度*/

@Override
public void onConnected(@Nullable Bundle bundle) {
     Log.i(TAG, "In onConnected(), Google API client is:: " + mGoogleApiClient.isConnected());

     if (mGoogleApiClient != null) {
         try {
                // Get last known recent location.
                mCurrentLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);

                if (mCurrentLocation != null) {
                    // Print current location if not null
                    final LatLng latLng = new LatLng(mCurrentLocation.getLatitude(),
                                                        mCurrentLocation.getLongitude());

                    //wrap LatLng into UserLatLong
                    userLatLong.setLat(latLng.latitude);
                    userLatLong.setLng(latLng.longitude);
//updating the value in the interface
                    mLLCallback.makeUseOfNewLocation(userLatLong);

                    CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 20);
                    mMap.animateCamera(cameraUpdate);
                    mMap.addMarker(new MarkerOptions().position(latLng));
                    Log.i(TAG, "::Google::My current location set::");

                    mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
                        @Override
                        public void onMapClick(LatLng latLng1) {
                            mMap.clear(); //removes the previous marker
                            mMap.addMarker(new MarkerOptions().position(latLng1));

                //updating the value in the interface
                mLLCallback.makeUseOfNewLocation(userLatLong);
                            float x = (float) latLng1.latitude;
                            float y = (float) latLng1.longitude;
                            Log.d(TAG, "Map clicked w/ lat: " + x + " and long: " + y);

                            //wrap LatLng into UserLatLong
                            userLatLong.setLat(latLng1.latitude);
                            userLatLong.setLng(latLng1.longitude);

                        }
                    });

                mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));

                    //for zooming automatically to the location of the marker
                    CameraPosition cameraPosition = new CameraPosition.Builder().target(latLng).zoom(12).build();
                    mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));

                    //TODO: Constrain the camera target to bounds defined by API
                    mMap.setMinZoomPreference(Constants.DEFAULT_MIN_ZOOM);
                    mMap.setMaxZoomPreference(Constants.DEFAULT_MAX_ZOOM);

                } else {
                    Toast.makeText(getActivity(), "Current location is null", Toast.LENGTH_SHORT).show();
                }
            } catch (SecurityException se1) {
                Log.e(TAG, "SecurityException1: " + se1.getLocalizedMessage());
            }

        } else {
            Toast.makeText(getActivity(), "Google API client is null!", Toast.LENGTH_SHORT).show();
        }

FragmentB /**in this fragment, I want to refresh content based on latitude/longitude from FragmentA */ FragmentB /** 在这个片段中,我想根据FragmentA纬度/经度刷新内容 */

public class FragmentB extends Fragment {
    /**
     * Required empty public constructor
     */
    public FragmentB() {
    }


/**the getArguments() is always null*/
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    currLatLong = getNewLatLong();
    }

    /**I want latitude/longitude from FragmentA before onCreateView gets called*/ 
    @Override
    public View onCreateView(LayoutInflater inflater, final ViewGroup container,
                             Bundle savedInstanceState) {

        LayoutInflater inflater1 = LayoutInflater.from(getContext());
        // Inflate the layout for this fragment
        view = inflater1.inflate(R.layout.fragment_a, container, false);
       currLatLong = getNewLatLong();
        //fetch my list based on LatLong
        handleDataFetch(currLatLong);

        return view;
    }

    //
    private void handleDataFetch(UserLatLong newLatLong) {
        final UserLatLong latLong = newLatLong;
        final APIEndpointI apiEndpointI = APIRequests.getClient().create(APIEndpointI.class);

        String userId = "XXXX-XXX-XXXXXXX";

        currLatLong = new UserLatLong(newLat.doubleValue(), newLong.doubleValue());
        if (currLatLong != null) {
            Log.i(TAG, "Finally! Lat is: " + currLatLong.getLat() +
                    " and Long is:" + currLatLong.getLng());
            /**using retrofit*/
            Call<MyResp> call = apiEndpointI.getMyList(userId, currLatLong);
            call.enqueue(new Callback<MyResp>() {
                @Override
                public void onResponse(Call<MyResp> call, Response<MyResp> response) {


                    Log.i(TAG, "Count: " + response.body().getBundles().size());
                    Resources res = getContext().getResources();
                    String cntString = String.format(res.getString(R.string.count), response.body().getBundles().size());
                    tv1.setText(cntString);

                    //Initialize with empty data
                    mGridData = new ArrayList<>();
                    mGridAdapter = new ProfilePicAdapter(getActivity(), R.layout.grid_item_layout, mGridData);
                    mGridView.setAdapter(mGridAdapter);

                   }    
                @Override
                public void onFailure(Call<MyResp> call, Throwable t) {
                    //do something here
                    Log.d(TAG, "Failed to get response for GetMyList(): " + t.getMessage());
                }
            });
        } else {
            Log.e(TAG, "In onCreateView(), lat long are empty");
        }
    }


   //called from activity to pass the latest latlong
   public void setNewLatLong(UserLatLong userLatLong) {
      currLatLong = userLatLong;
   }

   //called from activity to pass the latest latlong
   private UserLatLong getNewLatLong() {
      return currLatLong;
   }

}

It looks like all you need to complete the implementation is to call handleDataFetch() from the setNewLatLong() method if it is a new location.看起来完成实现所需的全部内容就是从setNewLatLong()方法调用handleDataFetch()如果它是一个新位置。

This is needed since onCreateView() won't be called due to the Fragment being in a ViewPager, so the best way to get the updated location info to FragmentB when it is displayed is to just use a public method called from the ViewPager.OnPageChangeListener in the Activity, as you are doing here.这是必需的,因为由于 Fragment 位于 ViewPager 中,因此不会调用onCreateView() ,因此在显示 FragmentB 时将更新的位置信息获取到 FragmentB 的最佳方法是使用从ViewPager.OnPageChangeListener调用的公共方法在 Activity 中,正如您在这里所做的那样。

Just be sure that your equals() method override is implemented correctly in the UserLatLong class, and add this to the setNewLatLong() method:只需确保在UserLatLong类中正确实现了您的equals()方法覆盖,并将其添加到setNewLatLong()方法中:

   //called from activity to pass the latest latlong
   public void setNewLatLong(UserLatLong userLatLong) {
      //Added:
      if (!currLatLong.equals(userLatLong)) {
          handleDataFetch(userLatLong);
      }
      currLatLong = userLatLong;
   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM