2

I am trying to convert one of my apps to now use Fragments. This app also uses the Android License checker. While testing I had the license checker code commented out and now have the app working like I want. I am now ready to uncomment that code so I can put it back on the Market but when I do I get this message every other time I start the app:

java.lang.IllegalStateException: Fragment MainHomeFragment{40544bd8} not attached to Activity

This happens if I test on the phone or with the emulator. It almost seems like the license checker is not finishing fast enough so when it inflates the Fragment there is no Activity to attach it to. At first I was just starting the app and then pressing the back button once it loaded and tried it again right away. I thought the license checker might have still been running from the first try so the next time I waited 5 minutes before using the back key and still get the same issue. The weird thing is after the app blows up the 2nd time if I try it again it works but on the 4th try it fails again so something must not be getting cleared out from the first try that is successful. If I comment out the LicenseChecker code and run it again it works every time. I tried putting the call to the LicenseChecker in a new Class as a Thread so it wouldn't hold up the Activity being created but still get the same issue. Any ideas on what I should try to fix this?

Here is the onCreate code for my main FragmentActivity:

public void onCreate(Bundle savedInstanceState) {      
  super.onCreate(savedInstanceState);

  ConnectivityManager connectivityManager 
    = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
  NetworkInfo activeNetwork = 
    connectivityManager.getActiveNetworkInfo();

  if (activeNetwork != null) { 
    android_id = Secure.getString(this.getContentResolver(), 
      Secure.ANDROID_ID);
    mObsfuscator = new AESObfuscator(SALT, getPackageName(), android_id);
    ServerManagedPolicy serverPolicy = new 
      ServerManagedPolicy(this, mObsfuscator);
    mLicenseCheckerCallback = new MyLicenseCheckerCallback();
    mChecker = new LicenseChecker(this, serverPolicy,
      BASE64_PUBLIC_KEY);
    mChecker.checkAccess(mLicenseCheckerCallback);
  } 

  setContentView(R.layout.fragment_layout);
}
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
Chris
  • 379
  • 1
  • 6
  • 19
  • Update on this issue. I forgot to mention that in my License Checker I am keeping a count of how many times the License Checker fails in the Shared Preferences. The reason for this is I have had a few users who seem to fail every now and then so I wanted to let it fail a few times before giving them the error message. If I comment out just the commit() on the SharedPreferenceEditor the error goes away but then the value I am trying to put is not saved. Any idea why this would be causing my issue and also why it would be only every other time it runs? – Chris Oct 26 '11 at 20:07

2 Answers2

0

I know this is really old, but I'll still put in my 2 cents.

It's not clear in your question how you're adding the Fragment (whether through the XML <fragment> tag, or with a FragmentTransaction. Whatever you're doing, if you only want the Fragment added in a certain case (if the License checker returns OK or whatever) I'd recommend you add the fragment programatically.

So basically, define your "Loading..." view inside a FrameLayout, or any other layout, and then, with a FragmentTransaction, replace whatever's in that layout object with your new Fragment.

The way I do this is with a Thread. I dislike AsyncTask very strongly because it makes all background jobs share one thread. It makes synchronization a bit easier but can really affect performance if you have a lot of downloads/network jobs, for instance, because it kind of queues one after the other, and the launching of a long job will delay all the other background jobs from executing.

I define TWO Runnable objects (implements Runnable) because you need another one to execute on the UI thread (if you manipulate UI from a background thread, you get an Exception).

So basically, in the first Runnable object that will be executed by the Thread, you receive a reference to the calling Activity, and save it as an instance variable. Then, you use that reference to execute the second Runnable object on the UI thread, like this (I do this at the end of the run method: callingActivity.runOnUiThread(new RunnableToRunOnUIThread()); and in there you add the Fragment programatically.

Daniel Gray
  • 1,697
  • 1
  • 21
  • 41
0

Why don't you initially do a setContentView with loading view and then after finishing the licensing procedure, you do the "real" setContentView with your fragment?

I think that would work ok.

Jack Allen
  • 549
  • 2
  • 5
  • 19
rui.araujo
  • 9,597
  • 1
  • 18
  • 24
  • Sometimes the license check can take several seconds and I don't want the app to take that long to show the user the main screen. Is anyone else out there using the license server with Fragments and would mind telling me how they make this work? – Chris Oct 27 '11 at 00:10