2011年12月7日水曜日

JavaのArrayListの削除時の注意点


AndroidやJavaではよくArrayListを頻繁に使用する。
特にAndroidではListViewにアタッチする時によく利用されるようだ。
そこで私がしでかした失敗談を一つ。

ArrayListの要素を削除する場合removeメソッドを使用する。
このremoveメソッドは要素を削除した場合
indexも変更になる事に気をつけなければならない。
例えば

ArrayList<String> arrayList = new ArrayList<String>[];
arrayList.add("AAA");
arrayList.add("BBB");
arrayList.add("CCC");

とした際にまとめて削除したい場合
for( int i = 0 ; i < arrayList.size() ; i++ ){
    arrayList.remove(i);
}
とかするとエラーになってしまう。
なぜならsizeで取得した時点の要素数は3だが
removeを実行した瞬間にsizeが変わる。
index0番目(i=0)に相当するAAAを削除したらsizeはその時点で2になるのだ。
そしてindex1番(i=1)はBBBを指してはおらずCCCを指す事になる。
この時点でBBBは残りCCCは削除されるが
次のindex2番(i=2)はremoveをかけた瞬間にエラーとなる。
そう。要素が既に無いのだ。
3個消したい場合これではだめ。
全部消したいのなら
arrayList.clear()とするか
for( int i = 0 ; i < arrayList.size() ; i++ ){
    arrayList.remove(0);
}
などとすればよいだろう。
だが例えば「1番目と3番目を削除したい」としたらどうだろう。
理論的にはindex0を削除したあとindex1を削除すればいいのだが・・・。
「減っていくなら最後の方から削除すればいいのに」という声が聞こえた。

for( int i = arrayList.size() - 1 ; i >= 0 ; i-- ){
    if ( i == 0 ){
        arrayList.remove(i);
    }
    if ( i == 2 ){
        arrayList.remove(i);
    }
}

こんな感じ?

2011年12月4日日曜日

Androidプログラミングメモ 2011/12/4

simple_list_item_multiple_choiceのListViewを使用していて
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
などとした時にチェックされた物を処理したい場合に
getCheckedItemPositions()を使おうと思ったんだけどどうも違うみたい。
正しくは「チェックしたものがある時にすべてのリストを返す」物みたい。
例えば以下の直感コードではうまく動かない。

SparseBooleanArray positions = lv.getCheckedItemPositions();
for (int i = 0; i < positions.size(); i++) {
    if(positions.valueAt(i)){
        data.remove(positions.keyAt(i));
    }
}

一個だけだとうまく行く時もあるけど二個以上のチェックに失敗したり
データを追加したりした後のデータ削除などすると目もあてられない。
SparseBooleanArrayのsize()はListViewの最大値を返してくれるし
keyAt(i)なんかはよくわからない数値を出してくるし。

ListViewが何百もあった場合は結構つらそうだけど以下のように地道に
処理した方が無難みたい。

for (int ii = 0; ii < lv.getChildCount(); ii++) {
    CheckedTextView vv = (CheckedTextView)lv.getChildAt(ii);
    if (vv.isChecked()) {
        //チェックしたものの作業
        data.remove(ii);
    }
}

また、これはAndroidだけではない事だけどデバッグなどで
データを見たいからと言って

Log.v(getClass().getSimpleName(), "values: " + data.toString());
data.remove(ii);
Log.v(getClass().getSimpleName(), "values: " + data.toString());

とかするとデータの無いものを見たりしようとするので
馬鹿な真似はしないように。

2011年10月19日水曜日

素で入れたperlbrewにはLWP::Protocol::httpsを

ニコニコ動画を取り込みたいと思いperlbrew環境で試していた所
どうもAPIから帰ってくる答えが手元のブラウザと違う。
なんでかなといろいろ探って遡っていったらサインアップでこけてた。
サインアップは毎回LWP::UserAgentを使用しているので問題無いと
思っており戻り値もちゃんと帰ってくるのでいいと思っていたら
大間違いに気がつく。そう戻り値にちゃんと書いてあるのだ。

$ lwp-request -e -d https://secure.nicovideo.jp
501 Protocol scheme 'https' is not supported
(LWP::Protocol::https not installed)
Content-Type: text/plain
Client-Date: Wed, 19 Oct 2011 06:21:24 GMT
Client-Warning: Internal response

(ダメじゃん。おれ)
自分Crypt::SSLeayが入っていればLWPもそれに追従するものと
思っておりました。基本的に。
なので

cpanm LWP::Protocol::https

で解決。

2011年10月13日木曜日

HTC Evo WiMAXでgoldcard作成

ISW11HTでMicroSDカードをカスタムFWなどを
インストールする際に必要なgoldcard作成のお話。
どうもこの機種ではマウント構造が少し違うみたい。
私のは
/sys/class/mmc_host/mmc2/mmc2:*/cid
にありましたので表示する際は
adb shell cat /sys/class/mmc_host/mmc2/mmc2:*/cid
となります。

2011年9月26日月曜日

Plagger野良プラグイン作成

Plagger::Plugin::Filter::ImageResizeなるものを作った。
利用用途としては携帯のパケット量が気になる方や
androidなどの端末でリサイズする時に時間が気になる方向け。

私は画像入りfeedなどをgmailのようにメールで読む時
大きなサイズの画像などはリサイズ処理がかかるが
この処理時間がちとイライラしていたので
なんとかならないかといろいろサイトを見ていた。

昔にだれか公開していたと思うのだが
いくら探してもなかなか出てこないため作ってみた。

package Plagger::Plugin::Filter::ImageResize;
use strict;
use warnings;
use base qw (Plagger::Plugin);

use Image::Magick;

sub register {
    my($self, $context) = @_;
    $context->register_hook(
        $self,
        'update.entry.fixup' => \&filter,
    );
}

sub init {
    my $self = shift;
    $self->SUPER::init(@_);

    $self->conf->{width} or Plagger->context->error("config 'width' is not set.");
}

sub filter {
    my($self, $context, $args) = @_;

    my $conf_width = $self->conf->{width};

    for my $enclosure ($args->{entry}->enclosures) {
        my $image = Image::Magick->new;
        my $local_path = $enclosure->local_path;
        unless ($local_path) {
            $context->log(warn => "\$enclosure->local_path is not set. You need to load Filter::FetchEnclosure to use this plugin.");
            return;
        }
        $context->log(debug => "Load Image $local_path...");
        $image->Read($local_path);
        my $org_local_image_size = $image->Get('width') ;
        $context->log(debug => "Image Size $org_local_image_size");
        $context->log(debug => "Resize Size $conf_width");
        if ($org_local_image_size > $conf_width){
            $context->log(debug => "Image Width Bigger...");
            $image->Scale(geometry=>$conf_width);
            $image->Write($local_path);
        }
        undef $image;
    }
}

1;

でyaml的にはこんな感じ。

  - module: Filter::ImageResize
    config:
      width: 280

とりあえず適当なPluginをパクッてます。

基本的に"見る向き"の横幅を基本にするため
そこしか設定する箇所がありません。

ソース読んで頂ければわかると思うけど
ImageMagickとImageMagick-perlが必要。

LogLevelをdebugにすると詳細な動きが出てきます。

他にも"画質を落とす"などもできると思いますが
取り合えず自分的には満足したので
必要な方はご自身で追加してみてください。

久々に組んでみたら結構時間がかかってしまった。
もう年かなぁ。

2011年9月11日日曜日

家の携帯達



家の携帯達です。

両方共にandroidです。

ここに落ち着くまで結構長かったなぁ。

HTC Evo WiMAX



購入しました。

これから少しづつ更新していきますね。