我正在尝试从我的应用程序发送紧急短信。我必须确保SMS发送成功。
在Android系统启动后并进行检查后,将发送SMS。
因此,我有一个处理BOOT_COMPLETED意向过滤器的服务类。此类进行检查,如果内容正确,则尝试通过另一个“扩展服务”类发送SMS消息
确保成功发送短信后,两个服务(处理启动呼叫的服务和发送短信的服务)都必须退出。
问题1 :如何使我的短信发送功能在超时的情况下被调用,而不会导致应用程序无响应消息?目前,我正在使用此功能(尽管可以正常工作,但我不知道这是否是正确的方法):
Timer mTimer = new Timer(); //wait a small timeout prior to sending the message. mTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { this.cancel(); //I don't want to run the timer more than once sms_sender sms = new sms_sender(); sms.sendSMS(phoneNumber, messageText); } }, 30000, 30000); //run sendSMS() after 30 seconds
问题2 :如何实现sendSMS功能,以便在意识到上一次尝试失败后每30秒重试一次?
问题3 :在知道短信发送成功后,如何停止两种服务?
这是我的代码不起作用:
public class sms_sender extends Service { @Override public IBinder onBind(Intent arg0) { // TODO Auto-generated method stub return null; } final String SENT = "SMS_SENT"; public void sendSMS(final String phoneNumber, final String message, final boolean check_result) { PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(SENT), 0); registerReceiver(new BroadcastReceiver(){ @Override public void onReceive(Context arg0, Intent arg1) { if(!check_result) return; switch (getResultCode()) { case Activity.RESULT_OK: //exit stopSelf(); return; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: case SmsManager.RESULT_ERROR_NO_SERVICE: case SmsManager.RESULT_ERROR_NULL_PDU: case SmsManager.RESULT_ERROR_RADIO_OFF: //try again in 1 minute Timer mTimer = new Timer(); mTimer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { this.cancel(); //no need to run again, if it fails, this exact code will run again sendSMS(phoneNumber, message, true); } }, 60000, 60000); return; } } }, new IntentFilter(SENT)); SmsManager smsManager = SmsManager.getDefault(); smsManager.sendTextMessage(phoneNumber, null, message, sentPI, null); } }
当前,该程序在PendingIntent调用上崩溃。我尝试使用私有成员变量在onCreate方法上实现BroadCastReceiver,以便通过onReceive方法再次调用sendSMS()函数,但是onReceive似乎从未运行。
-编辑-
因此,这是我的最终工作代码。我猜我的情况很特殊,因为它不适用于UI线程。我有一个在启动时运行的广播接收器。我正在尝试发送SMS消息,直到成功发送为止。
此Boot Broadcast Receiver启动服务。这是一些代码:
public class service extends Service{ static public service serv; //member variable. Initializing to null so as to know whether to unregister the service or not private BroadcastReceiver messageSent = null; ... ... @Override public void onStart(Intent intent, int startid) { serv=this; //will use this static variable in order to shutdown the service when the message is successfully sent ... ... if(somethingIsTrue()){ //register receiver messageSent = new sent_message(); registerReceiver(messageSent, new IntentFilter(sms_sender.INTENT_MESSAGE_SENT)); startMessageServiceIntent(messageText, phoneNumber); //function code can be found on accepted answer } } }
send_message类如下:
public class sent_message extends BroadcastReceiver { private Context pubCon; private void startMessageServiceIntent(String message, String receiver) { Intent i = new Intent(pubCon, sms_sender.class); i.putExtra(sms_sender.EXTRA_MESSAGE, message); i.putExtra(sms_sender.EXTRA_RECEIVERS, new String[] { receiver }); pubCon.startService(i); } @Override public void onReceive(Context context, Intent intent) { pubCon=context; switch (getResultCode()) { case Activity.RESULT_OK: //all went OK, stop the service where this is called from service.serv.stopSelf(); break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: case SmsManager.RESULT_ERROR_NO_SERVICE: case SmsManager.RESULT_ERROR_NULL_PDU: case SmsManager.RESULT_ERROR_RADIO_OFF: //try sending the message again after 30s new Handler().postDelayed(new Runnable(){ @Override public void run(){ startMessageServiceIntent(service.messageText, service.phoneNumber); } }, 30000); break; } } }
下面是sms_sender类的简化版本(仅接受一个接收器):
public class sms_sender extends IntentService { public static final String INTENT_MESSAGE_SENT = "message.sent"; public static final String INTENT_MESSAGE_DELIVERED = "message.delivered"; public static final String EXTRA_MESSAGE = "extra.message"; public static final String EXTRA_RECEIVERS = "extra.receivers"; public sms_sender() { super("sms_sender"); } private static class IDGenerator { private static final AtomicInteger counter = new AtomicInteger(); public static int nextValue() { return counter.getAndIncrement(); } } public void sendSMS(String message, String receiver) { SmsManager sm = SmsManager.getDefault(); PendingIntent sentPI = null; Intent sentIntent = new Intent(INTENT_MESSAGE_SENT); int sentID = IDGenerator.nextValue(); sentPI = PendingIntent.getBroadcast(sms_sender.this, sentID, sentIntent, PendingIntent.FLAG_CANCEL_CURRENT); try { sm.sendTextMessage(receiver, null, message, sentPI, null); } catch (IllegalArgumentException e) { System.out.println("Illegal argument"); } } protected void onHandleIntent(Intent intent) { String message = intent.getStringExtra(EXTRA_MESSAGE); String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS); sendSMS(message, receivers[0]); } }
这是我所做的:
public class SMSSender extends IntentService { public static final String INTENT_MESSAGE_SENT = "message.sent"; public static final String INTENT_MESSAGE_DELIVERED = "message.delivered"; public static final String EXTRA_MESSAGE = "extra.message"; public static final String EXTRA_RECEIVERS = "extra.receivers"; public SMSSender() { super("SMSSender"); } private final String TAG = "SendSMS"; private static class IDGenerator { private static final AtomicInteger counter = new AtomicInteger(); public static int nextValue() { return counter.getAndIncrement(); } } private void sendSMS(String message, String[] receivers) { SmsManager sm = SmsManager.getDefault(); ArrayList<String> parts = sm.divideMessage(message); PendingIntent sentPI = null; PendingIntent deliveredPI = null; Intent sentIntent = new Intent(INTENT_MESSAGE_SENT); int sentID = IDGenerator.nextValue(); sentPI = PendingIntent.getBroadcast(SMSSender.this, sentID, sentIntent, PendingIntent.FLAG_CANCEL_CURRENT); Intent deliveryIntent = new Intent(INTENT_MESSAGE_DELIVERED); int deliveredID = IDGenerator.nextValue(); deliveredPI = PendingIntent.getBroadcast(SMSSender.this, deliveredID, deliveryIntent, PendingIntent.FLAG_CANCEL_CURRENT); Log.i(TAG, "sending SMS: parts: " + parts.size() + " message: " + message); if (parts.size() > 1) { ArrayList<PendingIntent> sentIntents = null; ArrayList<PendingIntent> deliveredIntents = null; sentIntents = new ArrayList<PendingIntent>(); deliveredIntents = new ArrayList<PendingIntent>(); for (int i = 0; i < parts.size(); i++) { sentIntents.add(sentPI); deliveredIntents.add(deliveredPI); } for (String receiver : receivers) { try { sm.sendMultipartTextMessage(receiver, null, parts, sentIntents, deliveredIntents); } catch (IllegalArgumentException e) { Log.e(TAG, "illegal receiver: " + receiver); } } } else { for (String receiver : receivers) { try { sm.sendTextMessage(receiver, null, parts.get(0), sentPI, deliveredPI); } catch (IllegalArgumentException e) { Log.e(TAG, "illegal receiver: " + receiver); } } } } @Override protected void onHandleIntent(Intent intent) { String message = intent.getStringExtra(EXTRA_MESSAGE); String[] receivers = intent.getStringArrayExtra(EXTRA_RECEIVERS); sendSMS(message, receivers); }
并使用它:
private void startMessageServiceIntent(String message, String receiver) { Intent i = new Intent(context, SMSSender.class); i.putExtra(SMSSender.EXTRA_MESSAGE, message); i.putExtra(SMSSender.EXTRA_RECEIVERS, new String[] { receiver }); startService(i) }
请注意,它支持多个接收器,此方法未演示/使用。
记住清单中的内容:
<uses-permission android:name="android.permission.SEND_SMS" /> <service android:name="your.package.SMSSender" android:enabled="true" />
(可选)您可以侦听何时发送和/或传递消息:
@Override protected void onCreate() { ... // ---when the SMS has been sent--- private BroadcastReceiver messageSent; // <- stored as a field messageSent = new SentMessage(); registerReceiver(messageSent, new IntentFilter(SMSSender.INTENT_MESSAGE_SENT)); // ---when the SMS has been delivered--- private BroadcastReceiver messageDelivered; // <- stored as a field messageDelivered = new MessageDelivered(); registerReceiver(messageDelivered, new IntentFilter( SMSSender.INTENT_MESSAGE_DELIVERED)); } @Override protected void onDestroy() { // remember to unregister unregisterReceiver(messageSent); unregisterReceiver(messageDelivered ); }
我知道这并不能说明您所有问题的答案,但我希望这已足够。
编辑: 添加了我的messageSent和messageDelivered实现
这些特定于我的实现,因此包括一些您无法使用的代码,仅用于演示。
讯息已发送:
public class SentMessage extends BroadcastReceiver { private final String TAG = "SentMessage"; @Override public void onReceive(Context context, Intent intent) { long _id = intent.getLongExtra(EXTRA_ID, -1); long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1); Log.d(TAG, "SentMessage"); switch (getResultCode()) { case Activity.RESULT_OK: Log.d(TAG, "RESULT_OK"); if (MessageData.sentMessage(_id, protocol_id)) { try { Database.messageSent(_id); } catch (DatabaseRowNotFoundException e) { Log.e(TAG, e.toString(), e); } } break; case SmsManager.RESULT_ERROR_GENERIC_FAILURE: Log.d(TAG, "RESULT_ERROR_GENERIC_FAILURE"); MessageData.postponeMessage(_id); ApplicationData.hasSignal(false); break; case SmsManager.RESULT_ERROR_NO_SERVICE: Log.d(TAG, "RESULT_ERROR_NO_SERVICE"); MessageData.postponeMessage(_id); ApplicationData.hasSignal(false); break; case SmsManager.RESULT_ERROR_NULL_PDU: Log.d(TAG, "RESULT_ERROR_NULL_PDU"); break; case SmsManager.RESULT_ERROR_RADIO_OFF: Log.d(TAG, "RESULT_ERROR_RADIO_OFF"); MessageData.postponeMessage(_id); ApplicationData.hasSignal(false); break; } }
讯息已传送:
public class DeliveredMessage extends BroadcastReceiver { private final String TAG = "DeliveredMessage "; @Override public void onReceive(Context context, Intent intent) { long _id = intent.getLongExtra(EXTRA_ID, -1); long protocol_id = intent.getLongExtra(EXTRA_PROTOCOL, -1); switch (getResultCode()) { case Activity.RESULT_OK: if (_id != -1 && MessageData.deliveredMessage(_id, protocol_id)) { try { Database.messageDelivered(_id); Cursor messageCursor = Database.getCursorByID(MessageOutboxContentProvider.CONTENT_URI, MessageOutboxContentProvider._ID, _id); messageCursor.close(); } catch (DatabaseRowNotFoundException e) { Log.e(TAG, e.toString(), e); } } break; case Activity.RESULT_CANCELED: break; } }
}
我也需要可靠的发送,因此请保留对数据库中所有未决消息的引用,我会经常扫描这些消息以查找延迟的消息。如果没有无线电,消息将被推迟,或者由于某种原因发送失败。
我还结合使用GCM和SMS来使消息尽快传递,同时使用两个通道发送消息。
Edit2: 哦,还可以解决问题,无论如何我们几乎都在那儿:
问题1: 由于使用IntentService,因此发送是在后台完成的。
您只希望发送在延迟后发生一次,因此您应该这样做:
new Handler().postDelayed(new Runnable() { @Override public void run() { // send sms } }, delay);
问题2: 很容易,当您发送的消息广播检测到错误时,请执行上述方法。除了接收者和消息之外,您还可以添加其他信息,计算到目前为止的重试次数,这样您就有机会停止发送/重试循环。
问题3: 发送是一种意图服务,因此发送本身会停止。对于其他服务,我认为最简单的方法是发送公共广播,该广播由您的主要活动接听。这样,您就可以在适当的位置获得该服务并停止该服务。