Asynctask等待短信

时间:2014-07-02 10:08:28

标签: android android-asynctask sms

我正在开发一款应用程序,通过移动设备和硬件设备之间的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个命令。所以,也许我错了,但我认为如果我在第一次测试的接收器上管理所有这些,它可能会使错误的摊位测试出错。

1 个答案:

答案 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;
    }
}