ナカザンドットネット

それって私の感想ですよね

「ブログを書くまでが勉強会です」を実践して来なかったことへの懺悔

6月もそろそろ終わりますね。
このブログを見てくださってる方々は「なかざん、ブログ書く頻度多くになったなあ」とか思っていただいているかと思います。
それもそのはず。今月は密かに「”ブログを書くまでが勉強会です”実践月間」と位置づけて、できる限り、勉強会に出たことや、日頃調べたりしたことをブログにまとめるように心がけていました。

この記事で今月10個目。6月はあと1週間近くありますから、その間にもう2つほど記事を書けば、月間の記事数は人生トップになります。おそらく、現時点でも記事の文章量だけで言えば人生初の分量を書いていることでしょう。

「”ブログを書くまでが勉強会です”実践月間」は、大成功に終わりそうです。

今月参加した勉強会の記事

2つだけといえば2つだけなんですが、Niigata.pmの記事にスターが沢山ついていることからも分かるように、当日参加した方々から読んでいただいたり、Twitterでシェアしたりしていただけました。

参加者同士がレポ記事を書くことでさらに繋がっていく。勉強会当日に気付けなかったことが、さらに深みを増して自分の糧となる。「ブログを書くまでが勉強会です」という言葉の意味と意義を、初めて実感しています。

自分がやってきた勉強会はどうだったろう

日本Androidの会 新潟支部とか、Corona SDK方面とか、この2年間、ちょこちょことイベントは開いてきましたが、そのレポ記事を書いたことは、ほとんどありませんでした。
主催者がこのザマなので、参加者の方々もブログで感想を書いてくれることは稀でしたし、意義を理解できていなかった僕は呼びかけることすらしたことがありませんでした。

言っちゃえば、僕がブログでレポ記事を書かないということが、きっと僕がやってきた勉強会をインスタントに消費される勉強会に貶めてしまっていたのではないかなと思うのです。楽しさも、熱気も、そのときその場所にいた人たちだけで消費しきってしまう。外にも後にも残る記録がない。記憶の中にしか残らない。そして記憶に残っているだけの情報は、そうそう外には伝わらないし、いつかは薄れていってしまう。
もちろん、参加しなかった人が記事を読んだからって当日の臨場感を体験できるわけではありませんが、それでも伝わるものはあるはずです。そして逆に、参加した人であれば、記事を読んで当日の臨場感を鮮明に思い出すことで、楽しさや熱気を追体験できるのでは。

これまで、たくさんのイベントを終わらせてあげられなかった。正直、後悔してます。

これからの僕が(そして僕らが)やるべきこと

イベントをやったら、楽しさを、熱気を、ブログ記事として「形にして残す」。
主催者はもちろん主催者視点での記事を残すべきだし、参加者にも参加者視点での記事を残してもらえるように呼びかける。


まずは、来月のJSON日の金曜日半分ジョークで企画した勉強会でしたが、思った以上にガチなものになりそうです。
自分で勉強会を企画するのは、たぶん去年の11月以来です。今回からは、レポート記事を書いて、自分が主催する勉強会たちに引導を渡してやります。


ブログを書くまでが、勉強会です。

新潟のRubyistの飲み会(+勉強会)に紛れ込んできました【勉強会編】

新潟の Rubyist で集まりましょう! Ruby に興味があるという方もご参加ください!
新潟の Rubyist が集まるイベント : ATND

これね。
「とりあえず新潟って最近Rubyな人の集まりが全然ないよね。どんな人がいるのか知りたいね」ということで id:jewel12 先生が企画してくれました。

普段から「勉強会の本番は懇親会」論を唱える側の僕ですが、今回は本当に飲み会のほうが本番です。
ただ、初心者が多いということで、昼間にギークハウス新潟で初心者向けの「かんたん♪Ruby講習会」が行われました。

各種資料

こちら→ https://github.com/jewel12/ruby_lecture/

環境

OS 自由
Rubyバージョン 1.9系推奨

OSはWindowsやLinuxが多数派で、珍しいことにMac持ってきてるのが僕だけでした。
Linux使ってた id:saisa6153 先生が「MBPにコーヒーこぼして壊したから今Retina MBP待ちなんですよ!!」とか主張しててマジウケた(外道)

内容

  • 何故、Rubyを使うのか?
  • Rubyの基本的な使い方を写経しながら知る
    • 文法とかの話は少なめ
    • 他の言語で例えるともっと理解が深まりそうな場面も多々あった
    • 知っている言語が少ない人にとってはちょうど良かったかも
  • SinatraHamlでWebプログラミング
    • Hamlはインデントで階層構造を表現する
    • HamlコードをコンパイルするとHTMLになる素敵言語
    • PDF見ながら写経していた俺大勝利
    • 出席簿アプリ作りました

