2012年4月26日木曜日

[Android]スライドショーをつくってみる

長らくblogを更新しておりませんでした・・・。
こんにちは、@mogakanaです。とりあえず生きてます。

本日はスライドショー的なものをつくってみました。
SDカード直下にある画像を読み込んでループ表示をするだけの簡単なお仕事です。

というわけで、まずは準備。
以下の画像をSD直下に保存します。

手書きの画像。ちょっとかわいい(笑)
↑こういうのを自画自賛という。

ちなみに完成画面はこんな簡易なものになります。

まずはSDカード直下に保存されている画像を取得するメソッドを作成します。
このときは".png"で判断しています。
.jpegなどは容赦なく無視。

private ArrayAdapter getImageFile() {
 // adapter の作成
 ArrayAdapter adapter = new ArrayAdapter(this,
   android.R.layout.simple_spinner_item);

 // SDカードのディレクトリを取得
 File directory = Environment.getExternalStorageDirectory();

 // SDカードの一番上からファイルを取得
 File[] files = directory.listFiles();

 // adapterにファイルパスを追加
 for (int i = 0; i < files.length; i++) {
  // pngを追加
  if (files[i].getName().endsWith(".png")) {
   adapter.add(files[i].getPath());
  }
 }

 return adapter;
}
あとで使うのでadapterで返しています。
取得したSDの画像をスピナーへ。
SD直下になにも画像がなかったときは強制的にアプリを終了させてみました(おい)。

// SDのファイル取得
mFileSpinner = (Spinner) findViewById(R.id.fileSelectSpinner);

// adapterの作成
mFileSpinner.setAdapter(getImageFile());
mFileSpinner.setOnItemSelectedListener(this);

// ファイルがなかったときはアプリケーション終了
if(mFileSpinner.getChildCount() == 0) {
 Toast.makeText(this, "File Nothing! application close...", Toast.LENGTH_LONG).show();
 finish();
}
スタートボタンを押すとはじまります。

最初にmIsSlideShowというフラグをつくっておいてSTART/STOPを制御します。

private boolean mIsSlideShow = false;
では、スタートボタンの実装へ。

public void onClickShowButton(View view) {

 Button showButton = (Button) findViewById(R.id.showButton);

 if (mIsSlideShow) {
  // ストップ
  mHandler.sendEmptyMessage(0);
  showButton.setText("START");
 } else {
  // スタート
  mCurrentPosition = mFileSpinner.getSelectedItemPosition();
  showImageFile(mFileSpinner.getSelectedItemPosition());
  showButton.setText("STOP");
  mIsSlideShow = true;
  Thread thread = new Thread(this);
  thread.start();
 }

}
スレッドで制御しております。なぜなら、途中でストップを押すために。
その前に画像を表示させるメソッドを。

private void showImageFile(int position) {

 String selectFilePath = (String) mFileSpinner
   .getItemAtPosition(position);

 Bitmap bitmap = BitmapFactory.decodeFile(selectFilePath);
 mImageCanvas.setImageBitmap(bitmap);

}
スレッドはこうなります。

@Override
public void run() {
 while (mIsSlideShow) {
  try {
   // スリープ(10秒)
   Thread.sleep(10000);
  } catch (Exception e) {
   Log.e(TAG, "error!!");
  }

  Log.i(TAG, String.valueOf(mCurrentPosition));

  // 画像の変更
  if (mCurrentPosition == mFileSpinner.getCount() - 1) {
   // 先頭へ
   mCurrentPosition = 0;
  } else {
   mCurrentPosition++;
  }

  mHandler.post(new Runnable() {
   @Override
   public void run() {
    showImageFile(mCurrentPosition);
   }
  });

 }

}

private Handler mHandler = new Handler() {
 public void handleMessage(Message msg) {
  // 終了
  mIsSlideShow = false;
 }

};
ストップが押されるまで画像がループされます。

というわけで今日のソースはこちら。

package jp.co.mogakana.slideshow;

import java.io.File;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.Toast;

