title: Android Service Losing an ArrayList
body: <p>Edit: <a href="http://pastebin.com/YqBcQDvU" rel="nofollow">here's</a> the source on PasteBin. I feel like I might need to just redesign the entire Service.. :(</p>
  
  <p>I'm the developer of <a href="https://market.android.com/details?id=com.cryclops.ringpack&amp;feature=search_result" rel="nofollow">RingPack</a>. The basic idea is that there is a Service launched in the background that takes care of switching the ringtone out for the user. I'm having issues with losing my reference to an ArrayList within the Service. I think I may be misunderstanding how the lifecycle works. My intent was for it to be started whenever the user selects a pack from the Activity.</p>
  
  <p><code>Intent i = new Intent(RingActivity.this, RingService.class);
                      i.putExtra(RingService.ACTION, RingService.PACK_SET);
                      i.putExtra(RingService.PASSED_PACK, currentPackId);
                      RingActivity.this.startService(i);</code></p>
  
  <p>I tell the Service to set the Default Notification Tone to the first tone of the pack corresponding to "currentPackId".</p>
  
  <p>When the user wants to turn off RingPack, the disabling is done like so:</p>
  
  <p><code>Intent i = new Intent(RingActivity.this, RingService.class);
                      RingActivity.this.stopService(i);</code></p>
  
  <p><code>Toast.makeText(RingActivity.this.getBaseContext(), RingActivity.this.getString(R.string.ringPackDisabled), Toast.LENGTH_SHORT).show();</code></p>
  
  <p>So the Service's onCreate looks like so:</p>
  
  <pre><code>public void onCreate() {
  db = new DbManager(this);
  db.open();
  
  vib = (Vibrator) getSystemService(VIBRATOR_SERVICE);
  
  IntentFilter intentFilter = new IntentFilter(Intent.ACTION_TIME_TICK);
  registerReceiver(tReceiver, intentFilter);
  timeTick = 0;
  
  //figure out the widget's status
  SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
  widgetEnabled = prefs.getBoolean(WIDGET_ALIVE, false);
  
  //save the ringtone for playing for the widget
  Uri u = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
  r = RingtoneManager.getRingtone(this.getBaseContext(), u);
  playAfterSet = false;
  
  super.onCreate();}
  </code></pre>
  
  <p>Then it passes it off to onStartCommand, which returns START_NOT_STICKY (since I will be creating and destroying the Service manually), who passes it off to handleStart().</p>
  
  <pre><code>@Override private void handleStart(Intent intent) {     
  final Intent i = intent;
  if (isSdOk()) {
      int action = i.getIntExtra(ACTION, -1);
  
      if (action != -1) {
          if (action == PACK_SET) {
              playAfterSet = true;
  
              Thread packSetThread = new Thread() {
                  @Override
                  public void run() {
                      int passedPackId = i.getIntExtra(PASSED_PACK, -1);
                      //we were passed the id
                      if (passedPackId != -1) {
                          checkPrefs();
  
                          if (!enabled)
                              initControl(passedPackId);
                          else
                              setPack(passedPackId);
  
                          packSetHandler.sendEmptyMessage(0);
                      }
                  }
              };
              packSetThread.start();
          }
          else if (action == NEXT_TONE) {
              checkPrefs();
              swapTone();
          }
          else if (action == PLAY_TONE) {
              playCurrentTone();
          }
          else if (action == WIDGET_STATUS) {
              widgetEnabled = intent.getBooleanExtra(WIDGET_ALIVE, false);
              if (toneName != null)
                  RingWidget.update(getBaseContext(), toneName);
          }
      }
  }}
  </code></pre>
  
  <p>The isSdOk() method just checks if the SD card is mounted, since the ringtones are stored on it. initControl() just saves the user's default ringtone, so that we can give it back when they disable us. The setPack() method looks like this:</p>
  
  <pre><code>private void setPack(int packId) {
  //save the current pack id in the prefs for restarting
  SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(RingService.this.getBaseContext());
  SharedPreferences.Editor editor = prefs.edit();
  editor.putInt(SAVED_PACKID, packId);
  editor.commit();
  
  //get the info we need to work with this pack
  //it's path on the SD
  //build the tones ArrayList to work from
  grabPath(packId);
  if (tones == null)
      tones = new ArrayList&lt;Integer&gt;();
  else
      tones.clear();
  mapTones(packId);
  currIndex = 0;
  setNotificationTone(tones.get(currIndex));}
  </code></pre>
  
  <p>The tones ArrayList is what I've been losing. This is where it is initialized. It holds the ids of all the enabled ringtones within a pack. The NullPointerException I've been seeing is in swapTone():</p>
  
  <pre><code>private void swapTone() {
  //locked
  if (lockPref)
      return;
  //shuffle on
  else if (shufflePref) {
      int randIndex = currIndex;
  
      while (randIndex == currIndex)
          randIndex = (int) Math.floor(Math.random() * tones.size());
      currIndex = randIndex;
  }
  //shuffle off
  else {
      if (currIndex != (tones.size() - 1))
          currIndex++;
      else
          currIndex = 0;
  }
  
  setNotificationTone(tones.get(currIndex));}
  </code></pre>
  
  <p>They way I intended it work is for swapTone() to never be called if setPack() hasn't already. Again, my users keep getting this error, but I can't reproduce it myself. Any help would be greatly appreciated. I apologize for the code wall, but I am very confused. Perhaps I'm not using the concept of a Service correctly?</p>