2011年4月27日水曜日

ListViewのadapterでAsyncTaskを使って画像DownloadしてImageViewに乗せるとスクロール時にズレる問題について

以下のようなadapterを作ってみた

    public class ImageListAdapter extends ArrayAdapter<String>{
        private ArrayList<String> urls;
        private LayoutInflater inflater;
    
public UserListAdapter(Context context, int textViewResourceId,
ArrayList<String> urls) {
       super(context, textViewResourceId, users);
       this.urls = urls;
       this.inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
   }

@Override
public View getView(int position, View convertView, ViewGroup parent) {
       View view = convertView;

       if (view == null) {
           view = inflater.inflate(R.layout.row_status, null);
       }

       String url = urls.get(position);
       if (user != null) {
           ImageView imageview = (ImageView) view.findViewById(R.id.image);
         
           /*//コンストラクタでImageView送ってその後executeでURL送る
           DownloadTask task = new DownloadTask(imageview);
           try {
               task.execute(url);
           } catch (RejectedExecutionException e) {
}
*/

           /*//ImageViewにURLをタグを乗せてAsynctask起動
           GetImageInBackground task = new GetImageInBackground();
           imageview.setTag(url);
           try {
               task.execute(imageview);
           } catch (RejectedExecutionException e) {
}
*/

       }
       return view;
}
    }
  
  
で、以下それぞれのタスク
public class DownloadTask extends AsyncTask<String, Void, Bitmap> {
    // アイコンを表示するビュー
    private ImageView imageView;

    // コンストラクタ
    public DownloadTask(ImageView imageView) {
        this.imageView = imageView;
    }
  

    // バックグラウンドで実行する処理
    @Override
    protected Bitmap doInBackground(String... urls) {
        Log.v("AsyncTastTest", "DownloadTask doInBackground" + " urls[0] =" + urls[0]);
     Bitmap image = ImageCache.getImage(urls[0]);
        if (image == null) {
           image = HttpClient.getImage(urls[0]);
           ImageCache.setImage(urls[0], image);
        }
        return image;
}

    // メインスレッドで実行する処理
    @Override
    protected void onPostExecute(Bitmap result) {
        Log.v("AsyncTastTest", "DownloadTask onPostExecute");
        this.imageView.setImageBitmap(result);
    }
}

public class GetImageInBackground extends AsyncTask<ImageView , ImageView , Long > {
    Bitmap bitmap;
    String tag;

    @Override
    protected void  onProgressUpdate  (ImageView... params){
    if (bitmap!=null){
              ImageView imageViewByTag = (ImageView) params[0].findViewWithTag(tag);
              if (imageViewByTag != null) {
                  imageViewByTag.setImageBitmap(bitmap);
                }
      }
    }

    @Override
    protected Long doInBackground(ImageView... params) {
        tag = (String) params[0].getTag(); //タグからurl引っ張る
        if (tag==null){
            bitmap = BitmapFactory.decodeResource(Resources.getSystem(), R.drawable.icon);//デフォ画像
        }else{
         bitmap = ImageCache.getImage(tag);
            if (bitmap == null) {
                bitmap = HttpClient.getImage(tag);
                ImageCache.setImage(tag, bitmap);
            }
        }
        publishProgress(params[0]);
        return null;
    }
}

HttpClientのclassとImageCacheとかは以下から引っ張ってきて下さい
"AsyncTaskでユーザビリティを向上させる"
http://labs.techfirm.co.jp/android/cho/1079
前者のDownloadTaskもそのまま使わせてもらっています。


           /*//コンストラクタでImageView送ってその後executeでURL送る
           DownloadTask task = new DownloadTask(imageview);
           try {
               task.execute(url);
           } catch (RejectedExecutionException e) {
}
*/
こっちのタスクを使う場合、実機で高速にスクロールしたりすると画像が違うrowに格納されたりズレたりします。
Logを取ってみた所、たまにonPostExecuteされていない場合があるみたい?それによってpositionとの対応関係がズレるって現象が起きちゃうみたいです。
別にRejectedExecutionException発生してなかったりするんですが・・・もっと細かくログ取って調査したほうがいいかな。
解決方法はどうにかなってるので気が向いたらで。

           /*//ImageViewにURLをタグを乗せてAsynctask起動
           GetImageInBackground task = new GetImageInBackground();
           imageview.setTag(url);
           try {
               task.execute(imageview);
           } catch (RejectedExecutionException e) {
}
*/
こちらの場合ImageViewにタグを乗せて送っているので対応関係がズレる可能性がなくなる。

実は後者でも何か若干動作怪しい場合があります。
もうちょっと色々やる余地はあるのかな?

2011年4月25日月曜日