public class SlideShowActivity extends Activity implements
  OnItemSelectedListener, Runnable {

 private static final String TAG = "SlideShow";

 private int mCurrentPosition;

 private Spinner mFileSpinner;
 private ImageView mImageCanvas;

 private boolean mIsSlideShow = false;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  mImageCanvas = (ImageView) findViewById(R.id.slideShowImageView);

  // SDのファイル取得
  mFileSpinner = (Spinner) findViewById(R.id.fileSelectSpinner);
  // adapterの作成
  mFileSpinner.setAdapter(getImageFile());

  mFileSpinner.setOnItemSelectedListener(this);
  
  
  // ファイルがなかったときはアプリケーション終了
  if(mFileSpinner.getChildCount() == 0) {
      Toast.makeText(this, "File Nothing! application close...", Toast.LENGTH_LONG).show();
      finish();
  }
  

 }

 public void onClickShowButton(View view) {

  Button showButton = (Button) findViewById(R.id.showButton);

  if (mIsSlideShow) {
   // ストップ
   mHandler.sendEmptyMessage(0);
   showButton.setText("START");
  } else {
   // スタート
   mCurrentPosition = mFileSpinner.getSelectedItemPosition();
   showImageFile(mFileSpinner.getSelectedItemPosition());
   showButton.setText("STOP");
   mIsSlideShow = true;
   Thread thread = new Thread(this);
   thread.start();
  }

 }

 private void showImageFile(int position) {

  String selectFilePath = (String) mFileSpinner
    .getItemAtPosition(position);

  Bitmap bitmap = BitmapFactory.decodeFile(selectFilePath);
  mImageCanvas.setImageBitmap(bitmap);

 }

 private ArrayAdapter getImageFile() {
  // adapter の作成
  ArrayAdapter adapter = new ArrayAdapter(this,
    android.R.layout.simple_spinner_item);

  // SDカードのディレクトリを取得
  File directory = Environment.getExternalStorageDirectory();

  // SDカードの一番上からファイルを取得
  File[] files = directory.listFiles();

  // adapterにファイルパスを追加
  for (int i = 0; i < files.length; i++) {
   // pngを追加
   if (files[i].getName().endsWith(".png")) {
    adapter.add(files[i].getPath());
   }
  }

  return adapter;
 }

 @Override
 public void onItemSelected(AdapterView arg0, View arg1, int position,
   long arg3) {

 }

 @Override
 public void onNothingSelected(AdapterView arg0) {
  Toast.makeText(this, "File Nothing!", Toast.LENGTH_LONG).show();
 }

 @Override
 public void run() {
  while (mIsSlideShow) {
   try {
    // スリープ(10秒)
    Thread.sleep(10000);
   } catch (Exception e) {
    Log.e(TAG, "error!!");
   }

   Log.i(TAG, String.valueOf(mCurrentPosition));

   // 画像の変更
   if (mCurrentPosition == mFileSpinner.getCount() - 1) {
    // 先頭へ
    mCurrentPosition = 0;
   } else {
    mCurrentPosition++;
   }

   mHandler.post(new Runnable() {
    @Override
    public void run() {
     showImageFile(mCurrentPosition);
    }
   });

  }

 }

 private Handler mHandler = new Handler() {
  public void handleMessage(Message msg) {
   // 終了
   mIsSlideShow = false;
  }

 };

 @Override
 protected void onResume() {
  super.onResume();
  
 }

 @Override
 protected void onPause() {
  super.onPause();
 }

}
適当に書いたんだけど、けっこう絵がかわいいと自画自賛中。

2011年9月2日金曜日

[Android] GALAPAGOS メディアタブレットのUSBドライバについて

ADB USBドライバは
ここ。

ソフトウェアダウンロード

でかいタイプ(いちばんおおきいやつ)も
これでいけます。

ねむりたい。ねむりたい。

2011年8月20日土曜日

[Windows Phone 7] アプリケーションの作成と起動

簡単に。
まずはVisualStdio2010(WP)を起動します。

