我正在开发一款应用程序,通过移动设备和硬件设备之间的SMS管理M2M通信,用于内部测试程序。
要运行测试,操作员只需触摸一个按钮,应用程序就应该向硬件设备发送一些配置命令消息,并监听每条消息的确认响应。
我已经实现了一个BroadcastReceiver,我在那里监听传入的消息。然后,我使用回调接口将此数据(sender_number,消息,时间)发送到UI活动。
所以我的MainActivity
实现了这个接口,我使用Asynctask来执行测试过程。
这是回调接口的方法,我用它来从UI中的接收器获取数据。
public void gotSms(String num, String msg, long time) {
mNumber = num;
mMessage = msg;
mTime = time;
}
}
这是运行测试程序的Asynctask:
class TestProcedure extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
/*First command*/
String command1 = "DEV123"+"-"+"DEV-NUM1";
/*Send SMS with command*/
smsManager = SmsManager.getDefault();
try {
smsManager.sendTextMessage(mNumber, null, command1, null, null);
} catch (Exception e) {
Log.d("SMS_SENT", "Sending error: "+e.getMessage());
}
//AFTER SMS IS SENT, I NEED TO WAIT TILL THE RECEVIER RECEIVES THE
//CONFIRMATION SMS TO GET THE OK
/*Then the second command is sent*/
String command2 = ...
}
}
我面临的问题是,现在我只能发送命令,我不知道Asynctask如何等待收到的短信以及如何回调可以通知Asynctask短信已经到达。
更新 - &gt;接收者定义
我在清单中声明了接收器:
<receiver
android:name=".SmsReceiver"
android:exported="true" >
<intent-filter
android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
另外,我在SmsReceiver类中声明了回调接口:
public class SmsReceiver extends BroadcastReceiver {
public SmsReceiver(SmsUpdater updater) {
smsUpdater = updater;
}
@Override
public void onReceive(Context context, Intent intent) {
//...
}
public interface SmsUpdater {
void gotSms(String num, String msg, long time, String imei);
}
}
所以在MainActivity中我实现SmsUpdater
并在OnCreate中实例化接收器:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
smsReceiver = new SmsReceiver(this);
//...
}
更新 - &gt;代码修改
在Mike M.的帮助下,我改变了代码中的一些内容。首先是我不再使用Asynctask。我目前的代码如下:
我首先使用此方法从主活动中的片段中获取一些值。此方法也是用户单击开始测试按钮时启动的方法。该测试自动发送3个命令并在发送下一个命令之前等待每个命令的响应。
public void manageConfiguration(String pin, String number, String operator) {
/*Saves values*/
mPin = pin;
mNumber = number;
mOperator = operator;
/*Sends first command*/
configTnum1(pin, number);
}
这就是这种情况下发送命令方法的样子:
public void configTnum1(String pin, String number) {
/*Command generate*/
String command = constructCommand(pin, "DEV+TNUM1", getPhoneNumber());
//The command would look like: DEV1234,DEV+TNUM1,394876354;
/*Sends SMS*/
sendSMS(number, command);
}
当发送此命令时,我应该等待传入的消息,除了给我确认(消息OK或ERROR)之外,它还向我提供有关硬件设备的其他信息,因为它的GPS位置,识别我可能需要在任何时刻使用代码等。
所以,现在我进入临界点。即使我用Mike M。在活动中实现接收器,或者以我的方式使用回调将数据从接收器传递到活动......我进入了我需要的情况管理我如何继续自动测试并发送命令2。
Mike M.建议在同一个接收器中管理它(或者在我的代码中的回调方法中,它会是相同的)。乍一看似乎是一个不错的选择。但我必须解释一下,这个测试并不是我唯一的测试。此测试自动发送3个命令,但在执行此操作后,我有其他屏幕(活动),用户必须执行另一个测试,此时自动发送5个命令。所以,也许我错了,但我认为如果我在第一次测试的接收器上管理所有这些,它可能会使错误的摊位测试出错。
答案 0 :(得分:3)
由于我不知道您实施的所有细节,以下是一个稀疏的轮廓。我自己运行它,然后根据需要填写附带的详细信息,我相信这应该可以根据需要运行。
由于我们已经确定您的应用只需要在运行时收听传入的短信,因此您不需要在清单中注册BroadcastReceiver
。我再次将它作为MainActivity
的内部类,它将接收传入消息的通知,然后将其转发给相应的Fragment
。我把你的上一篇文章更新意味着你担心单独的测试会“混淆”,而且,由于这些测试不能同时运行,这应该不是问题。
在MainActivity
中,我们有以下内容(除样板代码外):
private SmsTestListener listener = null;
private void sendSmsTest(String number, String command, SmsTestListener listener)
{
this.listener = listener;
SmsManager.getDefault().sendTextMessage(number, null, command, null, null);
}
private void notifyIncoming(String message)
{
listener.onSmsTestResponse(message);
}
private BroadcastReceiver receiver = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
// Standard decoding for SMS
Object[] pdus = (Object[])intent.getExtras().get("pdus");
StringBuilder message = new StringBuilder();
SmsMessage messageSegment;
for (int i=0;i < pdus.length;i++)
{
messageSegment = SmsMessage.createFromPdu((byte[]) pdus[i]);
message.append(messageSegment.getDisplayMessageBody());
}
if (isMessageValid(message.toString()))
{
notifyIncoming(message.toString());
}
}
private boolean isMessageValid(String message)
{
// Check that the message is valid
// Here, I've listed the message text for
// the check, but you could also use the
// originating number, etc.
return true;
}
};
我们还需要定义以下界面:
public interface SmsTestListener
{
void onSmsTestResponse(String message);
}
然后,实现上述接口的Fragments
的结构如下:
class FragmentOne extends Fragment implements SmsTestListener
{
private String number = "1234567890";
private String[] commands;
private int commandIndex;
private Button startButton;
private void startSmsTest()
{
// Initialize commands here
// and fire the first one
commands = new String[] { "command1", "command2" };
commandIndex = 0;
fireNextCommand();
}
private void fireNextCommand()
{
// Tell the Activity to send the next message,
// and pass it a reference to the Fragment that
// is running the test
((MainActivity) getActivity()).sendSmsTest(number, commands[commandIndex], this);
}
@Override
public void onSmsTestResponse(String message)
{
// Increment our command counter and if
// we're not finished, fire the next one
commandIndex++;
if (commandIndex < commands.length)
{
fireNextCommand();
}
else
{
Toast.makeText(MainActivity.this, "Test finished", 0).show();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// This is standard; I put it here to show our
// start button initialization
View rootView = inflater.inflate(R.layout.fragment_one, container, false);
startButton = (Button) rootView.findViewById(R.id.button_execute);
startButton.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v)
{
startSmsTest();
}
}
);
return rootView;
}
}