2012年6月28日木曜日

SimpleAdapter : データの変更を画面に反映させる。

SimpleAdapter : データの変更を画面に反映させる。

Activityの起動時に(onCreateメソッド内で)SimpleAdapterを使ってListViewに値を設定する方法は既に述べた。
参考:android.R.drawableのアイコンを一覧表示する


ListViewが表示された後で、データの内容が変更された場合における、その変更をListViewに反映させる方法は次のとおりである。
この例では、任意のレコードに表示されている文字列を、別の文字列に変更する。
public class SimpleAdapterActivity extends ListActivity {

    SimpleAdapter sa;
    ArrayList<Map<String, Object>> data;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        int i;
        String sFrom[] = {"Image", "String"};
        int iTo[] =  new int[] {R.id.Image, R.id.Text};
        data =new ArrayList<Map<String, Object>>();
        
        for(i=0; i<IconRawData.length; i++){
            Map<String, Object> m = new HashMap<String, Object>();
            m.put("Image", IconRawData[i++]);
            m.put("String", IconRawData[i]);
            data.add(m);
        }
        sa = new SimpleAdapter(this, data, R.layout.child, sFrom, iTo);
        setListAdapter(sa);
    }
    
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        Map<String, Object> m;
        m = data.get(position);//クリックした位置にあるレコードを取得する。
        m.put("String", "This data has been modified.");//文字列を書き変える。
        data.set(position, m);//レコード内のデータを変更する。
        sa.notifyDataSetChanged();//変更を画面に反映させる。
    }


    public Object IconRawData[] = {
        android.R.drawable.ic_btn_speak_now,
        "ic_btn_speak_now",
        
        android.R.drawable.ic_delete,
        "ic_delete",
        
        android.R.drawable.ic_dialog_alert,
        "ic_dialog_alert",
        
        android.R.drawable.ic_dialog_dialer,
        "ic_dialog_dialer",
(以下省略)        

2012年6月19日火曜日

res>drawableにある画像ファイルをBitmapに変換する

res>drawableにある画像ファイルをBitmapに変換する

Resources r = getResources();
Bitmap b = BitmapFactory.decodeResource(r, R.drawable.green);

2012年6月9日土曜日

surfaceDestroyedメソッドの引数の意味

surfaceDestroyedメソッドの引数の意味

surfaceDestroyedメソッドには引数としてSurfaceHolderがある。

SurfaceHolderについては、surfaceCreatedメソッドや、surfaceChangedメソッドにおいて、lockCanvasメソッドを使ってcanvasに描画するのが主な使い方になる。

しかし、surfaceDestroyedメソッドは、終了をする時点で呼ばれるのであるため、こんな時点で描画を行っても、あまり意味は無い。
では、surfaceDestroyedメソッドの引数SurfaceHolderは何に使うのか。

これは、他のスレッドでcanvasを使わせることを阻止するための、排他制御の仕掛けとして使うのである。「描画をする」という目的では使わない。

Threadクラスでは、例えば、stopメソッドはdeprecatedであるとされている。スレッドを外部から止めることはできない。スレッドの外部で、何かフラグを立ててやることになる。

SurfaceViewが非表示になった後で、描画用スレッドがSurfaceViewのcanvasに書き込みを行うと、何か不都合が発生すると思われる。
この不都合を阻止するため、surfaceDestroyedメソッド内で、SurfaceHolderのlockCanvasメソッドを使って、canvasを排他的に取得し、取得後「SurfaceViewは終了しました」という趣旨のフラグ等を設定するのである。canvasには描画しない。
そうして、描画用スレッドでは、フラグを見て終了を検知し、canvasへの書き込みを行わないようにすれば良い。

この場合、描画用スレッドがcanvasに描画している最中に、surfaceDestroyedメソッドが呼ばれる、という事態も想定しなければならないと思われる。

下記のsample codeではBitmapを解放することを主眼にしてしまっているが、肝心なことは、描画用スレッドに対して終了を通知しcanvasへの書き込みを止めさせれば良いのである。

    @Override
    public void surfaceDestroyed(SurfaceHolder h) {
        
        //Bitmapを解放することが目的である。
        Canvas c = h.lockCanvas();//排他的にキャンバスを使う
        if(c==null){//もし、他のスレッドでキャンバスを使っていた場合。
            tDestroy = new Thread(this);
            tDestroy.start();//このスレッド内でBitmapを解放する。
        }
        else{
            go.Destroy();//Bitmapを解放する。
            go = null;//終了を示すフラグを代入する。
            h.unlockCanvasAndPost(c);
        }
    }
    
    @Override
    public void run(){
        
        //tDestroyは、Bitmapを解放することを目的としている。
        if(Thread.currentThread()==tDestroy){
            Canvas c = getHolder().lockCanvas();
            if(c==null){//他のスレッドがCanvasを使っている場合
                try {
                    Thread.sleep(10);
                }
                catch (InterruptedException e) {
                }
                tDestroy.start();//再度、呼び出す。
                return;
            }
            go.Destroy();//Bitmapを解放する。
            go = null;//終了を示すフラグを代入する。
            getHolder().unlockCanvasAndPost(c);
            return;
        }
        
        //tは、描画用のスレッドである。
        if(Thread.currentThread()==t){
            
            //終了スレッドが動いている場合、tスレッドではCanvasを使えないようにする。
            if(tDestroy!=null) return;
            
            Canvas c = getHolder().lockCanvas();
            if(c==null) return;//他のスレッドがCanvasを使っている場合
            if(go!=null
            && go.getBackground()!=null){
                //まだ、稼働中である場合、描画する。
                c.drawBitmap(go.getBackground(), 0, 0, null);
            }
            getHolder().unlockCanvasAndPost(c);
        }
    }