【发布时间】:2017-12-03 17:26:55
【问题描述】:
所以我有一个应用开始它的生命有 4 个独立的活动,但最近我决定最好有 1 个主要活动和 4 个片段。
我现在的问题是我之前的 2 个活动,现在是片段,其中包含位置连接代码,我需要将代码移动到我的 MainActivity 以便应用程序正确请求位置访问等,而无需崩溃。
两个片段中的每个片段中的代码几乎相同,因此我将在下面的示例中只展示两个片段中的一个。
我主要关心的问题之一是这个特定的代码:
private void handleNewLocation(Location location) {
Log.i("TEST handleNewLocation", "Called handleNewLocation");
// Returns the current adapter in use by the ListView supplied (mListView).
LocationsAdapter adapter = (LocationsAdapter) mListView.getAdapter();
adapter.setCurrentLocation(location);
adapter.notifyDataSetChanged();
}
如您所见,代码引用了 ListView,片段利用该 ListView 获取该 ListView 的正在使用的适配器:LocationsAdapter adapter = (LocationsAdapter) mListView.getAdapter();
我不知道如何将这段代码移动到 MainActivity 中,并且仍然以某种方式从片段中引用 ListView。为了增加这个问题,我还需要在 MainActivity 中再次使用相同类型的代码,但在 2 的第二个片段中也引用 other ListView。
这是我的片段之一,也是它下面的 MainActivity。
位置片段:
public class Locations extends Fragment implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener, LocationListener {
public Locations() {
// Required empty public constructor
}
private static final int PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 100;
private final static int CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
private static final String LOG_TAG = Locations.class.getName();
private GoogleApiClient mGoogleApiClient;
private LocationRequest mLocationRequest;
Location mLocation = new Location(LocationManager.NETWORK_PROVIDER);
private ListView mListView;
public List<Word> locations = new ArrayList<>();
// If the app already has the permission to access the user's location at high accuracy
// (fine location), then connect to the GoogleApiClient.
// If not, no connection-handling methods will be called.
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_ACCESS_FINE_LOCATION: {
// Permission was granted, yay! Do the location-related task you need to do.
if (ContextCompat.checkSelfPermission(getActivity(),
ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
}
}
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.word_list, container, false);
mListView = (ListView) rootView.findViewById(R.id.list);
// The following code checks if the app has permission to access the user's fine location,
// and requests the permission if necessary:
if (ContextCompat.checkSelfPermission(getActivity(), ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(),
ACCESS_FINE_LOCATION)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
new MaterialStyledDialog.Builder(getActivity())
.setTitle(R.string.title_location_permission)
.setDescription(R.string.text_location_permission)
.setIcon(R.drawable.ic_place_white_48dp)
.withDialogAnimation(true)
.setPositiveText(android.R.string.ok)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
//Prompt the user once explanation has been shown
ActivityCompat.requestPermissions(getActivity(),
new String[]{ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_ACCESS_FINE_LOCATION);
}
})
.setNegativeText(android.R.string.no)
.show();
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(getActivity(), new String[]{ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_ACCESS_FINE_LOCATION);
// PERMISSION_REQUEST_ACCESS_FINE_LOCATION is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
// Create the GoogleAPIClient object.
if (mGoogleApiClient == null) {
mGoogleApiClient = new GoogleApiClient.Builder(getActivity())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
// Create the LocationRequest object
mLocationRequest = LocationRequest.create()
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
.setInterval(10 * 1000) // 10 seconds, in milliseconds
.setFastestInterval(1 * 1000); // 1 second, in milliseconds\
locations.add(new Word("Bristol", R.drawable.bristol,
41.674009, -71.279006));
locations.add(new Word("Warren", R.drawable.warren_harbor,
41.730647, -71.282688));
locations.add(new Word("Newport", R.drawable.newport_breakers,
41.486677, -71.315144));
locations.add(new Word("Jamestown", R.drawable.jamestown,
41.496313, -71.368435));
locations.add(new Word("Beavertail Lighthouse", R.drawable.beavertail,
41.458054, -71.395744));
locations.add(new Word("Providence", R.drawable.providence,
41.830279, -71.414955));
locations.add(new Word("Roger Williams Park", R.drawable.roger_williams_park,
41.785836, -71.418525));
locations.add(new Word("Colt State Park", R.drawable.colt_state_park,
41.682970, -71.297362));
locations.add(new Word("Blithewold", R.drawable.blithewold,
41.6540652,-71.2681633));
locations.add(new Word("Narragansett", R.drawable.narragansett,
41.433179,-71.457148));
locations.add(new Word("Barrington", R.drawable.barrington_town_hall,
41.740674, -71.308610));
ViewCompat.setNestedScrollingEnabled(mListView, true);
mListView.setAdapter(new LocationsAdapter(getActivity(), locations, mLocation));
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public void onStart() {
// If the app already has the permission to access the user's location at high accuracy
// (fine location), then connect to the GoogleApiClient.
if (ContextCompat.checkSelfPermission(getActivity(),
ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED || mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
super.onStart();
}
@Override
public void onResume() {
// If the app already has the permission to access the user's location at high accuracy
// (fine location), then connect to the GoogleApiClient.
if (ContextCompat.checkSelfPermission(getActivity(),
ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
mGoogleApiClient.connect();
}
super.onResume();
// Instantiate the locations ArrayList.
locations = new ArrayList<>();
}
@Override
public void onPause() {
super.onPause();
// If the user has paused the app and the GoogleApiClient is currently connected,
// remove location updating, and disconnect from the GoogleApiClient.
if (mGoogleApiClient.isConnected()) {
LocationServices.FusedLocationApi.removeLocationUpdates(mGoogleApiClient,
this);
mGoogleApiClient.disconnect();
locations.clear();
}
}
public void onStop() {
// If the user has stopped the app, disconnect from the GoogleApiClient.
mGoogleApiClient.disconnect();
super.onStop();
}
@Override
public void onConnected(@Nullable Bundle bundle) {
Log.i(LOG_TAG, "Location services connected.");
mLocation = LocationServices.FusedLocationApi.getLastLocation(mGoogleApiClient);
if (mLocation == null) {
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient,
mLocationRequest, this);
} else {
handleNewLocation(mLocation);
}
}
@Override
public void onConnectionSuspended(int i) {
Log.i(LOG_TAG, "Location services suspended. Please reconnect.");
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(getActivity(),
CONNECTION_FAILURE_RESOLUTION_REQUEST);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else {
Log.i(LOG_TAG, "Location services connection failed with code " +
connectionResult.getErrorCode());
}
}
@Override
public void onLocationChanged(Location location) {
handleNewLocation(location);
}
private void handleNewLocation(Location location) {
Log.i("TEST handleNewLocation", "Called handleNewLocation");
// Returns the current adapter in use by the ListView supplied (mListView).
LocationsAdapter adapter = (LocationsAdapter) mListView.getAdapter();
adapter.setCurrentLocation(location);
adapter.notifyDataSetChanged();
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
CategoryAdapter adapter = new CategoryAdapter(this, getSupportFragmentManager());
viewPager.setAdapter(adapter);
// Keeps all 4 Fragments active at once
viewPager.setOffscreenPageLimit(3);
final SmartTabLayout tabLayout = (SmartTabLayout ) findViewById(R.id.viewpagertab);
final LayoutInflater inflater = LayoutInflater.from(tabLayout.getContext());
final Resources res = tabLayout.getContext().getResources();
tabLayout.setCustomTabView(new SmartTabLayout.TabProvider() {
@Override
public View createTabView(ViewGroup container, int position, PagerAdapter adapter) {
AppCompatImageView icon = (AppCompatImageView) inflater.inflate(R.layout.tab_bar_icon,container,
false);
switch (position) {
case 0:
icon.setImageDrawable(res.getDrawable(R.drawable.ic_place_white_24dp));
break;
case 1:
icon.setImageDrawable(res.getDrawable(R.drawable.ic_restaurant_white_24dp));
break;
case 2:
icon.setImageDrawable(res.getDrawable(R.drawable.ic_wallpaper_white_24dp));
break;
case 3:
icon.setImageDrawable(res.getDrawable(R.drawable.ic_account_balance_white_24dp));
break;
default:
throw new IllegalStateException("Invalid position: " + position);
}
return icon;
}
});
tabLayout.setViewPager(viewPager);
// Fragment/Tab Titles
final String[] mTitleNames = {"Locations", "Food", "Photos", "History"};
// Default actionbar title
setActionBarTitle(mTitleNames[0]);
// Set actionbar title when tab is selected
tabLayout.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
setActionBarTitle(mTitleNames[position]);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
public void setActionBarTitle(String title) {
getSupportActionBar().setTitle(title);
}
}
有没有人有任何想法和/或代码可以与我分享,说明我将如何解决我遇到的这个问题?非常感谢!
更新:
我可能应该更详细地解释一下。由于我对所有术语缺乏经验,我希望我的解释不会太难理解。
所以handleNewLocation() 的全部目的是由onLocationChanged 调用,这样当用户的位置发生变化时,它会运行handleNewLocation() 中的代码,它会获取用户的位置并针对其中定义的设置坐标运行它上面片段中的 ArrayList。这将导致两个位置之间的距离被更新为,例如 6.5 英里以外,等等,然后显示在 ListView 中的 TextView 中。
LocationsAdapter 是一个单独的 java 类,我可以在任何地方调用它。 - 所以我认为这不是问题的一部分。
我有数据类型Word,它由ArrayList 使用,并包含计算给定用户和位置坐标并将它们全部转换为DecimalFormat 以显示在给定ListView 中的TextView 中的代码。
我认为我的问题是……我需要在 Locations 类中引用 ArrayList。我需要引用我将 LocationsAdapter 设置为的 ArrayList 和 ListView 的确切实例,如:mListView.setAdapter(new LocationsAdapter(getActivity(), locations, mLocation));
我对 Java 的相对缺乏经验表现为我不知道如何复制代码的所有当前状态,而是在 MainActivity 中拥有所有获取位置的代码,但仍然可以引用 mListView对于每个片段。
这有意义吗?我很难解释它。如果有帮助,我可以提供其他类以供参考?
【问题讨论】:
-
所有片段都有一个
getActivity()方法。如果你让你的 Activity 有一个用于适配器(或列表数据)的 getter,你的 Fragments 都可以从共享的 Activity 中获取,并填充一个 ListView -
您好 cricket_007,感谢您的回复!抱歉,您有什么办法可以在代码示例中向我展示这一点吗?我是一个视觉学习者,如果我没有“看到”我所教的东西,有时我可能会丢失简单的东西,如果这有意义的话! :)
标签: java android listview android-fragments