当应用程序关闭时,来自服务的 BroadcastReceiver 无法正常运行
BroadcastReceiver from Service not functioning correctly when app is closed
我正在创建一个应用程序,它有一个图像按钮,当它被点击时会启动一个服务。该服务包含一个我用作 24 小时计时器的处理程序。启动服务后,该按钮将被禁用,因此无法再次单击。然后,当时间到了时,按钮将再次启用。在应用程序完全关闭之前,这一切都很好。如果应用程序完全关闭,服务将继续正常运行,除非 BroadcastReceiver 出现问题。如果应用程序关闭然后重新打开,即使服务已经运行,也可以单击启动服务的按钮。我不确定为什么在应用程序重新打开时启用了按钮,即使服务仍在运行。
这是我的服务代码:
public class SetupTimerPC1 extends Service
{
Handler handler;
Database data;
Intent i, result;
runGraphics runG;
int bucketLevel = 1, bucketExpTotal = 0, totalWater = 0, bucketExp = 0;
float waterAmt = 0;
int timerCount = 0;
Notification notify;
Notification.Builder builder;
NotificationManager notificationManager;
PendingIntent pendingIntent;
@Override
public IBinder onBind(Intent intent)
{
return null;
}//end onBind function
@Override
public void onRebind(Intent intent)
{
super.onRebind(intent);
}//end onRebing
@Override
public boolean onUnbind(Intent intent)
{
return true;
}//end onUnbind
@Override
public void onCreate()
{
super.onCreate();
//setup 24 hour timer
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(runnable, 2000); //600000 -> wait ten minutes then call runnable
}//end onCreate function
private Runnable runnable = new Runnable()
{
public void run()
{
//get current bucket exp
data = new Database(SetupTimerPC1.this);
data.open();
bucketExp = data.getBucketExp();
data.close();
//check experience for current level
if (bucketExp < 3000)
{
bucketLevel = 1;
}//end if
else if (bucketExp > 3000 && bucketExp < 6000)
{
bucketLevel = 2;
}//end else if
else if (bucketExp > 6000 && bucketExp < 9000)
{
bucketLevel = 3;
}//end else if
else if (bucketExp > 9000 && bucketExp < 12000)
{
bucketLevel = 4;
}//end else if
else if (bucketExp > 12000)
{
bucketLevel = 5;
}//end else if
//give resource based on level
if (bucketLevel == 1)
{
waterAmt += .2;
bucketExp += 1;
}//end if
else if (bucketLevel == 2)
{
waterAmt += .4;
bucketExp += 2;
}//end else if
else if (bucketLevel == 3)
{
waterAmt += .6;
bucketExp += 3;
}//end else if
else if (bucketLevel == 4)
{
waterAmt += .8;
bucketExp += 4;
}//end else if
else if (bucketLevel == 5)
{
waterAmt += 1.0;
bucketExp += 5;
}//end else if
timerCount++;
if (timerCount < 5)//144
{
handler.postDelayed(runnable, 2000); //600000
}//end if
else
{
//pull data
data = new Database(SetupTimerPC1.this);
data.open();
bucketExpTotal = data.getBucketExp();
totalWater = data.getWaterAmt();
data.close();
//add new data to old
bucketExpTotal += bucketExp;
totalWater += (int)waterAmt;
//push data
data.open();
data.bucketExpEntry(bucketExpTotal);
data.waterAmountEntry(totalWater);
data.bucketLevelEntry(bucketLevel);
data.close();
//send notification that resources have been gained
notifyUser();
i.putExtra("polarCap1Stat", true);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
handler.removeCallbacks(runnable);
}//end else
}//end run function
};//end runnable
public void notifyUser()
{
//notify user of resource gain
result = new Intent(this, runGraphics.class);
pendingIntent = PendingIntent.getActivity(
SetupTimerPC1.this,
0,
result,
Intent.FLAG_ACTIVITY_NEW_TASK);
notify = new Notification.Builder(getApplicationContext())
.setContentTitle("2023: Water Gained")
.setContentText("Successfully extracted water.")
.setTicker("2023")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setSmallIcon(R.drawable.alienicon)
.build();
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notify);
}//end notifyUser
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
i = new Intent("polarCap1Status");
i.putExtra("polarCap1Stat", false);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
return Service.START_STICKY;
}//end onStartCommand function
}//结束SetupTimerPC1类
这是从 BroadcastReceiver 接收布尔值的按钮的代码:
//setup image buttons
polarCap1 = (ImageButton) findViewById(R.id.polarCapButton1);
polarCap1.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(getApplicationContext(), "Attempting to Gain Resources", Toast.LENGTH_SHORT).show();
if (polarCap1.isEnabled() && appSound)
{
water = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
playSound = water.load(runGraphics.this, R.raw.watersound, 1);
//play water sound
water.setOnLoadCompleteListener(new OnLoadCompleteListener()
{
@Override
public void onLoadComplete(SoundPool soundPool,
int sampleId, int status)
{
water.play(playSound, 1, 1, 0, 0, 1);
}//end onLoadComplete
});//end setOnLoadCompleteListener
}//end if
//button cannot be clicked
polarCap1.setEnabled(false);
//start service for timer
startService(new Intent(runGraphics.this, SetupTimerPC1.class));
//stop service for timer
//stopService(new Intent(runGraphics.this, SetupTimerPC1.class));
//broadcast receiver to allow button to be clicked again
mMessageReceiver1 = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
clickOnOff1 = intent.getBooleanExtra("polarCap1Stat", false);
polarCap1.setEnabled(clickOnOff1);
updateScores();
}//end onReceive function
};
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageReceiver1, new IntentFilter("polarCap1Status"));
}//end onClick function
});//end setOnClickListener
非常感谢您的帮助。
我认为它已启用,因为您的应用程序重新启动,没有服务,什么都没有,按钮最初没有被禁用。
将 Service
用作 24 小时计时器是个坏主意,您应该改用 AlarmManager
并将 "alarm has been set" 状态保存在 Preference
中。然后根据保存的首选项 enable/disable 按钮。
如果您想保留您正在做的事情,您可以添加此代码以在 onCreate() 和 isMyServiceRunning(SetupTimerPC1.class)
中检查您的服务状态。如果是 运行 那么你可以禁用按钮:
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
我正在创建一个应用程序,它有一个图像按钮,当它被点击时会启动一个服务。该服务包含一个我用作 24 小时计时器的处理程序。启动服务后,该按钮将被禁用,因此无法再次单击。然后,当时间到了时,按钮将再次启用。在应用程序完全关闭之前,这一切都很好。如果应用程序完全关闭,服务将继续正常运行,除非 BroadcastReceiver 出现问题。如果应用程序关闭然后重新打开,即使服务已经运行,也可以单击启动服务的按钮。我不确定为什么在应用程序重新打开时启用了按钮,即使服务仍在运行。
这是我的服务代码:
public class SetupTimerPC1 extends Service
{
Handler handler;
Database data;
Intent i, result;
runGraphics runG;
int bucketLevel = 1, bucketExpTotal = 0, totalWater = 0, bucketExp = 0;
float waterAmt = 0;
int timerCount = 0;
Notification notify;
Notification.Builder builder;
NotificationManager notificationManager;
PendingIntent pendingIntent;
@Override
public IBinder onBind(Intent intent)
{
return null;
}//end onBind function
@Override
public void onRebind(Intent intent)
{
super.onRebind(intent);
}//end onRebing
@Override
public boolean onUnbind(Intent intent)
{
return true;
}//end onUnbind
@Override
public void onCreate()
{
super.onCreate();
//setup 24 hour timer
handler = new Handler(Looper.getMainLooper());
handler.postDelayed(runnable, 2000); //600000 -> wait ten minutes then call runnable
}//end onCreate function
private Runnable runnable = new Runnable()
{
public void run()
{
//get current bucket exp
data = new Database(SetupTimerPC1.this);
data.open();
bucketExp = data.getBucketExp();
data.close();
//check experience for current level
if (bucketExp < 3000)
{
bucketLevel = 1;
}//end if
else if (bucketExp > 3000 && bucketExp < 6000)
{
bucketLevel = 2;
}//end else if
else if (bucketExp > 6000 && bucketExp < 9000)
{
bucketLevel = 3;
}//end else if
else if (bucketExp > 9000 && bucketExp < 12000)
{
bucketLevel = 4;
}//end else if
else if (bucketExp > 12000)
{
bucketLevel = 5;
}//end else if
//give resource based on level
if (bucketLevel == 1)
{
waterAmt += .2;
bucketExp += 1;
}//end if
else if (bucketLevel == 2)
{
waterAmt += .4;
bucketExp += 2;
}//end else if
else if (bucketLevel == 3)
{
waterAmt += .6;
bucketExp += 3;
}//end else if
else if (bucketLevel == 4)
{
waterAmt += .8;
bucketExp += 4;
}//end else if
else if (bucketLevel == 5)
{
waterAmt += 1.0;
bucketExp += 5;
}//end else if
timerCount++;
if (timerCount < 5)//144
{
handler.postDelayed(runnable, 2000); //600000
}//end if
else
{
//pull data
data = new Database(SetupTimerPC1.this);
data.open();
bucketExpTotal = data.getBucketExp();
totalWater = data.getWaterAmt();
data.close();
//add new data to old
bucketExpTotal += bucketExp;
totalWater += (int)waterAmt;
//push data
data.open();
data.bucketExpEntry(bucketExpTotal);
data.waterAmountEntry(totalWater);
data.bucketLevelEntry(bucketLevel);
data.close();
//send notification that resources have been gained
notifyUser();
i.putExtra("polarCap1Stat", true);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
handler.removeCallbacks(runnable);
}//end else
}//end run function
};//end runnable
public void notifyUser()
{
//notify user of resource gain
result = new Intent(this, runGraphics.class);
pendingIntent = PendingIntent.getActivity(
SetupTimerPC1.this,
0,
result,
Intent.FLAG_ACTIVITY_NEW_TASK);
notify = new Notification.Builder(getApplicationContext())
.setContentTitle("2023: Water Gained")
.setContentText("Successfully extracted water.")
.setTicker("2023")
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setDefaults(Notification.DEFAULT_SOUND)
.setAutoCancel(true)
.setSmallIcon(R.drawable.alienicon)
.build();
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notify);
}//end notifyUser
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
i = new Intent("polarCap1Status");
i.putExtra("polarCap1Stat", false);
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(i);
return Service.START_STICKY;
}//end onStartCommand function
}//结束SetupTimerPC1类
这是从 BroadcastReceiver 接收布尔值的按钮的代码:
//setup image buttons
polarCap1 = (ImageButton) findViewById(R.id.polarCapButton1);
polarCap1.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
Toast.makeText(getApplicationContext(), "Attempting to Gain Resources", Toast.LENGTH_SHORT).show();
if (polarCap1.isEnabled() && appSound)
{
water = new SoundPool(2, AudioManager.STREAM_MUSIC, 0);
playSound = water.load(runGraphics.this, R.raw.watersound, 1);
//play water sound
water.setOnLoadCompleteListener(new OnLoadCompleteListener()
{
@Override
public void onLoadComplete(SoundPool soundPool,
int sampleId, int status)
{
water.play(playSound, 1, 1, 0, 0, 1);
}//end onLoadComplete
});//end setOnLoadCompleteListener
}//end if
//button cannot be clicked
polarCap1.setEnabled(false);
//start service for timer
startService(new Intent(runGraphics.this, SetupTimerPC1.class));
//stop service for timer
//stopService(new Intent(runGraphics.this, SetupTimerPC1.class));
//broadcast receiver to allow button to be clicked again
mMessageReceiver1 = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
clickOnOff1 = intent.getBooleanExtra("polarCap1Stat", false);
polarCap1.setEnabled(clickOnOff1);
updateScores();
}//end onReceive function
};
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageReceiver1, new IntentFilter("polarCap1Status"));
}//end onClick function
});//end setOnClickListener
非常感谢您的帮助。
我认为它已启用,因为您的应用程序重新启动,没有服务,什么都没有,按钮最初没有被禁用。
将 Service
用作 24 小时计时器是个坏主意,您应该改用 AlarmManager
并将 "alarm has been set" 状态保存在 Preference
中。然后根据保存的首选项 enable/disable 按钮。
如果您想保留您正在做的事情,您可以添加此代码以在 onCreate() 和 isMyServiceRunning(SetupTimerPC1.class)
中检查您的服务状态。如果是 运行 那么你可以禁用按钮:
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}