Androidのアプリ開発関連のブログ

BufferedReaderの末尾改行

JavaのBufferedReaderでreadLine()で1行ずつ読み込むと、
readLine()で取得した行文字列には行末の改行コードが含まれないので、
while((line=buf.readLine())!=null){
   line+=lf;
   writer.write(line,0,line.length());
}
こんな感じで書き込み処理作ると元文字列に末尾に改行が無くても改行が追加されちゃう。

どうにかならんかと考えて、
改行コードの次の行ではnullではなくて空文字になる?
と思って、
if((line=buf.readLine())!=null){
  writer.write(line,0,line.length());
  while((line=buf.readLine())!=null){
    line=lf+line;
    writer.write(line,0,line.length());
  }
}
こんな感じでやってみたが、ダメだった。
これだとキッチリ改行の手前で終わっちゃうみたい。
よく考えると、空のStringだと0byteになるんだからそうだよな。

readLine()使う以上、BufferedReader通す前にサイズチェックしない限りどうにもならんかね。

元文字列の末尾が改行か他の文字かで処理分けるのもありかと思ったが、
書き込み処理はそれで良さそうだが、読み込み処理でもBufferedReader.readLine()使いたいから、その時は2回読まないと判別でき無いから、それなら1文字ずつ読んだ方が良いな・・・


そこまでして末尾の改行にこだわりたくないw

ディレクトリ指定では保存できるようになった

制作中のテキストエディターだが、今日は日中アプリ開発できなかったが、
処理の共通化とか既存コードの修正と、ディレクトリ指定でファイルの保存ができるようにした。

ローカルファイルのディレクトリ指定は前にFileWriterで作ってたが、
読み込みの方が文字コードと改行コードを変えれるようにしたから、書き込み処理も修正。

読み込み処理はInputStreamReaderでcharsetを指定できる感じにしたが、書き込みはOutputStreamWriterで文字コード指定。
改行コードを変えれるようにするためにBufferedReaderのreadLineで1行ずつ書き込みたいんで、書き込む内容は、
BufferedReader buf=new BufferedReader(new StringReader(str));
こんな感じでReader通した。

OutputStreamWriter writer=new OutputStreamWriter(out,charset);
BufferedReader buf=new BufferedReader(new StringReader(str));
String line;
while((line=buf.readLine())!=null){
   line+=lf;
  writer.write(line,0,line.length());
}
buf.close();
writer.close();
書き込み部分全体は、こんな感じ。



後テキストエディタとして必要なのは、
  • 元のファイルへの保存。
  • 文字コードの変換。
  • 初回読み込み時の文字コード指定。
くらいかなー。
処理自体は考慮して作ってるからほぼ完成してるようなもんで、メニュー項目追加すればすぐできそう。
それやったら、FTPSとSFTPの対応とかUI調整とか、ライセンスの表示かな。
HTTPのPUTとかも実装しようかな。

org.apache.commons.net.ftp.FTPClient.completePendingCommand()

前回の記事でFTPの接続状態が維持できるようになったが、応答が取得できなくなる場合があってハマった。

細かく例外処理分けて場所特定して、retrieveFileStream()の箇所っぽいことがわかった。
retrieveFileStream()でInputStreamが取得できるはずがnullになってるんだろうね。

で、アクティビティの切り替わりでダメなのかとか思ってたが、
retrieveFileStream()使った後は、completePendingCommand()しないとダメなんだね。

retrieveFileStream()使った後に、
if(!ftp.completePendingCommand()){
  切断処理;
}
って感じで失敗したら次回は再接続するように書いたらうまくいった。

転送port使うコマンドを使ったら、これやらないとコマンドportが把握してない感じかな?
アップロード処理でも同じことになるはず。

AsyncTaskLoaderで状態維持

制作中のテキストエディターで、初回load時にFTP接続して2回目以降は以前の接続状態から通信。
って処理がしたくて、loadInBackground()中でクラス変数に状態を保存してたんだが、

サブスレッドで変数記録しても、メインスレッドと別物じゃね?
って気がしたんで確認してみたが、案の定、記録できてなかった。

この件で今日はかなりハマったんだが、
慣れたPerl感覚だと別スレッドなら変数は全部別物と思ったが、Javaの場合はstaticな変数はスレッド間で共通みたい。
状態記憶用の変数をstaticにするだけでloadInBackground()中で設定した値が維持できた。

ただ、スレッド間で同じメモリ領域扱ってるってことだよね?
そうだとすると、複数スレッドで同時に触っちゃうと壊れね?
って思ったんだが、
synchronized(this){
   同期処理;
}
って感じで、synchronized使うとスレッド間でロック取って排他処理ができるみたい。

Android APIの方で調べてて全然わからなくてハマったが、Javaレベルでこんなことができるんだね。
知ってれば簡単だねー

アプリアイコンにメニュー

制作中のテキストエディターで、アプリアイコン(アプリタイトル)部分をクリックするとプルダウンメニューを出してタブUIのエディタの様に複数ファイルを切り替えられるようにしようとしていたが、
アプリアイコン部分をメニューにする方法がちょっとわかりにくかった。

まず、onCreateで、
getActionBar().setHomeButtonEnabled(true);
を設定しないとAndroidのバージョンによってはアプリアイコン部分がボタンにならない。
これは前のブログエディターでも使ってたからわかってた。

アプリアイコン部分がボタンになると、onMenuItemSelectedでタッチ時の処理ができ、
その場合はアプリアイコン部分のMenuItem.getItemId()はandroid.R.id.homeになる。
    public boolean onMenuItemSelected(int featureId,MenuItem item){
        if(item.getItemId()==android.R.id.home){
           処理
            return true;
        }
        return false;
    }
こんな感じでアプリアイコン部分がタッチされた時の処理が書けるわけだが、


    public boolean onMenuItemSelected(int featureId,MenuItem item){
        if(item.getItemId()==android.R.id.home){
            PopupMenu popup=new PopupMenu(this,findViewById(android.R.id.home));
            popup.getMenu().add("test");
            popup.show();
            return true;
        }
        return false;
    }
android.widget.PopupMenuを使うとプルダウンメニューが出せる。

android.widget.PopupMenuの使い方は、
android.widget.PopupMenu(Context context,View anchor);
で、2番目の引数でViewを渡すが、
popup.show();
した時に、設定したViewの直下にメニューが表示される。
メニューに対してサブメニューを作る感じではなくて、なんでもいいからViewに対して設定して、ポップアップする際の位置が設定したViewの位置になる感じ。
popup.getMenu()
でMenuが取得できるんで、普通にadd()で項目の追加ができる。

メニューは事前に作るものだと思ってたからちょっとわかりにくかったんだが、
ボタンタッチ等のアクション時にメニューを作成して、そのViewに対してshow()で即表示させられて便利だね。


PopupMenuで目的通りのことができそう。

今日は、予定してたファイル読み込み処理の分離をやって、
編集ファイルの切り替えができる仕様だと複数ファイルを読み込んで状態維持しなきゃいけないことに気づいたんで、複数ファイルを記録して管理できるようにした。
あとは上記のPopupMenuで切り替えられるようにして、保存できるように。

当初考えていたよりだいぶ時間かかっちゃってるが、今週中にはテキストエディタとして最低限の機能は持った状態になるかな。
保存機能がまだないからなw