Description: I two classes as follows,
public class A extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Do something
return rootView;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Do something
}
public void onStart() {
super.onStart()
}
/* Etc more normal lifecycle callback methods.
*
*/
// Second Class enclosed in first class
public class B extends FragmentActivity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
// Defined methods to be used by Class A.
}
Now my question, when I try to initialize class B in Class A. Like B b = new B();
My crashes on the line I try to initialize class B on (I've tried to initialize class B in various Activity callback methods such as onActivityCreated()
,OnCreateView()
etc none of them worked. The specific error is as follows:
android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:478)
android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
Further details Class A is being called by a MainActivity which in turn populates a ActionBar with Two Tabs. Finally here is the code of the actual class B and the separate Asynchronous class it calls.
public class rookWork extends FragmentActivity implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener {
LocationClient mLocationClient = new LocationClient(this, this, this);
public LocationClient setup() {
return mLocationClient;
}
@Override
public void onConnected(Bundle connectionHint) {
Toast.makeText(getApplicationContext(), "Connected!",
Toast.LENGTH_SHORT).show();
}
@Override
public void onDisconnected() {
Toast.makeText(getApplicationContext(), "Disconnected!",
Toast.LENGTH_SHORT).show();
}
@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());
}
}
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(getActivity(), 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
GetAddressTask getAddressTask = new GetAddressTask(
getActivity());
getAddressTask.execute(currentLocation);
// (new
// GetAddressTask.GetAddressTask(this)).execute(currentLocation);
} else {
Toast.makeText(getActivity(), "servicesConnected() == false",
Toast.LENGTH_SHORT).show();
}
}
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;
}
}
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.
*/
@SuppressLint("ValidFragment")
public class ErrorDialogFragment extends DialogFragment {
// Global field to contain the error dialog
private Dialog mDialog;
/**
* Default constructor. Sets the dialog field to null
*/
@SuppressLint("ValidFragment")
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.
*/
public Dialog onCreateDialog(Bundle savedInstanceState) {
return mDialog;
}
}
/*
* Google Imports
*/
/*
* Android Imports
*/
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.os.AsyncTask;
import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
public class GetAddressTask extends AsyncTask<Location, Void, String> {
Context mContext;
String addressText;
int test;
public GetAddressTask(Context context) {
super();
mContext = context;
}
@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(mContext, 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,
mContext.getString(R.string.IO_Exception_getFromLocation));
// print the stack trace
exception1.printStackTrace();
// Return an error message
return (mContext.getString(R.string.IO_Exception_getFromLocation));
// Catch incorrect latitude or longitude values
} catch (IllegalArgumentException exception2) {
// Construct a message containing the invalid arguments
String errorString = mContext.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 = mContext.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 mContext.getString(R.string.no_address_found);
}
}
protected void onPostExecute(String result) {
/*
* Toast.makeText(mContext.getApplicationContext(), "Execution Done",
* Toast.LENGTH_SHORT).show();
*/
Toast.makeText(mContext.getApplicationContext(),
"Params Length: " + Integer.toString(test), Toast.LENGTH_SHORT)
.show();
}
}
Everything runs fine if I comment out the instatiation of class B (RookWork). I have previously been able to run the asynchronous task with the geocoder fine. However that setup did not involve having a Class B embedded in class A.
the instatiation of class B (RookWork)
RookWork is an Activity
. Activities cannot be directly instantiated in Android. To create a new Activity, you must use Intents.
If In understand correctly, you need an Activity instance because some of the Google Play Services related methods (such as startResolutionForResult()
) require one.
The simplest solution is probably to move all this code (i.e. the implementation of the interfaces) into the fragment itself, then use getActivity()
whenever you need an Activity. It will return the activity to which the Fragment is currently attached.
For example:
public class A extends Fragment
implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener
{
...
@Override
public void onConnectionFailed(ConnectionResult connectionResult)
{
...
connectionResult.startResolutionForResult(getActivity(), LocationUtils.CONNECTION_FAILURE_RESOLUTION_REQUEST);
...
}
...