始まる前までの僕が持っていたRubyに関する知識

  • Matzさんが作った
  • 島根がゴリ押ししてる
    • Ruby合宿とか講師陣がガチすぎてやばい
  • RubyVM上で動作する言語
  • 全ての値はオブジェクトである
    • Javaのboolean, char, byte, short, int, long, float, doubleのようなプリミティブ型は存在しない
    • なので「1」のような数値は「数値(1ならInteger)クラスのオブジェクト」であり、「1.to_s」のようなメソッドを持つ
  • 実は新潟で一度盛り上がりそうになったけど立ち消えた歴史がある(後述)
  • 僕が書いたCorona本*1でお世話になっている達人出版会の高橋さんが会長をやっている日本Rubyの会というのがある。
    • RubyKaigi 2011の会期とCorona本の発売日をぶつけちゃって高橋さんには正直スマンカッタと思っている
    • 2011年にITコミュニティではなく一般社団法人として再スタートを切ったらしい

勉強会パートでは1つもこの辺の話が出てこなかったので、僕が知っていたRubyの知識は本当にRubyに関するものだったのか不安になりながら過ごしていました。

新潟とRuby

今、僕がいる会社は新潟産業創造機構(NICO)のお世話になっているわけなんですが、NICOの人から「何年か前に新潟でもRubyの勉強会がちょこちょことあったんだけどね」みたいな話を聞いたことがあって、当時の参加者達はコミュニティ活動もせずにどこへ消えてしまったんだろうという疑問がありました。
ということで、新潟とRubyのキーワードで引っかかる、過去のイベントをピックアップ。

2007/12/01 Ruby勉強会@新潟 第1回のお知らせ *2
2007/12/05 Rubyビジネスセミナー@新潟(Matzさん来てた)
2008/03/15 Ruby勉強会@新潟 第2回のお知らせ
2008/04/19 イケテルrails勉強会@新潟第1回について
2009/01/10 第2回NDS(第1回イケテルRails勉強会@長岡)参加したよ
2009/03/07 朱鷺メッセで「Ruby勉強会@新潟」が開催

簡単に探してみて出てきたのはこれだけ。多いかどうかはわからないけど、けっして少なくはないと思う。2007年末から2009年初めにかけて、新潟ではRubyのセミナーがそれなりに流行っていた、とは言えそう。
そして調べてみると飲み会にいた「いたさん」が当時のRuby振興にかなり貢献していたのがじわじわ見えてくる。あの人只者じゃないと思ってたけど本当に只者じゃなかった・・・!
いたさんみたいな方がいても続かなかったあたり、やっぱり技術者コミュニティを続けていくのって大変なんだなあ、とも思ったりした。

ということで、漏れがあるかも知れませんが今回のが概ね3年ぶりくらいのパブリックなRubyの勉強会になったようです。

今回の勉強会で分かったこと

  • なんか「スクリプト言語的なゆるふわさ」と「Java的なキッチリさ」の間を上手いこと取っている感じの言語なんだなあと思った
    • Luaっぽい文法あるなあと何度か思ったり
    • 隣の id:aokcub さんは「ここPerlっぽい」と何度か言ってた
    • 色んな言語のいいとこもらってきてるんだろうなあ感
  • 数値リテラルから直接メソッド叩くの楽しい
  • シンタックスシュガーに気をつけないと最悪の場合死に至る

勉強会中の疑問点1

「+記号で文字列結合するって話だけど、数値同士を文字列結合したい場合ってどうすんの?」
PerlPHPLuaなどの場合は、加算と文字列結合の演算子を別に用意しているので、この疑問は出てこないんですよね。

# Perlの場合
my $a = 1;
my $b = 2;
print($a.$b); # 12
print($a+$b); # 3
-- Luaの場合
local a = 1
local b = 2
print(a..b) -- 12
print(a+b)  -- 3

Rubyの場合は、+演算子文字列同士なら結合、数値同士なら加算と、ハッキリと役割が分けられています。
(今考えるとRubyの場合は普通の「演算子」だと思っていたこと自体が間違っていた*3のですが・・・)
それまで習っていた内容から僕が出した答えはこれ。

a = 1
b = 2
puts "#{a}#{b}" #=> 12
puts a+b #=> 3

ダサすぎて死にたくなりました。

まさか天下のRuby様が数値の文字列結合ごときにこんなダッサいソリューションしか用意してないわけないので、 id:jewel12 先生に質問してみました。答えはこれ。

a = 1
b = 2
puts a.to_s + b.to_s #=> 12
puts a+b #=> 3

「ダサい版より文字数増えてんじゃん・・・駄目じゃね・・・?」と最初は思ったものでしたが、『数値型もオブジェクト』という文化をまだちゃんと理解しきれていなかった自分を再確認できました。
ちなみにこのあと、飲み会でこの話題になったときに色々と意見を聞いて、ああ、これはこれで正しいんだ、と頷くことになりました。

わかったこと

Rubyは「何」と「何」を+で繋ごうとしているのかを考えることを僕らに強要してくれているのです。
変数に型を指定しない以上、その変数の中身が数値なのか文字列なのか他の何かなのか、実行するまで僕らには分かりません。
例えば、Luaには暗黙の型変換がないので、以下の様なことが起こりえます。(かなりアホな例ですが)

local number1 = 1
local number2 = "two"
-- +してはいけないのに変数名が紛らわしいので間違えて+しちゃう
print(number1 + number2) -- エラー:attempt to perform arithmetic on local 'number2' (a string value)

