我正在尝试从一个存在于不同类中的UI视图中调用方法。这些是来自Android开发者网站的两个样本。我会专注于这个问题的一个观点,因为其他观点基本相同。
在我的MainActivity.java中,我正在设置Drawer导航,填充列表等等。我总共有三个片段,每个片段都有自己的UI用于UI,每个片段都有自己的Java类(扩展)片段)来处理各自的onCreateView。对于其中一个片段,我有一个调用方法getAddress的按钮。这个方法存在一个单独的类LocationActivity.java,因为Android dev网站的示例代码要求它是Activity的扩展(加上很多这些方法将从其他片段中重用)。
对于我对where_am_i_longlat.xml的引用,该文件只包含UI组件。抱歉,这篇文章没空了。该XML中有一个按钮,用于调用getAddress按钮。
在下面的代码块中,我的where_am_i_longlat.xml有一个调用getAddress方法的按钮。 getAddress方法存在于LocationActivity.java中。但它无法找到那种方法,我猜是因为它在WhereAmILongLat.java中寻找它?此外,该方法更新where_am_i_longlat.xml内的文本框。关于如何解决这个问题的任何想法。
(对不起,如果标记不正确,我没有看到专门用于Android开发的那个)
MainActivity.java(构建抽屉和应用程序导航)
public class MainActivity extends FragmentActivity {
private String[] data;
private DrawerLayout drawer;
private ListView navList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
final String[] fragments = {
"com.example.android.navigationdrawerexample.Home",
"com.example.android.navigationdrawerexample.WhereAmILongLat",
"com.example.android.navigationdrawerexample.WhereAmIAddress",
"com.example.android.navigationdrawerexample.WhatAmIDoing"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTitle = mDrawerTitle = getTitle();
data = getResources().getStringArray(R.array.navigation_array);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
navList = (ListView) findViewById(R.id.left_drawer);
drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
navList.setAdapter(new ArrayAdapter<String>(getActionBar().getThemedContext(), R.layout.drawer_list_item, data));
navList.setOnItemClickListener(new DrawerItemClickListener());
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
drawer, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
};
drawer.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
selectItem(0);
}
}
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectItem(position);
}
}
private void selectItem(int pos) {
FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
tx.replace(R.id.content_frame, Fragment.instantiate(MainActivity.this, fragments[pos]));
tx.commit();
navList.setItemChecked(pos, true);
setTitle(data[pos]);
drawer.closeDrawer(navList);
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
getActionBar().setTitle(mTitle);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = drawer.isDrawerOpen(navList);
menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action buttons
switch (item.getItemId()) {
case R.id.action_websearch:
// create intent to perform web search for this planet
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
intent.putExtra(SearchManager.QUERY, getActionBar().getTitle());
// catch event that there's no activity to handle intent
if (intent.resolveActivity(getPackageManager()) != null) {
startActivity(intent);
} else {
Toast.makeText(this, R.string.app_not_available, Toast.LENGTH_LONG).show();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
WhereAmILongLat.java(从where_am_i_longlat.xml构建特定的UI)
package com.example.android.navigationdrawerexample;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class WhereAmILongLat extends Fragment {
public static Fragment newInstance(Context context) {
WhereAmILongLat f = new WhereAmILongLat();
return f;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.where_am_i_longlat, null);
return root;
}
}
LocationActivity.java。所有基于位置的方法都是。
public class LocationActivity extends FragmentActivity implements
LocationListener,
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
// A request to connect to Location Services
private LocationRequest mLocationRequest;
// Stores the current instantiation of the location client in this object
private LocationClient mLocationClient;
// Handles to UI widgets
private TextView mLatLng;
private TextView mAddress;
private ProgressBar mActivityIndicator;
private TextView mConnectionState;
private TextView mConnectionStatus;
// Handle to SharedPreferences for this app
SharedPreferences mPrefs;
// Handle to a SharedPreferences editor
SharedPreferences.Editor mEditor;
boolean mUpdatesRequested = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Get handles to the UI view objects
mLatLng = (TextView) findViewById(R.id.lat_lng);
mAddress = (TextView) findViewById(R.id.address);
mActivityIndicator = (ProgressBar) findViewById(R.id.address_progress);
mConnectionState = (TextView) findViewById(R.id.text_connection_state);
mConnectionStatus = (TextView) findViewById(R.id.text_connection_status);
// Create a new global location parameters object
mLocationRequest = LocationRequest.create();
/*
* Set the update interval
*/
mLocationRequest.setInterval(LocationUtils.UPDATE_INTERVAL_IN_MILLISECONDS);
// Use high accuracy
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
// Set the interval ceiling to one minute
mLocationRequest.setFastestInterval(LocationUtils.FAST_INTERVAL_CEILING_IN_MILLISECONDS);
// Note that location updates are off until the user turns them on
mUpdatesRequested = false;
// Open Shared Preferences
mPrefs = getSharedPreferences(LocationUtils.SHARED_PREFERENCES, Context.MODE_PRIVATE);
// Get an editor
mEditor = mPrefs.edit();
mLocationClient = new LocationClient(this, this, this);
}
@Override
public void onStop() {
// If the client is connected
if (mLocationClient.isConnected()) {
stopPeriodicUpdates();
}
// After disconnect() is called, the client is considered "dead".
mLocationClient.disconnect();
super.onStop();
}
@Override
public void onPause() {
// Save the current setting for updates
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, mUpdatesRequested);
mEditor.commit();
super.onPause();
}
@Override
public void onStart() {
super.onStart();
/*
* Connect the client. Don't re-start any requests here;
* instead, wait for onResume()
*/
mLocationClient.connect();
}
/*
* Called when the system detects that this Activity is now visible.
*/
@Override
public void onResume() {
super.onResume();
// If the app already has a setting for getting location updates, get it
if (mPrefs.contains(LocationUtils.KEY_UPDATES_REQUESTED)) {
mUpdatesRequested = mPrefs.getBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
// Otherwise, turn off location updates until requested
} else {
mEditor.putBoolean(LocationUtils.KEY_UPDATES_REQUESTED, false);
mEditor.commit();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
// Choose what to do based on the request code
switch (requestCode) {
// If the request code matches the code sent in onConnectionFailed
case LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST :
switch (resultCode) {
// If Google Play services resolved the problem
case Activity.RESULT_OK:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.resolved));
// Display the result
mConnectionState.setText(R.string.connected);
mConnectionStatus.setText(R.string.resolved);
break;
// If any other result was returned by Google Play services
default:
// Log the result
Log.d(LocationUtils.APPTAG, getString(R.string.no_resolution));
// Display the result
mConnectionState.setText(R.string.disconnected);
mConnectionStatus.setText(R.string.no_resolution);
break;
}
// If any other request code was received
default:
// Report that this Activity received an unknown requestCode
Log.d(LocationUtils.APPTAG,
getString(R.string.unknown_activity_request_code, requestCode));
break;
}
}
private boolean servicesConnected() {
// Check that Google Play services is available
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
// If Google Play services is available
if (ConnectionResult.SUCCESS == resultCode) {
// In debug mode, log the status
Log.d(LocationUtils.APPTAG, getString(R.string.play_services_available));
// Continue
return true;
// Google Play services was not available for some reason
} else {
// Display an error dialog
Dialog dialog = GooglePlayServicesUtil.getErrorDialog(resultCode, this, 0);
if (dialog != null) {
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
errorFragment.setDialog(dialog);
errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
}
return false;
}
}
public void getLocation(View v) {
// If Google Play Services is available
if (servicesConnected()) {
// Get the current location
Location currentLocation = mLocationClient.getLastLocation();
// Display the current location in the UI
mLatLng.setText(LocationUtils.getLatLng(this, currentLocation));
}
}
/**
* Invoked by the "Get Address" button.
* Get the address of the current location, using reverse geocoding. This only works if
* a geocoding service is available.
*
* @param v The view object associated with this method, in this case a Button.
*/
// For Eclipse with ADT, suppress warnings about Geocoder.isPresent()
@SuppressLint("NewApi")
public void getAddress(View v) {
// In Gingerbread and later, use Geocoder.isPresent() to see if a geocoder is available.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD && !Geocoder.isPresent()) {
// No geocoder is present. Issue an error message
Toast.makeText(this, R.string.no_geocoder_available, Toast.LENGTH_LONG).show();
return;
}
if (servicesConnected()) {
// Get the current location
Location currentLocation = mLocationClient.getLastLocation();
// Turn the indefinite activity indicator on
mActivityIndicator.setVisibility(View.VISIBLE);
// Start the background task
(new LocationActivity.GetAddressTask(this)).execute(currentLocation);
}
}
/**
* Invoked by the "Start Updates" button
* Sends a request to start location updates
*
* @param v The view object associated with this method, in this case a Button.
*/
public void startUpdates(View v) {
mUpdatesRequested = true;
if (servicesConnected()) {
startPeriodicUpdates();
}
}
/**
* Invoked by the "Stop Updates" button
* Sends a request to remove location updates
* request them.
*
* @param v The view object associated with this method, in this case a Button.
*/
public void stopUpdates(View v) {
mUpdatesRequested = false;
if (servicesConnected()) {
stopPeriodicUpdates();
}
}
/*
* Called by Location Services when the request to connect the
* client finishes successfully. At this point, you can
* request the current location or start periodic updates
*/
@Override
public void onConnected(Bundle bundle) {
mConnectionStatus.setText(R.string.connected);
if (mUpdatesRequested) {
startPeriodicUpdates();
}
}
/*
* Called by Location Services if the connection to the
* location client drops because of an error.
*/
@Override
public void onDisconnected() {
mConnectionStatus.setText(R.string.disconnected);
}
/*
* Called by Location Services if the attempt to
* Location Services fails.
*/
@Override
public void onConnectionFailed(ConnectionResult connectionResult) {
/*
* Google Play services can resolve some errors it detects.
* If the error has a resolution, try sending an Intent to
* start a Google Play services activity that can resolve
* error.
*/
if (connectionResult.hasResolution()) {
try {
// Start an Activity that tries to resolve the error
connectionResult.startResolutionForResult(
this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
/*
* Thrown if Google Play services canceled the original
* PendingIntent
*/
} catch (IntentSender.SendIntentException e) {
// Log the error
e.printStackTrace();
}
} else {
// If no resolution is available, display a dialog to the user with the error.
showErrorDialog(connectionResult.getErrorCode());
}
}
/**
* Report location updates to the UI.
*
* @param location The updated location.
*/
@Override
public void onLocationChanged(Location location) {
// Report to the UI that the location was updated
mConnectionStatus.setText(R.string.location_updated);
// In the UI, set the latitude and longitude to the value received
mLatLng.setText(LocationUtils.getLatLng(this, location));
}
/**
* In response to a request to start updates, send a request
* to Location Services
*/
private void startPeriodicUpdates() {
mLocationClient.requestLocationUpdates(mLocationRequest, this);
mConnectionState.setText(R.string.location_requested);
}
/**
* In response to a request to stop updates, send a request to
* Location Services
*/
private void stopPeriodicUpdates() {
mLocationClient.removeLocationUpdates(this);
mConnectionState.setText(R.string.location_updates_stopped);
}
/**
* An AsyncTask that calls getFromLocation() in the background.
* The class uses the following generic types:
* Location - A {@link android.location.Location} object containing the current location,
* passed as the input parameter to doInBackground()
* Void - indicates that progress units are not used by this subclass
* String - An address passed to onPostExecute()
*/
protected class GetAddressTask extends AsyncTask<Location, Void, String> {
// Store the context passed to the AsyncTask when the system instantiates it.
Context localContext;
// Constructor called by the system to instantiate the task
public GetAddressTask(Context context) {
// Required by the semantics of AsyncTask
super();
// Set a Context for the background task
localContext = context;
}
/**
* Get a geocoding service instance, pass latitude and longitude to it, format the returned
* address, and return the address to the UI thread.
*/
@Override
protected String doInBackground(Location... params) {
/*
* Get a new geocoding service instance, set for localized addresses. This example uses
* android.location.Geocoder, but other geocoders that conform to address standards
* can also be used.
*/
Geocoder geocoder = new Geocoder(localContext, Locale.getDefault());
// Get the current location from the input parameter list
Location location = params[0];
// Create a list to contain the result address
List <Address> addresses = null;
// Try to get an address for the current location. Catch IO or network problems.
try {
/*
* Call the synchronous getFromLocation() method with the latitude and
* longitude of the current location. Return at most 1 address.
*/
addresses = geocoder.getFromLocation(location.getLatitude(),
location.getLongitude(), 1
);
// Catch network or other I/O problems.
} catch (IOException exception1) {
// Log an error and return an error message
Log.e(LocationUtils.APPTAG, getString(R.string.IO_Exception_getFromLocation));
// print the stack trace
exception1.printStackTrace();
// Return an error message
return (getString(R.string.IO_Exception_getFromLocation));
// Catch incorrect latitude or longitude values
} catch (IllegalArgumentException exception2) {
// Construct a message containing the invalid arguments
String errorString = getString(
R.string.illegal_argument_exception,
location.getLatitude(),
location.getLongitude()
);
// Log the error and print the stack trace
Log.e(LocationUtils.APPTAG, errorString);
exception2.printStackTrace();
//
return errorString;
}
// If the reverse geocode returned an address
if (addresses != null && addresses.size() > 0) {
// Get the first address
Address address = addresses.get(0);
// Format the first line of address
String addressText = getString(R.string.address_output_string,
// If there's a street address, add it
address.getMaxAddressLineIndex() > 0 ?
address.getAddressLine(0) : "",
// Locality is usually a city
address.getLocality(),
// The country of the address
address.getCountryName()
);
// Return the text
return addressText;
// If there aren't any addresses, post a message
} else {
return getString(R.string.no_address_found);
}
}
/**
* A method that's called once doInBackground() completes. Set the text of the
* UI element that displays the address. This method runs on the UI thread.
*/
@Override
protected void onPostExecute(String address) {
// Turn off the progress bar
mActivityIndicator.setVisibility(View.GONE);
// Set the address in the UI
mAddress.setText(address);
}
}
/**
* Show a dialog returned by Google Play services for the
* connection error code
*
* @param errorCode An error code returned from onConnectionFailed
*/
private void showErrorDialog(int errorCode) {
// Get the error dialog from Google Play services
Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
errorCode,
this,
LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
// If Google Play services can provide an error dialog
if (errorDialog != null) {
// Create a new DialogFragment in which to show the error dialog
ErrorDialogFragment errorFragment = new ErrorDialogFragment();
// Set the dialog in the DialogFragment
errorFragment.setDialog(errorDialog);
// Show the error dialog in the DialogFragment
errorFragment.show(getSupportFragmentManager(), LocationUtils.APPTAG);
}
}
/**
* Define a DialogFragment to display the error dialog generated in
* showErrorDialog.
*/
public static class ErrorDialogFragment extends DialogFragment {
// Global field to contain the error dialog
private Dialog mDialog;
/**
* Default constructor. Sets the dialog field to null
*/
public ErrorDialogFragment() {
super();
mDialog = null;
}
/**
* Set the dialog to display
*
* @param dialog An error dialog
*/
public void setDialog(Dialog dialog) {
mDialog = dialog;
}
/*
* This method must return a Dialog to the DialogFragment.
*/
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
}