Ruboto: スレッド処理の方法

RubotoでRSSを読み込もうと思ってrequre “rss”をしたらパーサーがおかしいといわれてアプリが落ちてしまった。

代替案として、Rubygemsからsimple-rssというgemをとってきた。
これはエラーにならなかったのだが、stack too largeというよくわからないエラーが出てしまってもうわけがわからなくなった。非同期で処理をするしかデータを取る方法がないのだろうか?(しかしまだRubotoで非同期処理する方法が俺はわかってない。AsyncTaskを継承したらエラーになったし。継承の仕方が悪いのかもしれんが)

そう思っていて、まぁとりあえずAndroidアプリを作る時に必要になるメニュー類の出し方とか先に調べとこうと前回の記事を書いていたのだが、RubotoはRuboto irbのScriptにあるソースを読むのがすごい勉強になりそうだったのでXOOMで見ていたら、JavaのHTTPClientを使って通信しているっぽいのを見つけた。これで通信できるんじゃねーの!?と思ってコードを追いかけた結果、with_large_stack &block というメソッドで囲まれていた(通信部分がブロックで)。

先ほどのsimple-rssでRSSを取得するところがstack too largeで落ちていたのだが、with_large_stackを使えば、そうならないのではないか?と考えた。
結論からいうと、うまくいった。
使い方はこんな感じ。

require "ruboto/util/stack"
.
.
.
# 通信部分をwith_large_stackで囲んでみた。
rss = SimpleRSS.parse with_large_stack{ open('http://slashdot.org/index.rdf') }

with_large_stackメソッドは、src/ruboto/util/stack.rbにある。
stack.rbはそこまで長くないコードなので、載せておく。ちなみにRubotoのバージョンは0.6.0です。

#######################################################
#
# ruboto/util/stack.rb
#
# Utility methods for running code in a separate 
# thread with a larger stack.
#
#######################################################

class Object
  def with_large_stack(opts = {}, &block)
    opts = {:size => opts} if opts.is_a? Integer
    opts = {:name => 'Block with large stack'}.update(opts)
    exception = nil
    result = nil
    t = Thread.with_large_stack(opts, &proc{result = block.call rescue exception = $!})
    t.join
    raise exception if exception
    result
  end
end

class Thread
  def self.with_large_stack(opts = {}, &block)
    opts = {:size => opts} if opts.is_a? Integer
    stack_size_kb = opts.delete(:size) || 64
    name = opts.delete(:name) || "Thread with large stack"
    raise "Unknown option(s): #{opts.inspect}" unless opts.empty?
    t = java.lang.Thread.new(nil, block, name, stack_size_kb * 1024)
    t.start
    t
  end
end

Objectクラスを拡張してどこからでもwith_large_stackを呼べるようにして、これに渡ったブロックはJavaのThreadクラスでうまいこと処理してくれて、例外がなければ戻り値を返してくれるということのようである。

ブロック内でプログレスダイアログの呼出しなども行えば、AsyncTask的なのがすぐにできそうな気がする。
使うときは、

require "ruboto/util/stack"

を忘れないように。


カテゴリー Android, Ruby | タグ | パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です