【发布时间】:2016-10-17 02:51:34
【问题描述】:
在我的应用程序的活动中,我有一个 ViewPager 实现,它在启动时加载地图片段 (FragmentA),然后还有 2 个其他片段根据在 FragmentA 中选择的纬度和经度显示内容。
我无法在启动时将 FragmentA 的纬度/经度提供给其他 2 个 Fragment,并在用户单击 FragmentA 中的地图时继续提供。
以下是我尝试过的方法:
- 使用接口在片段之间进行通信 -> 活动 -> 片段(坚持这种方法)
- 在片段初始化时使用 bundle 在片段之间传递信息
但是,这些方法都不适合我。
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
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 /**省略了大部分地图特定代码,
但我有兴趣在每次调用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 /**在这个fragment中,我要根据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;
}
}
【问题讨论】:
-
在上面的实现中,我滑动到
FragmentB的片段不会随着来自FragmentA的新位置而更新,而是另一个片段FragmentC获得更新的位置。我不确定为什么会这样。我正在使用方法#1,使用接口在片段之间进行通信。 -
取得了一些进展 - 用
addOnPageChangeListener更新了 MyActivity 但现在地图片段,FragmentA 也被刷新,这会产生 2 个问题:#1 选定的地图位置仅对我滑动到的视图可用,如果我再次滑动,我会返回再次创建的地图片段 FragmentA,因此新选择的片段不会获得先前选择的位置# 2 因为pagerAdapter.notifyDataSetChanged();,所有片段都被刷新了,刷新在地图片段上特别明显。 -
无需在 PagerAdapter 上调用
notifyDataSetChanged()。只需保留对ViewPager Fragments的引用,将当前数据存储在Activity中,并在每次加载时将最新数据提供给相关Fragment。在这里查看答案:stackoverflow.com/questions/36503779/… -
@DanielNugent 谢谢。您很友善地发布了很多答案,并且您回答了我的问题!根据您的回复,我不确定是否将活动中的数据传递给
FragmentB/FragmentC。当前的实现:定义了一个接口IUserLatLong,只有makeUseOfNewLocation(userLatLong)。FragmentA实现、获取位置数据并传递给此方法,而 Activity 也实现了此接口,因此,在FragmentB/FragmentC的onCreateView中,他们只需在 Activity 中调用公共方法getLLFromActivity()即可获取 LatLong。如何在这种新方法中进行数据传输? -
大部分看起来都不错。看起来您也应该在调用
((FragmentB) frag).setNewLatLong(newUserLatLong);之后再调用((FragmentB) frag).handleDataFetch(newUserLatLong);,但前提是位置已更改。
标签: android android-fragments android-viewpager android-maps-v2