で、見たことある感じの画面から
NEW Projectを選択するとこのような画面が出ます。


















なぜ、VBなんだ・・・。
というツッコミのもと、下のC#を選択します。
おそらくVBでもつくれなくはないのですが、エラーがでてとれなかったので(失格)、とりあえずこちらを。

















プロジェクト名に適当な名前を入れて(もちろんこのままでもいい)
OKを押すだけ。

あとは実行ボタンを押して待てばエミュレータが起動して
なにやらメッセージがでます。

終了。


というのもおもしろくないので
今回はコードはいじらずにデザイン画面からラベルを選択して
文字だけをいじってみました。

で、こうなる。























昔のHello Androidを思い出しますね、はい。

コードを書くときはそれぞれの配置したUIでクリックするなりなんだかんだりで
VisualStdion感満載でできるかとおもいます。

続きは後日。

[Windows Phone 7] 開発環境を整える

やってみることにしました。

OSはwindows7で。
Windows Phone 開発者向け技術情報 に飛ぶ

アプリケーション開発のところに
Windows Phone SDK 7.1 Beta 2
というリンクがあるのでジャンプ。

vm_web2.exe

をダウンロード。
ダウンロードしたファイルを実行するとインストーラーが走るのでまつべし。
私のパソコンはそんなに悪い性能ではないのですが、けっこうまたされました。
なのでコーヒー片手に本でも用意しておくとよいでしょう。

再起動を促されるのでおとなしく再起動をしましょう。


つづいては
Windows Phone Developer Tools RTW
のインストール。

余談ですが、この順序は逆なので・・・。(どちらからでもいいかとおもいますが)

vm_web.exe

をダウンロードして実行します。
こちらも時間がかかるので紅茶をのみながらのほほんとまっていましょう。

こちらは再起動は促されない様子です。

起動するとWindowsPhone用のVisualStudioが起動します。
外見は本当にVisualStudioなので(あたりまえだ)、触ったことある人は大体直感でわかるんじゃないかとおもいます。

2011年8月13日土曜日

[お知らせ] 日本Androidの会 関西支部のLTにでます。

9月3日にある
「日本Androidの会 関西支部勉強会」
でLTをやります。

もう人数埋まってますが、よかったらどうぞ。
ATNDより

LTやりますといったのはいいけど、ネタはこれからつくるのだったりする。
開発系のことをしゃべります。
あたまのなかで「あれをしゃべるかー」というのは考えているのですが

うーん。

5分で関西の人々の心をつかめるかはわからないですね。

ちなみに色々な都合上名前が「高田純三」になっています。
たぶんニッカポッカに木刀だな。

[Android] 007SH スクリーンショットの撮り方

いつのまにか007SH Jでスクリーンショットがとれるようになっておりました。

撮り方
取りたい画面で
終話キー(または側面のロックキー)+ ホームキー

ホームキーはさりげなく下にあってよくミスってうってしまうあのキーです。
0の下。

単体でスクリーンショットがとれるのはかなり便利。
友達とやりとりするときとか。

2011年8月6日土曜日

[Android] 2.1以上の電話帳(つまりContacts)とたたかってみるんだぜ その1

電話帳って2.1から変更されたんですよね。
ゆえにそんなにリファレンスサイトがないので自分でどーこーしてみることにした。
某会議でよく電話帳が話題になるので
まー、興味がでたっていえばでたんですけど。

Androidでは電話帳DBなるものが標準で搭載されている。
/data/data/com.android.providers.contacts/databases/contacts2.db
という場所にあったりする。
実際にデータをpullなどでぬいてきて
SQLite3のビューアーとかでみるとたしかにデータがはいっている。

が、これがすごくわかりづらい。
一回に解説したいですが、私にもわかってない箇所があるので
まー、それはゆっくりと。
とりあえず2.1からでは「ごっそりと仕組みが変わった」ということを覚えていただきたいです。
覚えなくてもいいけど。

では、簡単につかってみましょう。
前提条件として電話帳にこんな感じのデータをいれておきます。



















