カテゴリー「Java / Apache」の9件の記事

2014.02.22

ActivityのWidgetを動的に入れ替えるちょっとだけ面倒でない方法

Androidのアプリを作るとき、ひとつのActivityで、状況に応じてWidgetを動的に入れ替えたい場合があります。 一度に全部のボタンは不要で、他のコンテンツの表示領域を広く確保したいときなどですね。

よく、onCreateButtonを動的に生成し、コンテナにaddViewすると説明されているのを見ますが、実際、コード中でインスタンスを生成して見た目に関する設定をするのって、それなりに面倒な作業じゃないかなと思いまして、

Button自体は、main_activity.xml の、しかるべきコンテナ(LinearLayoutなど)に、全部配置しておき、見た目の設定はビジュアルに済ませて、実行時に、removeAllViewsで、一旦全部削除すればよいのです。

以下のような感じ(実際に動かしているコードではないのでお気をつけて)

main_activity.xml

<LinearLayout id="@+id/linearLayout"  ... >
  <Button id="@+id/button1" ... />
  <Button id="@+id/button2" ... />
  <Button id="@+id/button3" ... />
  <Button id="@+id/button4" ... />
</LinearLayout>

MainActivity.java

public class MainActivity extends Activity {
  ViewGroup linearLayout1 = null;
  Button button1 = null;
  Button button2 = null;
  Button button3 = null;
  Button button4 = null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    // find container widget
    linearLayout1 = (ViewGroup)findViewById(R.id.linearLayout1);
    // find each buttons
    button1 = (Button)findViewById(R.id.button1);
    button2 = (Button)findViewById(R.id.button2);
    button3 = (Button)findViewById(R.id.button3);
    button4 = (Button)findViewById(R.id.button4);
    changeState(0);
    //
    // ...
    //
  }
  private changeState(int state) {
    linearLayout1.removeAllViews();
    switch(state) {
    case 0:
      linearLayout1.addView(button1);
      linearLayout1.addView(button2);
      break;
    case 1:
      linearLayout1.addView(button3);
      linearLayout1.addView(button4);
      break;
    }
    //
    // ...
    //
  }
}

LinearLayoutの中身を均等割り付けするように設定しておけば、それなりにお手軽。

派手じゃないけど、堅実な動きですよ。


以下、GitHubのGist試用

ひとつのGist中で、ファイルの順番は入れ替えられないのかな。あと、なんでJavaは8タブにしかならないのか。

2012.02.03

CSVのインポートにStringTokenizerは使えない

本日やらかしていたのでメモ。StringTokenizerは、区切り文字で区切られた文字の断片を返してくれるわけだけど、空文字は無かったことにしてくれるので、CSVファイルからデータをインポートするような処理には使えない(カラムがずれちゃうからね)

StringTokenizer t =
    new StringTokenizer(line, ",");
String[] c = new String[13];
int i = 0;
while (t.hasMoreTokens() && i < 13)
{
  c[i++] = t.nextToken();
}

↑これだけ書いて客先からクレーム受けるわけ。対処法は↓

String[] c = line.split(",", 13);

古い人はStringTokenizerをそのクラス名から使っちゃうケースがあると思う(だってストリングトークナイザーだもの)が、いろいろ不条理だよな。この動きでは使えるケースが見当たらん。

2011.10.07

Aipo5のSQLTemplateを使う理由がわからない

自作ポートレットで com.aipo.orm.query.SelectQuery を使って一覧データを取得していたのだが、抽出条件を少し複雑な(サブクエリが三つも四つも出てくる的な)ものに変更しなければならなくなり、やってられんのでベタなSQLを書いてお茶を濁そうと、com.aipo.orm.query.SQLTemplate(以降AipoのSQLTemplateという)を使うことにした。

しかしどうやらこれがうまく行かない。SelectQueryと同じくデータオブジェクトのリストが取得できるのだが、そこから先のマッピングされた別テーブルのデータオブジェクトを取得できない。