android webviewにloadDataする時文字化けた。

WebView webview = (WebView) findViewById(R.id.WebView01);
webview.loadData("テストテキスト", "text/html", "UTF-8");

これだと文字化ける。なんかちゃんとhtmlの体裁整えないとNGみたいです。


WebView webview = (WebView) findViewById(R.id.WebView01);
webview.loadData(
"<html><head><meta http-equiv=\"content-type\" content=\"text/html;charset=UTF-8\"></head>" +


"テストテキスト" +
"</html>"
, "text/html", "UTF-8");

こんな感じにしたら問題なし。
まともなhtml使いましょうってことか。

eclipseだとソース自体がUTF-8使ってる場合が多いからソース内にhtmlをString hoge = "hogehoge"って持ってたりする場合にS-JISとしてhtmlを扱っちゃったらおかしくなりそう。
charset="s-jis"のhtml扱う時は注意なのかなぁ。

2011年3月31日木曜日

GlaxyTabでアプリを作った場合に黒枠がでちゃう問題+Canvasの謎

単純にどうにかしたいだけの場合

manifest.xmlに
<manifest>

~~~~~~~~~~~~~
~~~~~~~~~~~~~
<uses-sdk android:minSdkVersion="4" />

</manifest>

って記述足せばok
単純にEclipseでmanifest.xml開いてManifestタブのManifestExtrasのAddでUsesSdk追加してmin SDK versionを4にしてもok(xmlは結局同じことになる)


で、さらに立ち入ってこの問題について調べてみた。
http://developer.android.com/intl/ja/guide/topics/manifest/supports-screens-element.html
このあたりに記述ある
どうもAPI Level4から

supports-screensの
 android:smallScreens
 android:normalScreens
 android:largeScreens
 android:anyDensity
このへんが全てtrueになってるってことらしい。
で、minSDKversionを指定せずに全てをtrueにして見た結果は上手くいかない。根本的にAPILevel4までは実装されてないってことっぽい?
しかし、2.1-update1を指定して作ったパッケージで上手くいきません。
supports-screeens直接指定しても特に変化がない。謎。
minSDKversionを変えるとそのAPILevelにしたがって設定されるが手動指定は不可能って状態?

2.1-update1のみで試したので他のバージョンはどうなるか不明


さらに謎現象があって
APILevelを指定せずにBitmapデータからCanvas作って色々描いたりする場合のCanvasのサイズがおかしくなる。何故か1.5倍にされる。
定数で描画している処理等はズレます。

ついでにメモリかつかつで開発してるとGalaxyTabに対応しようとしたら落ちるってクソみたいな展開が予想されます。(っていうかなりました・・・。

回避するならCanvas使う描画時にBitmapからCanvas作る前にCanvasのサイズを指定して生成しておくって感じになるのかなぁ。
リファレンスに何か書いてあるかも。英語なので全部読むのメンドクサイ・・・いつかちゃんと読みます。

2011年2月3日木曜日

ヤターいまいち萌えないウィジェットできたよー\(^o^)/

勝手に作ってみた。
問題あれば削除する。

とりあえず
設定>アプリケーション>提供元不明のアプリ
を許可して、ファイル落として開いてインストールしてください。

で、ホーム画面をロングタップ>ウィジェットに入ってるので適当に置いてあげてください。
シングルタップすると時計の文字の色が変わるよ!

あくまでジョークソフトって感じの扱いで、バグとかはそれなりに含まれてるかも。

http://ux.getuploader.com/erw/download/1/ima.apk

#追記バグ発見。
とりあえず、ウィジェット置いて1分間はシングルタップで色が変わらないってバグ発見
原因わかるし、対策出来るけど放置
##さらにバグ発見
月日の表示おかしいねこれ。気づけよ。
あと、一晩動かしてたらたまーに時計の更新が止まる場合あるっぽい?サービス落ちてるみたいな感じタップすればサービスにインテント投げるから勝手に復活するけど、サービスの寿命って割と曖昧なんだよね・・・。

2011年1月12日水曜日

androidの動画のintent

mp4をintentした際に気づいたこと。

Uri uri = Uri.parse("file://sdcard/hoge.mp4");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setDataAndType(uri, "video/mp4");
startActivity(intent);
これだと標準動画プレイヤーが上手く動作しない
vplayerとかに投げる分には大丈夫なんだけど
標準のcom.google.android.gallery3d/com.cooliris.mediaMovieViewだと何故か上手くいってない。

で解決策
file://sdcardをfile://mnt/sdcardにする
Uri uri = Uri.parse("file://mnt/sdcard/temp.mp4");
これで上手く行った
テストしたのはnexus one,2.2.1の環境なので、全てこのとおりとは限らないかも。