これは標準電話帳の画面です。
で、最終的にこんな感じにする。



















今回はかるーくテストなんで名前だけの表示にしています。
本来なら、下に電話番号をだすなり、メアドだすなり好きにしていいんですが
仕事中の休み時間にできることは限られているので(1時間しかない)。
時間があればそのうちハイパーなものをつくりたんですが、はてさて。

では本日のコードです。

まずはレイアウトのXMLを。



    


簡単にListViewだけを表示しているのでこれだけです。
つづいてはこちらに名前を入れるコード。

import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class AddressListActivity extends Activity {
 
 private ListView mListView;
 
 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.address_list);
        
        // 表示
        mListView = (ListView) findViewById(R.id.listView);
        mListView.setAdapter(displayNameList());
  
 }
 
 // DBから取り出してごにょっとする
 private ArrayAdapter displayNameList() {
  
  // DBアクセス
  databaseAccess access = new databaseAccess(this);
  Cursor cursor = access.selectAllAddress();
  
  cursor.moveToFirst();
  ArrayAdapter adapter = new ArrayAdapter(this,android.R.layout.simple_list_item_1);
  
  // Contactsのデータを管理しているRAW_CONACT_ID
  int idIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.RAW_CONTACT_ID);
  // 表示名
  int nameIndex = cursor.getColumnIndexOrThrow(ContactsContract.Data.DISPLAY_NAME);
  // idにとりあえずの初期値を入れておく
  int id = 0;
  
  while (!cursor.isAfterLast()) {
   // idが変わったら次の人
   if(id != cursor.getInt(idIndex)) {
    // idの入れ替え
    id = cursor.getInt(idIndex);
    // 表示名取得
    adapter.add(cursor.getString(nameIndex));
    
    
   }
   cursor.moveToNext();
  }
  
  cursor.close();
  
  return adapter;
  
  
  
 }
 
}

コメントいれてあるのですが、実は上のコードにはDBにアクセスする処理はございません。
アクセスするにはこちらのコードを。
別にクラスを分ける必要性はなかったのですが、
あとあと入力とかを拡張しようと思っていたのでわけました。

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;

public class databaseAccess {
 
 private Context context;
 private Uri uri = ContactsContract.Data.CONTENT_URI;
 
 // コンストラクタ
 public databaseAccess(Context context){
  this.context = context;
  
 }
 
 /**
  * DB全件返しメソッド
  * @return
  */
 public Cursor selectAllAddress() {
  return context.getContentResolver().query(uri, null, null, null, null);
 }

}

クエリのつかいかたですが、

Cursor android.content.ContentResolver.query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

という記述がDevelopersなんとかっていう解説書(もう忘れた)にあります。
場所を指定して、取り出すものを指定。さらに条件・・・といったところでしょうか。
今回は簡易なのでいやでも全件返すようにしています。

全件返すことでもちろん名前以外にも電話番号まで帰ってきているので

  while (!cursor.isAfterLast()) {
   // idが変わったら次の人
   if(id != cursor.getInt(idIndex)) {
    // idの入れ替え
    id = cursor.getInt(idIndex);
    // 表示名取得
    adapter.add(cursor.getString(nameIndex));
    
    
   }
   cursor.moveToNext();
  }

このあたりのところでいろいろ分岐させています。
IDは一人につき1つなので、そのIDが切り替わったら次の人。
同じIDが名前を2回もっていることもあるのでこういう重複チェックをかけています。
なぜ名前を2回もっているのかというと・・・

「ID」「表示名」「電話番号」
「ID」「表示名」「苗字」

というようなデータ構造になっているためです。
表示名は何回もはいってくるのですね(汗)


なのでまわりくどいコードになっています。
このあたりは私の調査不足なのでおいおいかっこいいコードに(そりゃもう鼻血がでるほど)していけたらいいなーとおもいますがな。


そんな感じで第一回電話帳会議終了。

ではもどるぞ!!だいじゅうよんてい(ry)

はい、仕事します。