AipoのSQLTemplateは、org.apache.cayenne.query.SQLTemplate(以降cayenneのSQLTemplate)をフィールドに持つラッパークラスなのだが、仕方なくソースを読んでみると、コンストラクタで、このフィールドに対してsetFetchingDataRows(true); とかやっている。つまり、このSQLTemplateではデータをDataRowのリストで取得すると高らかに宣言してるみたいなものですな。DataRowでは連携先のデータを参照できないはずだからそのまんまの挙動。なんだ使えないじゃん。

先に書いたようにAipoのSQLTemplateからはデータオブジェクトのリストが返されるのだが、どうやら(なぜそんなことをするのかは不明だけど)データ取得時に変換しているみたい。このとき、マッピングの情報と能力が失われる(というかDataRowには元からそんな機能はないわけで作り出せない)ようだ。

なにかうまいやり方があるのかもしれないが、調べる時間がもったいないから素直にcayenneのSQLTemplateを使って実装した。多少行数は増えるけど、たいした手間ではなかった。

変更前のソース:AipoのSQLTemplateを使用

String sql = "SELECT * FROM my_data_model ...";
SQLTemplate sqlTemplate = Database.sql(MyDataModel.class, sql);

sqlTemplate.param("foo", "bar");
sqlTemplate.param("hoge", "hogehoge");

ResultList list = sqlTemplate.getResultList();

変更後のソース cayenneのSQLTemplateを使用

String sql = "SELECT * FROM my_data_model ..." ・・・
SQLTemplate sqlTemplate = new SQLTemplate(MyDataModel.class, sql);

Map param = new HashMap();
param.put("foo", "bar");
param.put("hoge", "hogehoge");
sqlTemplate.setParameters(param);

ResultList list = new ResultList();
DataContext dctx = DatabaseOrmService.getInstance().getDataContext();
list.addAll(dctx.performQuery(sqlTemplate));

2011.06.22

Velocity、long値比較が正しくない件

ここ2ヶ月ほどで2,3回遭遇したVTLの不可解な現象。

velocityテンプレートで、数値プロパティを #if で判定しようとすると、値にかかわらず常にfalseになる。long値のプロパティ限定かも?

両辺をダブルコーテーションで括って文字列として比較すればOK。

すっきりしないが、調査の時間ももったいない。やな方法だけど覚えておこう。

2011.06.10

ファイルダウンロード時の日本語ファイル名の文字化け

