编辑:这是PasteBin 的来源。我觉得我可能需要重新设计整个服务.. :(
我是RingPack的开发者。基本思想是在后台启动一个服务,负责为用户切换铃声。我在丢失对服务中的 ArrayList 的引用时遇到问题。我想我可能误解了生命周期是如何工作的。我的意图是在用户从 Activity 中选择一个包时启动它。
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);
我告诉服务将默认通知音设置为与“currentPackId”对应的包的第一个音。
当用户想要关闭 RingPack 时,禁用是这样完成的:
Intent i = new Intent(RingActivity.this, RingService.class);
RingActivity.this.stopService(i);
Toast.makeText(RingActivity.this.getBaseContext(), RingActivity.this.getString(R.string.ringPackDisabled), Toast.LENGTH_SHORT).show();
所以服务的 onCreate 看起来像这样:
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();}
然后将其传递给 onStartCommand,后者返回 START_NOT_STICKY(因为我将手动创建和销毁服务),后者将其传递给 handleStart()。
@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);
}
}
}}
isSdOk() 方法只检查 SD 卡是否已安装,因为铃声存储在其上。initControl() 只是保存用户的默认铃声,以便我们可以在他们禁用我们时将其归还。setPack() 方法如下所示:
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<Integer>();
else
tones.clear();
mapTones(packId);
currIndex = 0;
setNotificationTone(tones.get(currIndex));}
音调 ArrayList 是我一直在失去的。这是它被初始化的地方。它包含一个包中所有启用的铃声的 ID。我看到的 NullPointerException 在 swapTone() 中:
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));}
我希望它起作用的方式是,如果 setPack() 还没有调用 swapTone() ,则永远不会被调用。同样,我的用户不断收到此错误,但我自己无法重现它。任何帮助将不胜感激。我为代码墙道歉,但我很困惑。也许我没有正确使用服务的概念?