2012年2月27日月曜日

SMSの送受信


AndroidにおいてSMSの送信をしようと思ったらpreinstallされたアプリにIntentを投げるのが一番簡単ではあるが、アプリ内で送信してしまうのもありで、それは結構簡単でした。

こんなかんじ
public class SMSSenderDialog extends Dialog {

    public SMSSenderDialog(Context context) {
        super(context);
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.sms_sender_dialog);
        this.setTitle("SMS sender");
        final EditText phoneNumber = (EditText) findViewById(R.id.phoneNumber);
        final EditText message = (EditText) findViewById(R.id.sms_message);
        
        
        Button btn = (Button)findViewById(R.id.sendSMS);
        btn.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                SmsManager smsManager = SmsManager.getDefault();
                String destinationAddress = phoneNumber.getText().toString();
                String text = message.getText().toString();
                
                smsManager.sendTextMessage(destinationAddress, null, text, null, null);
                dismiss();
            }
            
        });
    }

}


sendTextMessageを書けばいいのだかららくなもんである

受信に関してはAPIdemosに既に記述があって
./ApiDemos/src/com/example/android/apis/os/SmsMessageReceiver.java
./ApiDemos/src/com/example/android/apis/os/SmsReceivedDialog.java
をパクれば一発であった。
SMSについてはかなり好きなように出来そうで、メッセージの内容も好きに見られるので、そこからUIの処理を走らせて通知とかもふつうに出来そうだった。





2012年2月26日日曜日

AndroidでModalなDialog


AndroidでModalなDialogがほしいー。と思ったことがある人も少なくないと思う。
ModalDialogってMFCとかではあったけどAndroidにはない。AndroidだとAlertDialogとかを使ってYES/NOのDialogを表示したとしても、結果を取得するためにListenerを書かなければいけないし、必ず非同期になる。非同期で取得した結果から処理を分岐させたいときには、そのListenerの中で処理を記述しなければならない。こうすると関数のネストが深くなりがちになる。まあ、関数分ければいいだけの話だけど、いちいち他の関数に飛ぶのもなー。ということでModalなDialogが欲しくなる。

ModalDialog dialog = new ModalDialog();
int result = dialog.show();

のように書いたら結果が同期で帰ってくるようなやつ。
で、作ってみようかと思た。

結論だけ書くと無理だった。。。
java.util.concurrent.CountDownLatch
を使ってthread止めればいけんじゃね?とかおもったけど、
mStartSignal.await();
でUIのThread止めちゃうとイベントリスナーのコールバックが帰ってこないのだ。。。
まあ、ListenerもUIスレッドで動いているから当たり前ですよね。。。
やっぱAndroidって動きがシングルスレッドっぽいよね。

ただ、かなりインチキ臭いけど回避策もある。ModalDialogの呼び出しをUIスレッド以外で行えばいいのだ!そうすれば同期でコールできる。
でも呼び出し元はこうなる。

public class ModalDialogActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button btn = (Button) findViewById(R.id.start);
        btn.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View v) {
                final Context c = v.getContext();
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        final int result = ModalDialog.show(c);
                        ModalDialogActivity.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast toast;
                                switch (result) {
                                    case ModalDialog.YES:
                                        toast = Toast.makeText(c, "YES", Toast.LENGTH_SHORT);
                                        break;
                                    case ModalDialog.NO:
                                        toast = Toast.makeText(c, "NO", Toast.LENGTH_SHORT);
                                        break;
                                    case ModalDialog.CANCEL:
                                    default:
                                        toast = Toast.makeText(c, "CANCEL", Toast.LENGTH_SHORT);
                                        break;
                                }
                                toast.show();
                            }
                            
                        });
                    }
                }).start();
            }
            
        });
    }


コールした結果をToastで出すだけなのに、すげー深くなったww
まあ、教訓としてはAndroidではCountDownLatchを極力使わないほうがいいし、もし使うならLooperが絡んでいるThreadでは呼んじゃだめってことくらいか。
まあ、Androidの場合はCountDownLatchを使いたくなる機会ってほぼないとは思うけど。