ファイルダウンロード時、ブラウザが表示するダウンロード確認のダイアログボックスで日本語のファイル名が化けてしまう場合、サーバー側のレスポンスヘッダでブラウザごとにファイル名の指定方法を変える必要がある。(とここに書いてあった)


  protected void doOutput(RunData rundata) 
    throws Exception 
  {
    ParameterParser parser = rundata.getParameters();
    String encoding = parser.getCharacterEncoding();
    parser.setCharacterEncoding("Shift_JIS");
    String filename = parser.getString("filename");
    parser.setCharacterEncoding(encoding);

    //(省略)

    HttpServletRequest request = 
                            rundata.getRequest();
    String agent = request.getHeader("User-Agent");
    agent = agent.toUpperCase();
    if (agent.indexOf("MSIE") > -1) {
      filename = URLEncoder.encode(
                filename, "UTF-8");
    } else
    if (agent.indexOf("FIREFOX") > -1 
    || agent.indexOf("CHROME") > -1) 
    {
      filename = MimeUtility.encodeWord(
                filename, "ISO-2022-JP", "B");
    }
    HttpServletResponse response =
                      rundata.getResponse();
    response.setHeader(
        "Content-disposition",
        "inline; filename=\"" + filename + "\"");

IEの場合はURLエンコード、Firefox、ChromeはMIME-Bエンコーディング。その他のブラウザでは手がないらしいから害の無い名前に変えちゃいましょうということですね。

ちなみに、各ブラウザはレスポンスヘッダに日本語がある場合、これをShift_JISと仮定して読み取るから化けるらしい。レスポンスの日本語エンコーディングが元からShift_JISなら化けないらしい。未確認だけど。つか最近UTF-8しか使わないしなぁ。

パラメータ値に日本語を含むリンクをたどって文字化け

Jetspeed / Turbine の環境でJetSpeedLinkを使ってaddQueryData("japaneseText", "<日本語文字列>")などとして日本語を指定して作成したリンクをたどると、サーバー側でパラメータを取り出したときに文字化けした。

ParameterParserの文字エンコーディングをShiftJISに変更して読み出せばOKでした。なんだ簡単じゃないか。


  protected void doOutput(RunData rundata)
    throws Exception {
    ParameterParser parser =
      rundata.getParameters();
    parser.setCharacterEncoding("Shift_JIS");
    String japaneseText = 
      parser.getString("japaneseText");

  //   (...省略...)

ページはUTF-8なんだけど、ブラウザはShift_JISでURLエンコードしてくるみたいだな。このリンク自体をサーバー側のvelocityテンプレートで(おそらくUTF-8で)作ってるのにヤヤコシイなぁ

2011.06.07

java.lang.Stringの文字列編集メソッドはインスタンスを変更しないな

javaのStringクラスのメソッドのtoUpperCaseなど、ほとんど(全部か?)の文字列編集メソッドは加工後の文字列を返してくるだけで、インスタンスそのものは変更しないんだな。

つまり、


    String s = "abc";
    s.toUpperCase(); 
    // toUpperCaseの戻り値は"ABC"だが
    // s自身は書き換わらない。

だけでは、sは"abc"のままということだ。

javaのStringクラスは固定文字列のクラスであって編集してごちゃごちゃするのはStringBufferクラスの仕事。とわかっているんだが、よく「どっちだっけ?」と迷ってしまうのはワタシだけか?

ちなみにjavadocでは、「この String 内のすべての文字列を大文字に変換しますとなっていて、勘違いして当然かと。toLowerCase然り、replaceAllやreplaceFirstも似たような表現。

一方、replace(char oldChar, char newChar)では、「この文字列内にあるすべての oldChar を newChar に置換した結果生成される、新しい文字列を返します。 」とちょっとあいまいだけど一応正確に書かれているのだが、先の説明と読み比べて間違いを助長してそうな気もするな。

さてconcatはどうだっけ?また迷う。

2011.04.28

velocityの整数演算では演算子前後にスペース入れる

velocityテンプレートの中で整数の引き算を行おうとしたら、ぬるポ出た。困る。

#set($foo=$bar-1)

という風にやっていて、その後$fooを参照してぬるポ。なんでよ。ちなみに足し算はOKだった。

試行錯誤の末、演算子の前後にスペースを入れて、

#set ($foo = $bar - 1)

とすれば、ぬるポが出ない。ああよかった。

おそらく'-'の前後が重要なのだろうと思うけど、細かい検証はしていない。

とりあえず覚え書きまで・・・

2011.04.22

Tomcat再起動直後にvelocimacroが失敗してたが解決した

Velocityマクロ(velocimacro)を定義したvmファイルを、個々のテンプレートファイルへ #parse で取り込んで使用していたら、Tomcat再起動直後の初回アクセス時にだけマクロ展開に失敗していた。

画面表示的には未定義のマクロを使用したときの挙動っぽい。引数のbeanがtoStringされたような状態でVTLがそのまま表示されている。

2回目以降は正常動作するが気持ち悪いし不細工なので、がんばって調べてなんとか解決。各ページで #parse せず、Velocityサービス起動時のライブラリとして読み込んでもらえばOKでした。

Webでは 「velocity.propertiesにvelocimacro.libraryエントリに記述せよ」とあるが、Turbine環境下ではTurbineResources.propertiesservices.VelocityService.velocimacro.libraryでOKのようだ。

現在aipo5.1.2のカスタマイズを行っているのでファイルの検索をしていたら、aipoのGlobalMacros.vmがライブラリ登録されていて発見。velocity.propertiesでもOKなのかもしれないけどそれは試していない。

ちゅうか、なんで #parse では初回に失敗するのか不明なままだがワタシだけかな?
#parseじゃあマクロ取り込めないとVelocimacro いろいろに書いてあった(#parse() を使って Velocimacro を登録できますか ? )。困ってるときは見つからないってもー

2017年5月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
フォト

Google AdSense

銀の弾丸

無料ブログはココログ