Rubyでも暗黙の型変換は原則行われないらしいので似たようなことは起こりうるのですが、文字列結合専用の演算子を用意しないことで「2つのオペランドが数値同士か文字列同士だと確実にわかっているとき以外の文字列結合では、to_sメソッドで両方のオペランドを文字列にしてから+しろよ」という文化を生み出しているようです。
Rubyよくできてんな。

勉強会中の疑問点2

よく出てくる|hoge|ってなんぞ
こういうコードですね。

5.times do |i|
    puts i
end

id:jewel12 先生に「この縦棒で囲まれてる変数って何なん?」と質問したら、なんだか実例を色々と見せていただけましたが、途中でlambdaとか使った実例も出てきて、まあみんな白目でしたよね。*4

lambda { |n| n ** 2 } # こんなん

最終的には「イテレータの中身を順次受け取る変数」みたいな理解をしましたが、さて、結局勉強会の中ではこの変数を何と呼ぶのか、名前が出てきませんでした。
名前が無いものを覚えるのはちょっと難しいので、名前を探してみましたよっと。

自分で定義したブロック付きメソッドでブロックを呼び出すときに使います。 yield に渡された値はブロック記法において | と | の間にはさまれた 変数(ブロックパラメータ)に代入されます。
メソッド呼び出し(super・ブロック付き・yield

ブロックパラメータというらしいです。
よし、これで覚えやすくなった(気がする)。

その他気づいて調べたこと

Rubyには、演算子扱いされているが実はメソッドだったりする演算子がある

プログラミングの利便のために一部のメソッド呼び出しと制御構造は演算子形 式をとります。Rubyには以下にあげる演算子があります。
演算子式

Ruby演算子オーバーロードができる」という話を聞いて、「あれ、それってScalaと同じじゃん? ってことは?」と思ってirbを叩いてみました。

1.+(2) #=> 3

なるほどできた。
ついでにもう一つ。

1.methods
# => [:to_s, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, :==, :===, :<=>, :>, :>=, :<, :<=, :~, :&, :|, :^, :[], :<<, :>>, :to_f, :size, :zero?, :odd?, :even?, :succ, :integer?, :upto, :downto, :times, :next, :pred, :chr, :ord, :to_i, :to_int, :floor, :ceil, :truncate, :round, :gcd, :lcm, :gcdlcm, :numerator, :denominator, :to_r, :rationalize, :singleton_method_added, :coerce, :i, :+@, :eql?, :quo, :remainder, :real?, :nonzero?, :step, :to_c, :real, :imaginary, :imag, :abs2, :arg, :angle, :phase, :rectangular, :rect, :polar, :conjugate, :conj, :between?, :nil?, :=~, :!~, :hash, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__] 

うん、四則演算の演算子やらなんやらが、メソッドとして定義されているようですね。
このへん、ググっても決定的なのが出て来なかったんだけど、以下の2つのルールがシンタックスシュガーとして設定されていそう。

  1. 括弧を省略してもよい*5
    • a.b(c, d)を a.b c, d と書いてもいいらしい
    • 引数がない場合の空括弧()を省略していいのも似たような話かなたぶん
  2. メソッド呼び出しの際にドット(.)を省略してもよいものもある*6

誰か実際のところどうなのか教えてください。

まとめ

LL言語に手を出すのは1年前のLua以来なので、色々と新鮮な部分もあり、これまで学んできた内容が助けてくれるところもありと、かなり楽しい感じでした。
Haskellと並行になっちゃうけど、Railsか何かに取り組んでみようかなあ。

たのしいRuby 第3版
たのしいRuby 第3版
posted with amazlet at 12.06.24
高橋 征義 後藤 裕蔵
ソフトバンククリエイティブ
売り上げランキング: 5902

*1:いい加減書き直したいなあ

*2:協力のとこに@masuidriveさんがいる…だと…

*3:RubyScalaとかと同じで「+」もメソッド名

*4:「ラムダってなんだ・・・すごいH本とか読めば分かるのか・・・?」という極論まで出てましたね

*5:コメント欄の情報を受けて修正しました

*6:二項演算子限定ルールかも

Niigata.pm 決起集会にこっそり紛れ込みました

Niigata.pmが正式にpm.orgに登録されたとのことで、お祝いしに行って来ました。

pmとは

地名.拡張子(ex. shibuya.js)の形式の団体名って結構ありますよね。
最初はpmもその手のアレかなと思ってたんですが、

Perl Mongers

の略だそうです。Perl狂。

なかざんPerl書けたっけ

大学1年後期のPerlの課題に躓いてそこから大学をサボりがちになった経緯から、Perlさんには名状しがたい冒涜的かつ理不尽な憎しみを抱いていたりいなかったりします。完全に自業自得です。

書けないけど書けないなりに、新潟のITコミュニティの盛り上げに何か役に立てることないかなーと思って顔を出している感じです。
ほら、他プラットフォームの人もいたほうが話に深みが出たりするじゃん!するじゃん!(必死)

ということで

Perlのイベントに出てきたのにPerlの話題にはほとんど乗れなかったりしましたが、LTはなかなか面白いもの揃いでした。
全体を通してPHPの話題率が高かったのも面白かったです。
特にid:jewel12先生の「プリキュアの最新情報を取得してくるスクリプト」は猫型さんの言うとおり「エンジニアリングとして正しい」と思いました!すばらしい!

あとPerl製のチャットシステム「yancha」はhachioji.pm内で運用されながら開発が進められているそうで、とても興味深いものでした。
あれ普通にの社内チャットとして使えるんじゃないかな。コード貼り付けができるあたり、LingrとかAsakusaSatelliteに近い匂いを感じます。

まとめ

ニセコイ最高。(何の話をしていたのか)

Support Package版ListFragmentにカスタムビューを適用するとsetListShownできなくなる問題とその対策

4ヶ月前にこんなツイートをしたまま放置してましたごめんなさい。書きます。
※ツイートした当時に認識していたものよりも問題が大きかったので、タイトルは少し違ったものになりました

はじめに

これからはFragmentの時代や! と誰が言ったか定かではありませんが、Fragmentの概念が登場してから1年半の月日が経ちそうです。みなさん、Fragment使ってますか?
僕はお仕事でゴリゴリFragment使ってます。ときどき使い方間違っててTLの皆様から失笑を買ったりしておりますがめげません(´;ω;`)ブワッ
で、アプリの中でListFragmentを使う機会というのは割と多いと思うんですが、やはりViewのカスタマイズが必要になってくる場面があると思います。そんな要望に応えるのがこちらの記事。

ListFragment 内で表示する View をカスタマイズするには、
onCreateView() 内で、差し替えたい View をインフレートします。

ListFragment の View をカスタマイズする方法 - adakoda

実は、これをそのまま使うと、ListFragment#setListShown(boolean)が使えなくなってしまいます。
ということで、今回はこの問題への対策となります。

※この問題自体はSupport Package版・3.x Higher版のListFragmentの両方で起こりますが、後者の対応方法は分からないので誰かよろしく

ver.0 元の動作

ソース

MainActivity.java
public class MainActivity extends FragmentActivity implements OnClickListener {

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
   
    Button btnSetAdapter = (Button) findViewById(R.id.btn_set_adapter);
    btnSetAdapter.setOnClickListener(this);

    Button btnToggleListShown = (Button) findViewById(R.id.btn_toggle_listshown);
    btnToggleListShown.setOnClickListener(this);
  }

  @Override
  public void onClick(View v) {

    // リストの中身
    String[] items = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "20" };
    // ListFragment
    SampleListFragment fragment = (SampleListFragment) getSupportFragmentManager().findFragmentById(R.id.f_list);

    switch (v.getId()) {
    case R.id.btn_set_adapter:
      // ListAdapterをセット(初期表示のProgressBarはここで消える)
      fragment.setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, items));
      break;
    case R.id.btn_toggle_listshown:
      // リストを消してProgressBarを表示する
      fragment.setListShown(isListShown); 
      isListShown = !isListShown;
      break;
    }
  }
}
SimpleListFragment.java
public class SampleListFragment extends ListFragment {

}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent" >

  <fragment
    android:id="@+id/f_list"
    android:name="net.nkzn.android.sample.v4.customlist.SampleListFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/btn_toggle_listshown" />

  <Button
    android:id="@+id/btn_set_adapter"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:text="set adapter" />

  <Button
    android:id="@+id/btn_toggle_listshown"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_above="@+id/btn_set_adapter"
    android:layout_alignParentLeft="true"
    android:text="toggle ListShown" />

</RelativeLayout>

画面

起動時

f:id:Nkzn:20120614210424p:image:w320

set adapterボタンを押下

f:id:Nkzn:20120614210442p:image:w320

toggle ListShownボタンを押下

f:id:Nkzn:20120614210424p:image:w120 f:id:Nkzn:20120614210442p:image:w120

解説

初期表示時からListAdapterをセットするまでの間、ProgressBarが自動でぐるぐる回っててくれます。
一度Adapterをセットしたあとは、ListFragment#setListShown(boolean)で以下の動作を切り替えられます。

false リストを隠してProgressBarを出す
true リストを出してProgressBarを隠す

そして余談ですが何も書かなくても動くListFragmentさんある意味すげえ。

ver.1 Viewをカスタマイズ

あだこだ先生の言うとおりに、以下のコードを足したり変更したりしました。
※背景画像やピンはヒバナさんからいただきました。

ソース

SampleListFragment.java
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
  View view = inflater.inflate(R.layout.custom_list_layout, container, false);
  return view;
}
custom_list_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@drawable/tile_bg" >

  <!-- タイトル付けてみた -->
  <TextView
    android:id="@+id/tv_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:drawableLeft="@drawable/pin"
    android:drawablePadding="8dp"
    android:gravity="center_vertical"
    android:text="カスタマイズサンプル"
    android:textAppearance="?android:attr/textAppearanceMedium" />

  <!-- ListView用(idは定義済みのandroid:list)-->
  <ListView android:id="@id/android:list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:layout_below="@+id/tv_title"
    android:drawSelectorOnTop="false" />
    
  <!-- アイテムが空の場合に使用するテキスト(idは定義済みのandroid:empty)-->
  <TextView android:id="@id/android:empty"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@id/android:list"
    android:text="No data" />

</RelativeLayout>

画面

起動時

f:id:Nkzn:20120614211324p:image:w320

set adapterボタンを押下

f:id:Nkzn:20120614211444p:image:w320

toggle ListShownボタンを押下

f:id:Nkzn:20120614211601p:image:w320

解説

哀しいことその1:ListAdapterのセット前にぐるぐるしてくれません。
哀しいことその2:setListShownすると落ちます。

ver.1で何が起きたのか

エラーメッセージ

FATAL EXCEPTION: main
java.lang.IllegalStateException: Can't be used with a custom content view
  at android.support.v4.app.ListFragment.setListShown(ListFragment.java:282)
  at android.support.v4.app.ListFragment.setListShown(ListFragment.java:258)
  at net.nkzn.android.sample.v4.customlist.MainActivity.onClick(MainActivity.java:38)
  at android.view.View.performClick(View.java:2604)
  at android.view.View$PerformClick.run(View.java:9314)
  at android.os.Handler.handleCallback(Handler.java:587)
  at android.os.Handler.dispatchMessage(Handler.java:92)
  at android.os.Looper.loop(Looper.java:130)
  at android.app.ActivityThread.main(ActivityThread.java:3691)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:507)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
  at dalvik.system.NativeStart.main(Native Method)

Can't be used with a custom content view

ListFragment#setListShownはカスタマイズしたViewでは使えませんよ」と。

なんか無理らしい

じゃあ諦めようか。

やっぱAndroidといえばコードリーディングっしょ!

ソースコード探訪

無理って言われたからって諦めてたらプログラマーやってられないんで、無理を道理でひっくり返している前例を探しに行きましょう。つまり、「本来のListFragmentはsetListShownできてるんだから、ListFragmentだけがやってる方法があるはずだ!」というわけです。
Support Packageの中にある本家ListFragmentをさくっと参照しちゃいましょう。

$ANDROID_SDK/extras/android/support/v4/src/java/android/support/v4/app/ListFragment

なんかonCreateViewの中身が色々とアレな様子が御覧いただけましたでしょうか。INTERNAL_HOGEHOGE_IDさんたちがキモのようです。

ver.2 既に出来上がったものがこちらになります。

ソース

SampleListFragment.java
public class SampleListFragment extends ListFragment {

  /** おまじないの材料1 */
  private static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
  /** おまじないの材料2 */
  private static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;
	
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.custom_list_layout, container, false);

    // ----------おまじないここから----------
    ProgressBar pBar = (ProgressBar) view.findViewById(android.R.id.progress);
    LinearLayout pframe = (LinearLayout) pBar.getParent();
    pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);

    ListView listView = (ListView) view.findViewById(android.R.id.list);
    listView.setItemsCanFocus(false);
    FrameLayout lFrame = (FrameLayout) listView.getParent();
    lFrame.setId(INTERNAL_LIST_CONTAINER_ID);
    // ----------おまじないここまで----------
	
    return view;
  }	
}
custom_list_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical"
  android:background="@drawable/tile_bg" >

  <TextView
    android:id="@+id/tv_title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="8dp"
    android:drawableLeft="@drawable/pin"
    android:drawablePadding="8dp"
    android:gravity="center_vertical"
    android:text="カスタマイズサンプル"
    android:textAppearance="?android:attr/textAppearanceMedium" />

  <FrameLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <ListView android:id="@id/android:list"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:paddingLeft="16dp"
      android:paddingRight="16dp"
      android:drawSelectorOnTop="false" />
  </FrameLayout>
  
  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:visibility="gone" >
    <ProgressBar
        android:id="@android:id/progress"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
  </LinearLayout>
    
  <!-- アイテムが空の場合に使用するテキスト(idは定義済みのandroid:empty)-->
  <TextView android:id="@id/android:empty"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:text="No data" />

</LinearLayout>

画面

起動時

f:id:Nkzn:20120614215720p:image:w320

set adapterボタンを押下

f:id:Nkzn:20120614215757p:image:w320

toggle ListShownボタンを押下

f:id:Nkzn:20120614215720p:image:w120 f:id:Nkzn:20120614215757p:image:w120

解説

(*´ω`*)むふー。
要点を挙げます。

  • カスタムレイアウトxml
    1. ListViewをFrameLayoutで囲む(width/height重要)
    2. ProgressBarをLinearLayoutで囲む(width/height重要)
  • ListFragment#onCreateView
    1. ListViewを囲んだFrameLayoutに0x00ff0002というIDを振る
    2. ProgressBarを囲んだLinearLayoutに0x00ff0003というIDを振る

これだけで、ListFragment#setListShownがカスタムレイアウトでも使えるようになります。

まとめ

ListFragmentさんが本来扱いたいIDやレイアウトを配置・設定しておく、というのが今回の肝でした。
人間側としてはかなり釈然としませんが、まあ動くので仕方ない。あとemptyさんがちゃんと動くか微妙。
しかし3.x Higherではどうすればいいんだろうなあ。


GitHubでJPP用のオレオレTokenConverterを公開しました

あるkeyに対して、string値、string配列のどちらが割り振られるかわからない場合に利用します。
JPPUtils - Utilities for JsonPullParser

仕事で使うJSONが普通のJPP(JsonPullParser)だと対応しきれない感じだったので作ってみました。

概要

今回作ったオレオレTokenConverterのルールは以下になります。

  • string値 -> サイズ1の ArrayList
  • string配列 -> デフォルトと同じ挙動(のつもり)
  • 空配列 -> サイズ0の ArrayList(デフォルトと同じ(ry)
  • 該当のkeyが存在しない -> null

要は面倒だから全部Listにぶち込めヒャッハーってことですね!素敵!

詳細

まず、こんなPOJO(JPPアノテーション済み)があったとします。

@JsonModel(decamelize=true)
public class Item {

	@JsonKey
	List<String> valueList1;
	
	@JsonKey
	List<String> valueList2;

	public List<String> getValueList1() {
		return valueList1;
	}

	public void setValueList1(List<String> valueList) {
		this.valueList1 = valueList;
	}

	public List<String> getValueList2() {
		return valueList2;
	}

	public void setValueList2(List<String> valueList2) {
		this.valueList2 = valueList2;
	}
}

このPOJOでマッピングするJSONが以下のように複数パターンある場合、普通のJPPでは対処できません。

// パターン1 - 両方string配列(今回のPOJOならば問題ない)
{
	"value_list1": [
		"hoge1",
		"fuga1"
	],
	"value_list2": [
		"hoge2",
		"fuga2"
	]
}

// パターン2 - 片方string配列、片方string値(string値のパースでエラー発生)
{
	"value_list1":"hoge1",
	"value_list2": [
		"hoge2",
		"fuga2"
	]
}

// パターン3 - 両方ともstring値(string値のパースでエラー発生)
{
	"value_list1":"hoge1",
	"value_list2":"fuga2"
}

// パターン4 - 片方空配列、片方string配列(今回のPOJOならば問題ない)
{
	"value_list1": [],
	"value_list2": [
		"hoge2",
		"fuga2"
	]

}

// パターン5 - key自体が無い(これはJPPのデフォルトでnull値が割り当てられる)
{
	"value_list1":"hoge1",
}

今回の問題は、「受け皿であるPOJO側では一つの型でしか受け取れないのに、JSON側の型はstring配列、空配列、string値のいずれかに柔軟に変更される」ということでした。
幸い、JsonPullParserではパースのためのルールを自前でカスタマイズするTokenConverterの仕組みがありますので、そちらを使って今回の問題を解決することにしました。

使い方

  1. https://github.com/Nkzn/JPPUtils/downloads から最新版のjarを落としてくる
  2. jarにパス通す
  3. 以下のようにstring値が来るかstring配列が来るか分からないフィールドのアノテーションにconverterオプションで指定すればOK
@JsonModel(decamelize=true)
public class Item {

	@JsonKey(converter=String2ListConverter.class)
	List<String> valueList1;
	
	@JsonKey(converter=String2ListConverter.class)
	List<String> valueList2;

	public List<String> getValueList1() {
		return valueList1;
	}

	public void setValueList1(List<String> valueList) {
		this.valueList1 = valueList;
	}

	public List<String> getValueList2() {
		return valueList2;
	}

	public void setValueList2(List<String> valueList2) {
		this.valueList2 = valueList2;
	}
}

感想

@さんと@さんのTokenConverterを見よう見まねしながら作ってみましたが、まあ何とか作れるもんですね。
こっそりとMaven3とJUnit4によるテスト&ビルド環境も整えて作ってみました。むしろ今回はそちらのほうが勉強になったかも。
Integer2ListConverterとか作ってみるのも面白いかも知れませんね。(BooleanはJSの仕様上カオスなことになりそうな予感がするのでパス)
ご意見などありましたら@までどうぞ。ご要望はpull requestで!

「会津大×学生プレゼン」について思うところ

Facebookでこんなの見つけました。

弊部の北澤がプレゼンテーション勉強会を開催します!
前にでてしゃべるのが苦手なあなたに参加をお待ちしております!
詳細と参加表明はこちらから
http://bit.ly/KTRKLn
Aizu Entrepreneurs Club(会津大学起業部)

「こういうのって、Aizu.LTでも開催できないのかな?」という思いつきと、「いや、ちょっと違うな」という考えが浮かんだりしました。今回はその『ちょっと』を掘り下げるために筆を取った感じの記事です。
考えながら思ったこと書いてるので突っ込みどころ満載な気がするね!

プレゼンってなんだろね

時と場合によって意味合いが異なってくるとは思いますが、「プレゼンテーション」という行為の根幹にあるのは、誰かに何かを伝えるというただ一点だと思います。
プレゼンテーションは、たった今『行為』と表現したとおり、行動であり、手段であり、ツールです。誰かに何かを伝えるための手段、またはその手段を行使するのがプレゼンテーションです。
ということは、プレゼンは目的ではありません。つまり、目的は別に存在しますし、色んな目的が存在し得るということです。

  • 新しい事業計画を出資者に伝える
  • 新しい企画を経営者に伝える
  • 案件の実現案を顧客に伝える
  • 事業が失敗した理由と改善案を伝える
  • 前年度の決算結果を社員に伝える
  • 最新技術の概要を伝える
  • 最近ハマったゲームの魅力を伝える
  • 腐女子視点から見た今期のスーパー戦隊の展望を伝える
  • 唐揚げの美味しい作り方を伝える
  • 美味しいコーヒー豆の選び方を伝える
  • 豆から美味しいコーヒーを淹れる方法を伝える

目的も、内容も、様々なものが存在し得る以上、プレゼンそのものが目的になることはありえません。
プレゼンは、ツールです。

面白いプレゼン、上手なプレゼン

突然ですが、皆さんが憧れるプレゼンターは誰ですか?
スティーブ・ジョブズと答える人はきっと多いのでしょうね。僕もジョブズに憧れる一人です。一応。
さて、日本人限定だと誰になるでしょうか。
僕は陣内智則に憧れています。


・・・え?


うん。陣内智則


いや、ほら、だって「大画面を使って」「テンポよく」「アイデアを伝える」って点では、間違いなくプレゼンじゃん?


というのは冗談として。
僕の独断と偏見では、「良いプレゼン」には『面白いプレゼン』と『上手なプレゼン』というのが存在します。

面白いプレゼン 内容が楽しい/興味深いもの
上手なプレゼン 内容に関係なく演出(間の取り方や話の流れの順番)が上手いもの

これらは両立しうるものですので、敢えて分ける必要も無いのかも知れませんが、敢えて分けたのにはもちろん理由があります。
前者は良いネタを用意できるかどうかの運と巡り合わせとインスピレーションの賜物であるのに対し、後者は完全にテクニックです。
つまり、「上手なプレゼン」は訓練次第で誰にでもできるはずですし、テクニックを身に着けた上で「面白いプレゼン」を行えば、それは本当に「良いプレゼン」になることでしょう。

エンターテインメント性

陣内智則の例で話しそこねましたが、プレゼンにはエンターテインメント性が必要だと思っています。
つまり、聞き手が「面白い」だとか「わくわくする」だとか、その手の感情を持ちながらプレゼンに没入する状況づくりがどこまでできるかどうかという話です。
これは「面白い『だけの』プレゼン」でも起こりえますし、「上手な『だけの』プレゼン」でも起こりうるとは思いますが、両方が合わさった時にこそ、プレゼンはエンターテインメント足りうるのかなとも思います。
つまり陣内智則は最高のプレゼンターです。(たぶん違う)

会津大の中での住み分け的ななにか

さて、ようやく会津大の話に戻ります。

Aizu.LTのプレゼン

発表テーマは「自由」。
例えば、コーヒーの美味しい入れ方から、ちょっとマニアックなプログラミング言語の紹介まで何でも発表していただけます。

Aizu.LT

僕が第1回から参加しているAizu.LTですが、「テーマ自由」が最大の特徴かと思います。
要は、発表者が好きなものを発表していい。聴講者が面白いと思うかどうかではなく、発表者が話したいことを話していい。そういうイベントです。
このやり方だと、自ずからニッチ路線になるんですよね。だって人間、一人ひとりの趣味嗜好が違って当たり前だもの。
それがいけない、というわけではないです。
以前から後輩たちには何度も言っていることですが、この機会にここにも書きます。

学生が青春を消費して「何か」をしているのなら、それはきっと誰かの心に響く。
サークル活動でも構わない。日々の生活のちょっとした工夫でもいい。なんなら引きこもってゲームしながら見つけた必勝攻略法だっていいだろう。
それを聞いた人の9割9分に「下らない」と言われることでも、残りの1分が「面白い」と言ってくれたなら、それはきっと、青春の一時を費やしてまで取り組む価値のあることだったのだろう。
だから、話して欲しい。君たちが何をして過ごしているのかを。

これが、僕の内にある「学生がテーマ自由でLTをやる意義」です。別に押し付ける気はないけど、こんな風に思っておいたほうが、喋る人は喋りやすいんじゃないかなと勝手に思ってる。
長岡技大LT部あたりも似たようなノリでやってくれてそうで嬉しい。

独善とニッチじゃビジネスは難しい

さて、アツくAizu.LTの良さを語った後でアレなのですが、オナニーは滅多にお金になりません。(暴言)
要は、Aizu.LTって「面白いプレゼン」の更に狭い分野を突き詰めたものなんですよね。「上手なプレゼン」をする人は@などの数少ない人だけです。内容勝負なので、内容がハズレると最悪の場合死に至る(会場の空気が)。
「上手なプレゼン」はそこまで面白くないものを、さも面白いものであるかのように聞き手に錯覚させるためのテクニックです。
『今まで考えたこともなかったけれど、もしかして自分には今紹介されているコレが、必要なのではないか』と思わせるのが、上手なプレゼンの最低条件です。そういう意味ではジャパネットたかたの高田社長は正しい意味で最強のプレゼンターだと思います。


で、ようやく最初の話に戻れるんですが、会津大学起業部に行かないと学べないプレゼンって「上手いプレゼン」なんだろうな、と思いました。
Aizu.LTでも「プレゼン慣れ」自体はできないこともないんですが、自己研鑽を積まないと上手くならないんですよね。なんていうか本当にお笑い芸人にでもなったような気分になります。ただ、「面白いプレゼン」もあれはあれで場数を踏んでネタ選びの感性を磨くほうの上達を目指すという点で価値があるので、起業部の面々もたまにAizu.LTに来てみてほしいなとか思ったり思わなかったり。


そして、内容の如何に関わらずプレゼンが面白いものに見えるようなテクニックをたくち先生が教えてくれるらしいので、会津大のみんなは是非とも起業部の勉強会に顔を出すといいよ!(超プレッシャーかけてみる)

余談1

起業部を「プレゼンガチ勢」、Aizu.LTを「プレゼンノリ勢」と呼ぼうかと思ったけどやっぱどうでもいいや

余談2

XPCとかIAAAもプレゼン的なことやってたような気がするんだけどよくわかんね

結局この記事まとまったのかな

分からん。どっとはらい

2012/6/15追記

たくち先生がこの記事の内容を取り上げてくれました!

スライド見るだけでもたくち先生がプレゼン上手っぽいのが分かって、調子こいてすいませんでした状態になった(^q^)



はてなブログでのアフィリエイト

はてなブログアフィリエイトできない?

こんなお話を見つけました。

有料版もリリースされたはてなブログですが、アマゾンアソシエイトや、楽天アフィリエイト、Googleアドセンスなど、個人がアフィリエイトを行うことはできるのでしょうか?
はてなブログは、アフィリエイト可能なのですか?

↑の回答を見る限り、

  • 規約上はグレー
  • 技術的には可能

といった雰囲気のようです。

ひとまず本記事では、「俺は有料会員なんだから、せめてAmazonアフィくらいは貼らせてくれ」というスタンスで、貼り方のほうを考えていきたいと思います。怒られたらそのとき考える。

はてなダイアリープラスならシステム側でサポートされてた

↓のように、はてダプラスの設定画面にはちゃんとアフィIDの入力欄があったりしました。
f:id:Nkzn:20120607185639p:image:w400

Google AdSense」「Amazonアソシエイト・プログラム」「楽天アフィリエイト」などはシステムでサポートしているアフィリエイトプログラムです
アフィリエイトをはじめよう - はてな

↑の3つはシステム的にサポートされていたので、IDの設定だけしておけば、普段のブログ運用の中ではアフィリエイト機能の存在自体、考える必要もありませんでした。

はてブロの設定画面には、この手の設定はありません。

asin記法は?

はてな記法の中には、Amazon商品へのリンクを貼るためのASIN記法というものがあります。

isbn/asin記法を使うと、書籍・音楽・映画などの商品に関する情報が集められたasinページへリンクしたり、商品の画像などを日記に表示することができます。
書籍・音楽・映画の紹介リンクを挿入する(isbn/asin記法) - はてなダイアリーのヘルプ

asin記法でも、確かにAmazon製品のリンクを貼ることはできるのですが。

リンク内容を見ていただければ分かる通り、この方法だと「hatena-hamazou-22」に稼ぎを取られてしまいます。(はてなががめついとか、そういう意図はないです。むしろ真っ当。)

しかし困った。今のところお手軽にアフィリンクを貼る手段はなさそうです。

お手軽ではない方法ならどうだろう

ということで、定番はamazletらしいです。

amazletはAmazon.co.jpアフィリエイトを手軽にするツールです
amazletツール

id:naoyaさんが作ったツールらすぃ。fmfm。

セットアップ

ヒント: amazletツールの使い方は 2 つあります。

  1. Amazon.co.jp の個別商品ページでブックマークからワンクリックでアソシエイト・リンクを作成
  2. 個別商品以外のページで起動して、商品名で検索しアソシエイト・リンクを作成

とりあえず1番で使ってみます。
「セットアップ」のリンク先でアフィIDを入力し、「次へ」。
出てきた「amazlet it!」のリンクをブックマークバーにドラッグ&ドロップして準備完了です。

f:id:Nkzn:20120607192605p:plain

こんな状態。

使ってみる

Amazonの商品ページを開いて、さっき作ったamazlet it!のブックマークをクリック。
f:id:Nkzn:20120607193032p:image:w400


上手いこといけば、↑のようにちゃんと出てきます。
元の商品ページのURLによっては上手くいかないことがある気がする。

上手くいくURL例 http://www.amazon.co.jp/dp/4844331744/
上手くいかないURL例 http://www.amazon.co.jp/gp/product/4844331744

productが入ってくるURLは割と最近出てきた仕様なのかな。Amazon内での検索結果とかだと上手くいきやすいです。

ということでレビューなし版を貼り付けてみます。

うん、良い感じ。

実はこれ、内部的には結構コード量が多いのですが。

f:id:Nkzn:20120607194351p:image:w400

特に手間が増えるわけでもないのでいいでしょう。

ということで

公式にアフィリンクを貼る機能が出てくるまでは、これでいこうと思います。