androidとiOSのネイティブアプリでplaceholderを使う
メモ。
■iOS
[textField setPlaceholder:@"(^o^)"];
■android
editText.setHint("(^o^)");
TrackBack URL :
Comments (0)日々勉強
メモ。
[textField setPlaceholder:@"(^o^)"];
editText.setHint("(^o^)");
TrackBack URL :
Comments (0)まず、コミットのハッシュ値を調べる
gitx
gitxを入れていない場合は以下のコマンドで調べる。
git log --all --graph
以下のコマンドで一度チェックアウトしたあとブランチを切った後、元のブランチをチェックアウトする。
git checkout 1234567 git branch -a git checkout -b forgetbranch git checkout master
addしてないファイルとかあると少し面倒になる。
TrackBack URL :
Comments (0)サービスには2種類の起動方法がある。
package info.justoneplanet.android.sample.service;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.widget.Toast;
public class ServiceActivity extends Activity {
private Intent mIntent;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// ブロードキャストレシーバの設定(サービスには直接関係しない)
IntentFilter filter = new IntentFilter(SampleService.ACTION);
registerReceiver(new ServiceReceiver(), filter);
}
@Override
public void onResume() {
super.onResume();
// サービスの起動
mIntent = new Intent(this, SampleService.class);
startService(mIntent);
}
@Override
public void onPause() {
super.onPause();
// サービスの停止
stopService(mIntent);
}
/**
* テスト用のブロードキャストレシーバ<br>
* 実行されるとToastを表示する
* @author justoneplanet
*/
private class ServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "hello", 200).show();
}
}
}
package info.justoneplanet.android.sample.service;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class SampleService extends Service {
public static final String ACTION = "SampleService.ACTION";
private Timer mTimer;
/**
* サービスが一番初めに作られたときに実行される
*/
@Override
public void onCreate() {
super.onCreate();
mTimer = new Timer();
Toast.makeText(getApplicationContext(), "onCreate", 1000).show();
}
/**
* サービスがスタートするごとに実行される<br>
* 但しこのメソッドは2.0以降は非推奨でonStartCommandを使うことが推奨されている
*/
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
hello();
Toast.makeText(getApplicationContext(), "onStart", 1000).show();
}
/**
* サービスが無効になり取り除かれるときに実行される
*/
@Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel();
Toast.makeText(getApplicationContext(), "onDestroy", 1000).show();
}
/**
* クライアントで登録したBroadcastReceiverに対してIntentを送る
*/
public void hello() {
mTimer.schedule(
new TimerTask() {
@Override
public void run() {
sendBroadcast(new Intent(ACTION));
}
},
200,
2000
);
}
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "onBind", 1000).show();
return null;
}
}
stopServiceを呼ばずにアプリを終了した場合は、バックグラウンドで動き続ける。
package info.justoneplanet.android.sample.service;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.widget.Toast;
public class ServiceActivity extends Activity {
private Intent mIntent;
private SampleService mSampleService;
/**
* サービスをモニタリングするインターフェース<br>
* 状態に応じて各メソッドがinvokeされる
*/
private ServiceConnection conn = new ServiceConnection() {
/**
* サービスとの切断時に呼ばれる
*/
@Override
public void onServiceDisconnected(ComponentName name) {
Toast.makeText(getApplicationContext(), "onServiceDisconnected", 1000).show();
}
/**
* サービスとの接続時に呼ばれる
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Toast.makeText(getApplicationContext(), "onServiceConnected", 1000).show();
mSampleService = ((SampleService.LocalBinder)service).getService();
mSampleService.hello();
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// ブロードキャストレシーバの設定(サービスには直接関係しない)
IntentFilter filter = new IntentFilter(SampleService.ACTION);
registerReceiver(new ServiceReceiver(), filter);
}
@Override
public void onResume() {
super.onResume();
// サービスの起動
mIntent = new Intent(this, SampleService.class);
bindService(mIntent, conn, Context.BIND_AUTO_CREATE);
}
@Override
public void onPause() {
super.onPause();
// サービスの停止
unbindService(conn);
}
/**
* テスト用のブロードキャストレシーバ<br>
* 実行されるとToastを表示する
* @author justoneplanet
*/
private class ServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "hello", 200).show();
}
}
}
package info.justoneplanet.android.sample.service;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;
public class SampleService extends Service {
public static final String ACTION = "SampleService.ACTION";
private Timer mTimer = new Timer();
/**
* ActivityでサービスのインターフェースにアクセスするためのBinder
* @author justoneplanet
*/
public class LocalBinder extends Binder {
public SampleService getService() {
return SampleService.this;
}
}
private IBinder mIBinder = new LocalBinder();
/**
* バインドされた時に実行される
*/
@Override
public IBinder onBind(Intent intent) {
Toast.makeText(getApplicationContext(), "onBind", 1000).show();
return mIBinder;
}
/**
* バインドが解除されtrueを返した後、再度バインドすると実行される
*/
@Override
public void onRebind(Intent intent) {
Toast.makeText(getApplicationContext(), "onRebind", 1000).show();
}
/**
* バインドが解除されたときに実行される
*/
@Override
public boolean onUnbind(Intent intent) {
Toast.makeText(getApplicationContext(), "onUnbind", 1000).show();
mTimer.cancel();
return true;
}
/**
* クライアントで登録したBroadcastReceiverに対してIntentを送る
*/
public void hello() {
mTimer.schedule(
new TimerTask() {
@Override
public void run() {
sendBroadcast(new Intent(ACTION));
}
},
200,
2000
);
}
}
TrackBack URL :
Comments (0)Thread thread = new Thread();
以下のようにすることで互いに別スレッドで動作するプログラムを記述できる。
class PingPong extends Thread {
private String mWord;
private int mDelay;
public PingPong(String word, int delay) {
mWord = word;
mDelay = delay;
}
@Override
public void run() {
try {
for(;;) {
System.out.println(mWord);
Thread.sleep(delay);// 自身が実行されているスレッドで次の時間まで待つ
}
}
catch(InterruptException e) {
return;// スレッドを終了させる
}
}
// スタートする
public static void main(String[] args) {
new PingPong("ping", 33).start();
new PingPong("PONG", 99).start();
}
}
但し、以下のようにRunnableを使った記述のほうが一般的ではある。
Runnableインタフェースを実装しThreadにセットすることができる。
class RunPingPong extends Runnable {
private String mWord;
private int mDelay;
public PingPong(String word, int delay) {
mWord = word;
mDelay = delay;
}
@Override
public void run() {
try {
for(;;) {
System.out.println(mWord);
Thread.sleep(delay);// 自身が実行されているスレッドで次の時間まで待つ
}
}
catch(InterruptException e) {
return;// スレッドを終了させる
}
}
// スタートする
public static void main(String[] args) {
Runnable ping = new RunPingPong("ping", 33);
Runnable ping = new RunPingPong("PONG", 99);
new Thread(ping).start();
new Thread(pong).start();
}
}
コンストラクタでスレッドを開始させるとコンストラクタが実行される前にスレッドがオブジェクトのフィールドにアクセスできてしまうため危険である。
class PrintServer implement Runnable {
private final PrintQueue q = new PrintQueue();
public PrintServer() {
Runnable service = new Runnable() {
}
new Thread(this).start();
}
@Override
public void run() {
for(;;) {
realPrint();
}
}
public void print(Print job) {
q.add(job);
}
public void realPrint(Print job) {
// 実際の処理
}
}
一般的には以下のように使用される。
class PrintServer {
private final PrintQueue q = new PrintQueue();
public PrintServer() {
Runnable service = new Runnable() {
@Override
public void run() {
for(;;) {
realPrint();
}
}
}
new Thread(service).start();
}
public void print(Print job) {
q.add(job);
}
public void realPrint(Print job) {
// 実際の処理
}
}
スレッドは生成された時に自身への参照を自身のThreadGroupに保持する。
全てのオブジェクトはロックを持っている。そのロックはsynchronizedメソッドやsynchronized文を使用することにより獲得したり解放したりできる。
以下の例では、synchronizedされたアクセサによって残高が同期なしに修正できないように保護されている。
public class BankAccount {
private long number;
private long balance;// 残高
public BankAccount(long initialDeposit) {
balance = initialDeposit;
}
public synchronized long getBalance() {
return balance;
}
public synchronized long deposit(long amount) {
balance += amount;
}
}
フィールドが外部から直接アクセス可能であった場合は同期を取る必要がない。
オブジェクトが生成される時だけ実行され新たなオブジェクトを生成する際には1つのスレッド内だけで実行される。
staticなフィールドのデータがスレッド間で共有されている場合、staticでsynchronizedされたメソッドからアクセスする必要がある。この時、自身に関連付けられたClassオブジェクトに対してロックがかかるが、synchronizedされたメソッドに対してのinvokeのみブロックの対象となる。
以下のようにすることで現在のスレッドがオブジェクトに対してロックを保持しているか判定できる。
Thread.holdLock(this);
以下のようにすることでカレントオブジェクトではなく任意のオブジェクトに対してのロックを獲得できる。但し、exprはオブジェクトの参照を返す必要がある。
synchronized(expr) {
statements
}
synchronizedメソッドはthisへの参照を伴うsynchronized文であり省略した表現である。
public static void abs(int[] values) {
synchronized(values) {
for(int i = 0; i < values.length; i++) {
if(values[i] < 0){
values[i] = -values[i];
}
}
}
}
エンクロージングオブジェクトに対して内部オブジェクトが同期を取る。
public class Outer {
private int data;
public class Inner {
void setOuterData() {
synchronized(Outer.this) {
data = 1;
}
}
}
}
コンストラクタ内で使用される。
class Body {
Body() {
synchronized(Body.class) {
idNum = nextID++;
}
}
}
クラスに対して適切な同期を設計することは複雑で難しい。
class Util {
private int value;
Util(int initial) {
value = initial;
}
public synchronized add(int x) {
value += x;
System.out.println("value:" + value);
}
}
// Util util = new Util(5);
// thread a : util.add(7);
// thread b : util.add(9);
// 5 12 21
// 5 14 21
class Util {
private static int value = 0;
public synchronized static add(int x) {
value += x;
System.out.println("value:" + value);
}
}
// thread a : Util.add(7);
// thread b : Util.add(9);
// 0 7 16
// 0 9 16
class Util {
private static int value = 0;
public synchronized static add(int x) {
value += x;
System.out.println("value:" + value);
}
public static subtract(int x) {
add(-x);
}
}
条件を待つスレッドは以下のように記述する。
synchronized void doWhenCondition() {
while(!condition) {// whileをifにしてはいけない
wait();
}
// 処理
}
スレッドを(一時)停止させるときにwaitはオブジェクトのロックをアトミックに解放する。(スレッドを停止した場合にロックの解放までがアトミックである)
以下のようにして他のスレッドに通知する。
synchronized void changeCondition() {
// 条件で使用される値の変更処理
notifyAll();// notify();
}
notifyAllを使用するのは以下の条件のときである。
notifyAllを使うことによって(superクラスの)notifyが機能しなくなる可能性がある。
class PrintQueue {
private SingleLinkQueue<PrintJob> queue = new SingleLinkQueue<PrintJob>();
/**
* プリントキューの追加<br>
* 他の待っているスレッドに通知する
*/
public synchronized void add(PrintJob job) {
queue.add(job);
notifyAll();
}
/**
* 他のスレッドが何か挿入するまで待つ
*/
public synchronized PrintJob remove() throws InterruptedException {
while(queue.size() == 0) {
wait();// プリントジョブが追加されるのを待つ
}
return queue.remove();
}
}
currentスレッドは以下の4つのケースまで待つ。
タイムアウトか条件を満たしたか知る必要がある場合は経過時間を計測する必要がある。
ロックが保持されていない時に使用するとIllegalMonitorStateExceptionが投げられる。
実行しているスレッドは以下の条件のどれかまで実行を続ける。
UIスレッドはNORM_PRIORITY+1で実行され、他のスレッドはNORM_PRIORITY-1で実行されることが多い。
ランタイムはデッドロックを検出したり防いだりはしないので、設計でデッドロックの可能性を熟考する必要がある。
ロックを獲得するオブジェクトに関して常に同じ順序でロックを取得するようにする。
以下の条件の時にスレッドは終了する。
キャンセルは割り込みによって実現される。
thread2.interrupt();
thread2では以下のような処理が記述されているとする。
void tick(int count, long pauseTime) {
try {
for(int i = 0; i < count; i++) {
System.out.println(',');
System.out.flush();
Thread.sleep(PauseTime);
}
}
catch(InterruptedException e) {// 他のスレッドから割り込みされた時
Thread.currentThread().interrupt();
}
}
下述の2点に注意して強調しているコードがマルチスレッドを生かして処理できるようにする必要がある。
class CalcThread extends Thread {
private double result;
@Override
publc void run() {
result = calculate();
}
publc double getResult() {
return result;
}
publc double calculate() {
// calc
}
}
class ShowJoin {
public static void main(String args[]) {
CalcThread calc = new CalcThread();
calc.start();
doSomethingElse();
try {
calc.join();// joinが戻ってきたときにはrunが終了されていることが保証される
System.out.println("result is " + calc.getResult());
}
catch(InterruptedException e) {
System.out.println("No answer: interrupted");
}
}
}
最後のユーザスレッドが終了するとデーモンスレッドは消滅させられてアプリケーションは終了する。
同期順序は常にプログラム順序と整合性が取れる。単一のスレッドが更新し多数のスレッドから読み取る場合は同期の必要がないが、多数のスレッドが更新した値にアクセスするような場合は同期が必要でvolatile修飾子を検討する。
TrackBack URL :
Comments (0)以下のコマンドでファイルを編集する。
vi /etc/rc.d/rc.local
以下のような記述があると思う。
touch /var/lock/subsys/local
最終行に起動時に実行したいコマンドを記述する。
ulimit -n 32768 /home/hogehoge/fugafuga/check.sh > /home/hogehoge/fugafuga/result.txt &
TrackBack URL :
Comments (0)そーいやmacで使ってなかったので一応メモ。
cd ~/.ssh ssh-keygen -t rsa -C "user@hogehoge.com" Generating public/private rsa key pair. Enter file in which to save the key (/var/root/.ssh/id_rsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /var/root/.ssh/id_rsa. Your public key has been saved in /var/root/.ssh/id_rsa.pub.
以下のコマンドで内容をメモる。
vi id_rsa.pub
Account Settingsのキーの方にペーストする。
ssh -T git@github.com Hi hogehoge! You've successfully authenticated, but GitHub does not provide shell access.
TrackBack URL :
Comments (0)以下のコマンドでapacheを再起動する。
/etc/init.d/httpd restart
以下のようなメッセージが表示されて再起動できなくなる。
Starting httpd: (98)Address already in use: make_sock: could not bind to address [::]:80
以下のコマンドでポートを使用しているプロセスを調べる。
/usr/sbin/lsof -i | grep http
プロセス番号が表示されるのでkillする。
TrackBack URL :
Comments (0)バッチ処理したい時などに使う技である。
以下のようにしてShellクラスを継承する。基本的にはコントローラと同様にモデルなどが使用できるがコンポーネントについては注意が必要である。
date_default_timezone_set('Asia/Tokyo');
//Configure::write('Config.environment', isset($_SERVER['CAKE_ENV']) ? $_SERVER['CAKE_ENV'] : "development");// コマンドラインから叩いている場合、$_SERVERによる環境分岐ができない
Configure::write('Config.environment', "production");
class RankShell extends Shell
{
public $uses = array(
'Logs',
'Ranks'
);
/**
* 処理を実行する前に読み込むコンポーネントなどを記述する
*/
public function initialize()
{
parent::initialize();
//$this->Email = new EmailComponent($this);// コンポーネント名に注意
}
/**
* ここに記述した処理が実行される
*/
public function main()
{
$this->out("start");
if($result = $this->Log->getRank()){
$this->Ranks->deleteAll();
if($this->Ranks->saveAll($result)){
$this->out("success");
}
else{
$this->out("failed to save");
}
}
else{
$this->out("failed to calc");
}
}
}
以下のようにして実行できるかどうか確認する。
/usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
以下のコマンドを実行してcrontabを編集する。
crontab -e
例えば10時のオヤツを忘れないよう10:15に実行するようにするには以下のようにする。
15 10 * * * /usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
15分ごとに処理をするには以下のように記述する。
*/15 * * * * /usr/bin/php /var/www/hogehoge.justoneplanet.info/cake/console/cake.php calc
以上のようにCakePHPでは非常に簡単にバッチ処理を書くことができる。個人的にはZendFrameworkよりも簡単に感じる。
TrackBack URL :
Comments (0)Chrome 14からWebSocketプロトコルのバージョンがdraft 10になる。現在、Chrome 13はdraft 76で実装されておりdraft 76とdraft 10は互換性がない。WebSocketを使った既存のサービスは壊れるのでdraft 10で実装されたWebSocketServerを探しときの情報をまとめた。
Please note that the new protocol is incompatible with one which Chromium previously supported (draft-ietf-hybi-thewebsocketprotocol-00),
so existing WebSocket-based services may break.
Please upgrade your servers to ones which support HyBi 10.
Existing JavaScript code still works once the protocol version used by the browser and server match.
新しいプロトコルは非互換でなので既存のWebSocketをベースとしたサービスは壊れる。HyBi 10をサポートするようにサーバをアップグレードしてくれ。既存のJavaScriptコードはプロトコルのバージョンが合致すれば動作するだろう。
A WebSocket Draft -08/-09/-10 Implementation for Node.JS
いけちゃうっぽい!broadcastメソッドが存在しないようだが、以下のようにbroadcastメソッドを実装することにした。
var WebSocketServer = require('websocket').server;
WebSocketServer.prototype.broadcastUTF = function(data){
this.connections.forEach(function(connection, i, ary){
connection.sendUTF(data);
});
};
作者の方にも気に入って頂けたようなので近いうちにモジュールに組み込まれるかもしれない。
npm install websocket
以下のようにしてWebSocketサーバをセットアップした。
/**
* extend default WebSocketServer for broadcast
*/
var WebSocketServer = require('websocket').server;
WebSocketServer.prototype.broadcastUTF = function(data){
this.connections.forEach(function(connection, i, ary){
connection.sendUTF(data);
});
};
/**
* websocket server for end users
*/
var server = require('http').createServer(
function(request, response) {
console.log((new Date()) + " Received request for " + request.url);
response.writeHead(404);
response.end();
}
);
server.listen(
eew.env['port'],
function() {
console.log((new Date()) + " Server is listening on port 80");
}
);
wsServer = new WebSocketServer({
"httpServer" : server,
"autoAcceptConnections" : true
});
wsServer.on(
'connect',
function(connection){
console.log((new Date()) + " Connection accepted.");
connection.sendUTF('{"status" : "accepted"}');
}
);
broadcastUTFメソッドを自作した以外は殆どサンプルコードと変わらない。
node.jsには何種類かWebSocket Serverの実装がある。
This will either be done
via node-websocket-protocol (preferable), or
via some kind of hack to the core of node-websocket-server, which is the route I really don’t want to take.
どうやらプロトコルだけ外に出してモジュール化することで対応する意向らしい。しかし、レスポンスが遅いのが気になる。
軽く読んだ限りでは最新の仕様では不具合が発生するようだ。ロングポールなど代替手段が揃っているので有用な選択肢ではある。但し、今回はクライアント側のコードを変更したくないので選択肢から外した。
追記:8/30動作するようになった模様。
node.js用のモジュールが存在しなければ、他の言語のモジュールで対応するという選択肢も考えた。pywebsocketではdraft-ietf-hybi-thewebsocketprotocol-07まで対応している。
Jetty has supported the various WebSocket drafts in the 7.x and 8.x releases.
どうやら最新の実装には対応していないようだ。
draft-ietf-hybi-thewebsocketprotocol-10
WebSocketサーバの実装が比較されているが更新されていないっぽい。
バージョンは適宜アップデートされるだろう。node.jsを選んで良かった。
TrackBack URL :
Comments (0)以前の記事にも書いたんだけど以下のようにしてインストールできる。
su yum install openssl-devel gcc-c++ git make git clone git://github.com/creationix/nvm.git ~/.nvm source ~/.nvm/nvm.sh echo "~/.nvm/nvm.sh" >> ~/.bash_profile echo "nvm use v0.5.0" >> ~/.bash_profile nvm sync nvm install v0.5.0 npm install node-base64
でも使い勝手に慣れなくて結局ソースからビルドしてしまったり。
以下のコマンドでインストールできる。
npm install socket.io
まぁ、一瞬で終わる。
var io = require('socket.io').listen(80);
io.sockets.on(
'connection',// 接続された時
function(socket){// 引数に接続(socket)をセットしてコールバックが実行される
socket.on(
'disconnect',
function () {
io.sockets.emit('message', 'hogehoge');// 全員にpushされる
}
);
}
);
socketのbroadcastメソッドは接続している以外の全てのクライアントに対してpushされる。
サーバを起動させるとクライアント側で読み込むべきscriptが特定の位置に展開される。楽といえば楽。
<script type="text/javascript" src="http://127.0.0.1:80/socket.io/socket.io.js"></script>
<script type="text/javascript">
var socket = io.connect('http://127.0.0.1:80');
socket.on(
'message',
function (data) {
console.log(data);
}
);
</script>
TrackBack URL :
Comments (0)