2015年12月21日月曜日

GAEのデータストアからの検索、挿入、削除、更新

目次へ



GAEのデータストアにJDOでアクセスし、データの検索、挿入、削除、更新をする方法です。
データストアには、Persistence Managerというオブジェクトを使い、アクセスします。
  • Persistence Managerの取得
  • カインドの定義(RDBのテーブルの定義にあたる)
  • データの挿入
  • JDOQLによる検索
  • データの削除
  • データの更新


■■■■Persistence Managerの取得

JDOによるデータストアからの検索、書き込みにはPersistence Managerというオブジェクトを使います。
Persistence ManagerオブジェクトはPersistence Manager Factoryというファクトリオブジェクトを使って作成します。
下のPMFクラスはPersistence Manager Factoryのインスタンスを1つだけ作成するシングルトンです。
PMFクラス
import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

public final class PMF {
 private static final PersistenceManagerFactory pmfInstance = 
       JDOHelper.getPersistenceManagerFactory("transactions-optional");
 
 private PMF(){}
 public static PersistenceManagerFactory get() {
  return pmfInstance;
 }
}



■■■■カインドの定義

JDOではアノテーション付きのクラスを定義することでカインドを定義します。
下のSyouhinクラスはnameとpriceというプロパティとLong型のキーを持つSyouhinカインドを定義しています。
カインドとはRDBの表だと思ってください

  • @PersistenceCapable このクラスがカインドを定義するためのクラスであることを示します。
  • @PrimaryKey このフィールドがキーであることを示します
  • @Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY) キーを自動で作成することを示します
  • @Persistent このフィールドをデータストアへ書き込むことを示します
Syouhinクラス
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.search.SortExpression.SortDirection;

@PersistenceCapable
public class Syouhin {

 @PrimaryKey
 @Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
 private Long key; //自動で作成するキー

 @Persistent
 private String name; //商品名

 @Persistent
 private Integer price; //価格

 //-------------------------------- getter setter
 public Long getKey() {
  return key;
 }
 public void setKey(Long key) {
  this.key = key;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 public Integer getPrice() {
  return price;
 }
 public void setPrice(Integer price) {
  this.price = price;
 }



■■■■データの挿入

次のメソッドはsyouhinオブジェクトをデータストアに格納します
格納するメソッド
public boolean insert(Syouhin syouhin) {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 try {
  pm.makePersistent(syouhin);
  return true;
 } catch(Exception e) {
  e.printStackTrace();
  return false;
 } finally {
  pm.close();
 }
}



■■■■JDOQLによる検索

次のメソッドはどちらも、データストアの中のSyouhinカインド内のすべてのエンティティを取得します
Single-String JDOQLによる全検索
public List selectAll() {
 PersistenceManager pm = PMF.get().getPersistenceManager();

 try {
  //------------- Single-String JDOQLによる検索
  Query query = pm.newQuery("SELECT FROM SYOUHIN");
  List list = (List)query.execute();
  return list;
 } catch(Exception e) {
  e.printStackTrace();
  return null;
 } finally {
  pm.close();
 }
}



Declarative JDOQLによる全検索
public List selectAll() {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 
 try {
  //------------- Declarative JDOQLによる検索
  Query query = pm.newQuery(Syouhin.class);
  List list = (List)query.execute();
  return list;
 } catch(Exception e) {
  e.printStackTrace();
  return null;
 } finally {
  pm.close();
 }
}



キーを指定して検索(キー以外でも使える)
public Syouhin selectByKey(long number) {
 PersistenceManager pm = PMF.get().getPersistenceManager();

 try {
  //---キーを作成
  Key key = KeyFactory.createKey(Syouhin.class.getName(), number);

  //---そのキーのデータを取得
  Syouhin syouhin = pm.getObjectById(Syouhin.class, key);

  return syouhin;
 } catch(Exception e) {
  e.printStackTrace();
  return null;
 } finally {
  pm.close();
 }
}



条件を指定して検索(キー以外でも使える)
public List selectByKey(long number) {
 PersistenceManager pm = PMF.get().getPersistenceManager();

 try {
  //------------- とりあえずすべてを選択するクエリー
  Query query = pm.newQuery(QData.class);
 
  //---条件作成 numberというパラメータを指定している
  query.setFilter("key==number");

  //---パラメータnumberの型を指定
  query.declareParameters("long number");

  //---パラメータに実際の値を入れて実行
  List results = (List) query.execute(number);

  return list;
 } catch(Exception e) {
  e.printStackTrace();
  return null;
 } finally {
  pm.close();
 }
}



Single-String JDOQLによる条件検索
public List selectByKey(String name) {
 PersistenceManager pm = PMF.get().getPersistenceManager();

 try {
  //------------- JDOQL作成
  String str = "select from " + Syouhin.class.getName() +
   " WHERE name==" + name + " order by price ASC";
  List list = (List) pm.newQuery(str).execute();

  pm.close();
  return list;
 } catch(Exception e) {
  e.printStackTrace();
  return null;
 } finally {
  pm.close();
 }
}



■■■■データの削除

次のメソッドはすべてのsyouhinオブジェクトをデータストアから削除します
Syouhinカインド内のすべてのエンティティを削除するメソッド
public boolean deleteAll() {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 try {
  Query query = pm.newQuery(Syouhin.class);
  List list = (List)query.execute();
  // いったん取得したものすべてを削除
  pm.deletePersistentAll(list);
  return true;
 } catch (Exception e) {
  e.printStackTrace();
  return false;
 } finally {
  pm.close();
 }
}



選択した1つのSyouhinを削除するメソッド
public boolean deleteByKey(long number) {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 try {
  //---キーを作成
  Key key = KeyFactory.createKey(Syouhin.class.getName(), number);

  //---そのキーのデータを取得
  Syouhin syouhin = pm.getObjectById(Syouhin.class, key);

  // 取得したものを削除
  pm.deletePersistent(syouhin);
  return true;
 } catch (Exception e) {
  e.printStackTrace();
  return false;
 } finally {
  pm.close();
 }
}



■■■■データの更新

更新は、選択したオブジェクトを変更すればよい
public boolean update(Syouhin s) {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 try {
  //---キーを作成しそのキーのデータを取得
  Key key = KeyFactory.createKey(Syouhin.class.getName(), s.getNumber());
  Syouhin syouhin = pm.getObjectById(Syouhin.class, key);
  syouhin.setName(s.getName());
  syouhin.setPrice(s.getPrice());
  return true;
 } catch(Exception e) {
  e.printStackTrace();
  return false;
 } finally {
  pm.close();
 }
}



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年12月7日月曜日

GAEのデータストア上のデータ構造

目次へ

  • データストア上のデータ構造
  • データストアに格納できるデータ型


■■■■データストア上のデータ構造

データストアに格納するデータ構造は次のようになります。


おおざっぱに言うとRDBのテーブルにあたるものがデータストアのカインド。
RDBのレコードにあたるものがエンティティ。
RDBの列項目にあたるものがプロパティになります。

また、各エンティティには、ユニークなキーが必要で、アプリケーションで指定することも、自動で作成することもできます。


■■■■データストアに格納できるデータ型

エンティティの各プロパティには下表のような型の値を格納することができます。
文字列、バイト列に対しては、500バイト未満と500バイト以上の型があります。

対応するJavaクラス
短い文字列(500バイト未満) String
長い文字列(500バイト以上) com.google.appengine.api.datastore.Text
短いバイト列(500バイト未満) com.google.appengine.api.datastore.ShortBlog
長いバイト列(500バイト以上) com.google.appengine.api.datastore.Blob
真偽値 boolean,Boolean
整数値 short,int,long,Short,Integer,Long
浮動小数点数 float,double,Float,Double
日時 java.util.Date
Googleアカウント com.google.appengine.api.users.User
エンティティキー com.google.appengine.api.datastore.Key
カテゴリ com.google.appengine.api.datastore.Category
電子メールアドレス com.google.appengine.api.datastore.Email
位置情報 com.google.appengine.api.datastore.GeoPt
インスタントメッセージのハンドル com.google.appengine.api.datastore.IMHandle
URL com.google.appengine.api.datastore.Link
電話番号 com.google.appengine.api.datastore.PhoneNumber
郵便番号 com.google.appengine.api.datastore.PostalAddress
評価値(1~100の整数値) com.google.appengine.api.datastore.Rating






にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年8月31日月曜日

SwingWorker サンプル

目次へ



  • イベントディスパッチスレッドとは
  • SwingWorkerとは
  • SwingWorkerの2つの引数
  • SwingWorkerサンプル


■■■■イベントディスパッチスレッドとは

Swingの描画に関連する処理と、イベントに対する応答処理(たとえばJButtonが押された時に呼び出されるactionPerformed等は イベントディスパッチスレッドと呼ばれる一つのスレッドで実行されます。
そのため、たとえば、ボタンを押すと画像を表示しているJLabelが300msecおきに5ピクセルづつ10回動くようにしたくて(ゆっくり進めたい)、 下のようなプログラムを作ったとすると、うまくいきません。
このプログラムを実行し、ボタンを押すと、300×10msecの間、画像は何も動かず、3000msec後にいきなり、5×10ピクセル移動してしまうことになります。

これはactionPerformedと、label.setBoundsを実行することによる描画処理が1つのスレッドで行われるためです。


なぜこうなるのでしょう
ボタンを押すと、①のactionPerformedがイベントディスパッチスレッド上で実行開始します。
1回目のループで②が実行されると、描画処理はイベントディスパッチスレッド上で行われなければいけないのですが、 イベントディスパッチスレッド上ではactionPerformedを実行中のため、これが終了したら実行できるように、 イベントキューにこの処理をならべます。
イベントキューとは、複数のイベントが発生した時に同時にその処理を実行できないため、それらのイベントを並べておく待ち行列です。
イベントディスパッチスレッドは、イベントキューに並んでいる処理を順番に実行していくことになります。

actionPerformedはイベントキューに描画処理を並べた後、300msecのスリープに入ります。
actionPerformedが終了するまでイベントキューに並んでいる処理は実行できませんから、まだ、描画処理は実行されず、待ち続けます。
2回目のループでも同じで、②の位置まで来ると、ひとつ前の②の処理がまだ実行されずにイベントキューで待っていますが、 その後ろに、②の処理を並べ、スリープします。
こうして、10回のループがやっと終了すると、イベントキューに並んでいる10個の処理が順番に実行されます。
10個の処理はスリープもなく、すぐに実行できますから、人間の目には1ぺんに、最初の位置から、最後の位置まで動いたように見えます。


うまくいかないプログラム
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class SwingworkerNasiTest extends JFrame {
 private static int WIDTH = 29; //画像幅
 private static int HEIGHT = 41; //画像高さ

 JButton btnWalk = new JButton("歩く");
 JLabel  label   = new JLabel(new ImageIcon("./penguin.gif"));
 JPanel  panel = new JPanel();
 JPanel  contentPane = (JPanel)getContentPane();

 int labelX = 0;   //ラベルの位置x
 int  labelY = 0;   //ラベルの位置y

 public SwingworkerNasiTest() {
  //--------------------------- パネルとボタンを置く
  contentPane.add(panel,BorderLayout.CENTER);
  contentPane.add(btnWalk,BorderLayout.SOUTH);

  //---------------------------画面の設定
  this.setSize(500,300);
  this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  this.setVisible(true);

  //----------------- パネルの右下にペンギンの乗ったラベルを置く
  panel.setLayout(null);
  labelX = panel.getWidth()-WIDTH;
  labelY = panel.getHeight()-HEIGHT;
  label.setBounds(labelX, labelY, WIDTH, HEIGHT);
  panel.add(label);

  //--------------------------- ボタンの処理
  btnWalk.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent e) {   //①
    for(int i=0; i<10; i++) {
     labelX -= 5;
     label.setBounds(labelY, labelY, WIDTH, HEIGHT); //②
     try {
      Thread.sleep(300);
     } catch (InterruptedException e1) {}
    }
   }
  });
 }
 public static void main(String[] args) {
  new SwingworkerNasiTest();
 }
}



■■■■SwingWorkerとは

SwingWorkerクラスはイベントディスパッチスレッドと別スレッドで処理をしたいときに使います。
たとえば、イベントディスパッチスレッド上で実行されるactionPerformedの中で長~い処理を書いた場合、 その間、描画処理などができなくなってしまいます。
その長い処理は別スレッドで行えればよいわけです。
別スレッドで行う処理はSwingWorkerを継承したクラスのdoInBackgroundに記述し、actionPerformedの中でこのクラスのインスタンスを作成し、 実行を開始します。

これだけなら、普通のスレッドと同じ気もしますが、SwingWorkerの場合、別スレッドで行いたい処理と、 イベントディスパッチスレッドで行いたい処理 の両方を書くことができます。
別スレッドで行いたい長~い処理は、上述のとおり、doInBackgroundに記述し、 イベントディスパッチスレッド上で行いたい処理は、done()あるいはprocess()に記述します。
doneはdoInBackgroundが終了してから実行したい場合
processはdoInBackground実行中に実行したい場合に使います。

doneメソッドの中に書いた処理は、doInBackgourndメソッドが終了すると自動で呼び出され、イベントディスパッチスレッド上で実行されます。
processメソッドの中に書いた処理は、doInBackgroundの中で、publish()を呼び出すと、やはり、イベントディスパッチスレッド上で実行されます。

また、イベントディスパッチスレッド上で実行しなければいけないような処理が無い場合にはdoInBackgroundのみ作成すればよいのです。


■■■■SwingWorkerの2つの引数

SwingWorkerには
SwingWorker<Object,Object>
のように2つの引数があります。
この2つの型はdone、あるいは、processに渡すためのデータの型で、必要な型を書けばよいのです。

まず、1つ目の型はdoInBackgroundの戻り値の型で、これは、doneメソッドの中でget()を呼び出すことで使えます。

2つ目の型はdoInBackgroundの中でpublishを呼び出すときに、引数として使います。
この引数はprocessメソッドに渡されます。
また、doInBackgroundと、processは別スレッドで実行されるため、 1回目のporocessがまだ実行される前に2回目のprocessが呼び出される可能性もあります。
そのような場合、効率のために、processは1回の呼び出しにまとめられ、publish2回分の引数がprocessに渡されます。

たとえば、SwingWorker<T,V>とした場合、
void publish(V... chunks)
void process(List<V> chunks)
となり、publishで渡せるのは、V型の引数をいくつでも渡せるし、processでは、たまたま、publishを2回分実行するような場合には、 2回渡された引数を2個のListとして受け取ることができるようになります。
また、publishは可変個引数ですから、processに引数で渡すものが無い場合には、引数なしで呼び出せばよいことになります。


■■■■SwingWorkerサンプル

さて、上でうまくいかなかったプログラムをSwingWorkerを使って変更してみます。
まずSwingWorkerを継承したクラスを作成します。②
別スレッドで行うのは、300msec待つという長い処理です。これをdoInBackgroundに書きます。③
label.setBoundsの部分はイベントディスパッチスレッド上で実行しなければいけないので、processに書きます。⑤
ループの途中でprocessを呼び出したいので、publishを呼び出し、間接的にprocessを呼び出します。④

10回のループが終わった後、イベントディスパッチスレッド上で実行しなければいけないことはないので、 doneメソッドは、本当は作る必要はないです。削除しても大丈夫です。⑥

doInBackgroundからprocessに渡すデータはないので、publishの引数はなしです。④
引数の型は、使わないので、<Object,Object>としています。②

これで、SwingWorkerを継承したクラスができたので、actionPerformedの中で、このインスタンスを作り、executeを呼び出します。①
executeを呼び出すことにより、別スレッドで、doInBackgroundの実行が開始されます。


SwingWorkerを使ったクラス
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;

public class SwingworkerTest extends JFrame{
 private static int WIDTH = 29;
 private static int HEIGHT = 41;

 JButton btnWalk = new JButton("歩く");
 JLabel  label   = new JLabel(new ImageIcon("./penguin.gif"));
 JPanel  panel = new JPanel();
 JPanel  contentPane = (JPanel)getContentPane();

 int  labelX = 0;
 int  labelY = 0;

 public SwingworkerTest() {
  //--------------------------- パネルとボタンを置く
  contentPane.add(panel,BorderLayout.CENTER);
  contentPane.add(btnWalk,BorderLayout.SOUTH);

  //---------------------------画面の設定
  this.setSize(500,200);
  this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  this.setVisible(true);

  //----------------- パネルの右下にペンギンの乗ったラベルを置く
  panel.setLayout(null);
  labelX = panel.getWidth()-WIDTH;
  labelY = panel.getHeight()-HEIGHT;
  label.setBounds(labelX, labelY, WIDTH, HEIGHT);
  panel.add(label);

  //--------------------------- ボタンの処理
  btnWalk.addActionListener(new ActionListener(){
   public void actionPerformed(ActionEvent e) {
    MySwingWorker worker = new MySwingWorker();
    worker.execute(); //①
   }
  });
 }
 class MySwingWorker extends SwingWorker <Object,Object> { //②
  protected Object doInBackground() throws Exception { //③
   for(int i=0; i<10; i++) {
    publish(); //process()を呼び出す④
    try {
     Thread.sleep(300);
    } catch (InterruptedException e1) {}
   }
   return null;
  }
  protected void process(List <Object>  chunks) {  //⑤
   labelX -= 5;
   label.setBounds(labelX, labelY, WIDTH, HEIGHT);
   System.out.println("process");
  }
  protected void done() {     //⑥
   System.out.println("doInBackgroundの処理が終了しました");
  }
 }
 public static void main(String[] args) {
  new SwingworkerTest();
 }
}



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年5月26日火曜日

AndroidのListView内に複数項目を表示する方法(SimpleAdapterを使う)

目次へ



  • ListViewとは
  • ListViewをレイアウトの中で作成
  • ListViewの中の各項目用レイアウトの作成
  • プログラムでSimpleAdapterを作成し表示


■ListViewとは

いろいろなデータを一覧で表示するにはListViewを使うと便利です。
項目がたくさんあればスクロールも自動でできます
下の画面がListViewを使ったものです。
必要なものは
  • activity_main.xml この中でListViewを定義
  • item.xml ListViewの中の1つ分のデータ(下図の赤の部分)を定義
  • ActivityのonCreateメソッドでSimpleAdapterを作成しListViewの中に複数の項目を作成



■ListViewをレイアウトの中で作成

activity_main.xmlの内容

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:drawSelectorOnTop="false"
        android:layout_weight="1" />

    <TextView
        android:id="@id/android:empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</LinearLayout>



■ListViewの中の各項目用レイアウトの作成

item.xmlの内容

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/vw1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

        <TextView
           android:id="@+id/comment"
             android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>



■プログラムでSimpleAdapterを作成し表示

MainActivity.javaの内容


public class MainActivity extends ActionBarActivity {

 ArrayList<Map<String,Object>> list = new ArrayList<Map<String, Object>>();
 SimpleAdapter adapter;

 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  // ListView を取得
  ListView listView = (ListView) findViewById(R.id.listView);

  // SimpleAdapterに渡すArrayList作成
  createData();

  // リストビューに渡すアダプタを生成
  adapter = new SimpleAdapter(
   this,
   list,               //ArrayList
   R.layout.item,          //ListView内の1項目を定義したxml
   new String[] { "title", "comment","img" },    //mapのキー
   new int[] {R.id.title, R.id.comment, R.id.img });//item.xml内のid

  // アダプタをセット
  listView.setAdapter(adapter);
 }

 private void createData() {
  for (int n = 0; n < 15; n++) {
   Map data = new HashMap();
   data.put("title", "title" + n);
   data.put("comment", "comment" + n);
   data.put("img", R.drawable.ic_launcher);
   list.add(data);
  }
 }
}










にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年4月2日木曜日

AndroidのSoundPoolを使って効果音を鳴らす方法

目次へ



  • SoundPoolとMediaPlayer
  • SoundPoolを使って効果音を鳴らす方法


■■■■SoundPoolとMediaPlayer■■■■

SoundPool、MediaPlayer のどちらも音を鳴らすときに使います。
BGMのような長い音楽を鳴らすにはMediaPlayer、短い効果音などを鳴らすときには、SoundPoolが向いています。
SoundPoolの場合には、メモリにロードされた状態にしておいて、音を鳴らすため、遅延が少ないのが特徴です。

■■■■SoundPoolを使って効果音を鳴らす方法■■■■

使いたい効果音データはリソースとして、プロジェクトのresフォルダ内にrawという名前のフォルダを作成し、その中に保存をします。
SoundPoolのインスタンスを作成するには、SoundPool.Builderクラスのbuildメソッドを使います。
音を再生するにはplayメソッドを使います。
playメソッドの引数は次のようになっています。

int play (int soundID, float leftVolume, float rightVolume, 
   int priority, int loop, float rate)

soundID  サウンドID。loadメソッドが返した値
leftVolume 左のボリューム。範囲は0.0 ~ 1.0
rightVolume 右のボリューム。範囲は0.0 ~ 1.0
priority 優先度。0が優先度が最も低い
loop  ループモード。0:ループしない。-1:ループする
rate  再生速度。1:ノーマル。範囲は 0.5 ~ 2.0




下の例はbutton1を押すと、nyao.wav、button2を押すとgao.wavを再生します
playメソッドの引数を変更することにより、button1の方が小さい音。button2の方が大きい音となり、 また、button2の再生スピードの方が速く(高く)なります。

リソースは res/rawにnyao.wav、gao.wavを入れています。

public class MainActivity extends Activity {
 SoundPool soundPool;
 int sound1;
 int sound2;

 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 
  //--------------------- SoundPoolのインスタンス作成
  SoundPool.Builder builder = new SoundPool.Builder();
  soundPool = builder.build();

  //--------------------- 効果音をロードしておく。
  //------------引数はContext、リソースID、優先度
  sound1 = soundPool.load(this, R.raw.gao, 1);
  sound2 = soundPool.load(this, R.raw.nyao, 1);
 
  //---------------- button1を押すと効果音(nyao.wav)が鳴る。
  Button button1 = (Button) findViewById(R.id.button1);
  button1.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
    soundPool.play (sound1,0.5f,0.5f,0,0,1);
   }
  });

  //------------------button2を押すと効果音(gao.wav)が鳴る。
  Button button2 = (Button) findViewById(R.id.button2);
  button2.setOnClickListener(new View.OnClickListener() {
   public void onClick(View v) {
    soundPool.play (sound2,1.0f,1.0f,0,0,2);
   }
  });
 }
}





にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

AndroidのMediaPlayerを使ってBGMを流す方法

目次へ



  • MediaPlayerを使ってBGMを流す


■■■■MediaPlayerを使ってBGMを流す方法■■■■

BGMを鳴らすには、MediaPlayerを使います。
使いたい音楽データはリソースとして、プロジェクトのresフォルダ内にrawという名前のフォルダを作成し、その中に保存をします。
MediaPlayerのインスタンスを作成するには、MediaPlayer#createメソッドを使います。
下の例はstartボタンを押すとBGMがスタートし、stopボタンを押すとストップするだけのプログラムです


stopを呼び出した後、もう1回再生するには、もう1度createを実行し、MediaPlayerを作り直しています。
なにかほかに方法がありそうな気がします。
stopのあと、prepareメソッドを呼び出したりしてみましたが、うまくいきませんので、とりあえず、忘れないように、createし直す方法だけ書いておきます。
何かわかったら、また追記します。


参考までに、例外の種類は次のとおりです。
stopした後、すぐstartを実行すると、IOException。
stopした後、prepareを呼び出すと、IllegalStateExceptionとなります。


ActivityクラスのonCreateメソッドで次のようにしました
res/rawにはbgm.mp3を入れています。

protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);

 mp = MediaPlayer.create(this, R.raw.bgm);

 //--------------startボタンの処理
 Button buttonStart = (Button) findViewById(R.id.buttonStart);
 buttonStart.setOnClickListener(new View.OnClickListener() {
  public void onClick(View v) {
   if(!mp.isPlaying()){
    mp.start();
   }
  }
 });
 //--------------stopボタンの処理
 Button buttonStop = (Button) findViewById(R.id.buttonStop);
 buttonStop.setOnClickListener(new View.OnClickListener() {
  public void onClick(View v) {
   if(mp.isPlaying()){
    mp.stop();
    mp.release();
    mp = MediaPlayer.create
     (MainActivity.this, R.raw.bgm);
   }
  }
 });
}





にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年3月9日月曜日

Androidで画像を動かす SurfaceViewの使い方

目次へ



  • SurfaceViewとは
  • SurfaceViewを使って画像を動かす例
  • 画像をタッチしたらカウントしてみる


■■■■SurfaceViewとは■■■■

SurfaceViewが他のViewと異なるのはメインスレッド以外のスレッドから描画ができるという点です。
SurfaceView以外では、メインスレッドで描画処理をしなければならないため、定期的に再描画を繰り返すようなものには向きません。 その点、SurfaceViewは別のスレッドを作成し、その中で、ずっと再描画を繰り返すということができます。


■■■■SurfaceViewを使って画像を動かす例■■■■

  • まずは、SurfaceViewを継承したクラスを作成します。下の例のMyViewがそれです。
    コンストラクタでは、あとで表示をする時に使うために、リソースからBitmapオブジェクトを取り出しておきます①。

  • 表示用スレッドをスタートさせるのは画面が表示された時です。②はそのための処理です。
    画面が表示された時に呼び出されるのは、SurfaceHolder.CallbackインターフェースのsurfaceCreatedメソッドです。
    SurfaceHolder.Callbackインターフェースには、surfaceCreated⑤、surfaceChanged⑥、surfaceDestroyed⑦が定義されています。
    これらのメソッドをこのViewに登録するのが②です。

  • DrawThreadクラスは画像を表示するためのスレッドです。
    その中で、表示用のいろいろなメソッドを持つCanvasオブジェクトを取り出しているのが③です。
    このCanvasは他のスレッドからの描画を排他するので、lockCanvasというメソッド名となっています。
    そのため、描画が終わったら他のスレッドからの描画ができるようにするための④が必要です

  • 画像を表示するmydrawメソッドは、canvasを使ってランダムな位置に画像を表示しているだけです。
    このメソッドがスレッドから、2秒おきにずっと呼び出されます


MyViewクラス
import java.util.Random;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MyView extends SurfaceView implements Callback {
    Random random = new Random();
    Bitmap bitmap;  //表示画像
    int x;   //表示位置x
    int y;   //表示位置y
    int bitmapWidth; //画像サイズ 幅
    int bitmapHeight; //画像サイズ 高さ

    Thread thread = null; //画像を表示するスレッド

    public MyView(Context context) {
        super(context);
        bitmap = BitmapFactory.decodeResource
                       (getResources(), R.drawable.ic_launcher);     //①
        bitmapWidth = bitmap.getWidth();
        bitmapHeight = bitmap.getHeight();
        getHolder().addCallback(this);                               //②
    }
    //画像を表示するスレッド
    private class DrawThread extends Thread {
        public void run() {
            SurfaceHolder holder = getHolder();
            while(true) {
                Canvas canvas = holder.lockCanvas();                 //③
                if (canvas != null) {
                    mydraw(canvas);
                    holder.unlockCanvasAndPost(canvas);              //④
                }
                try {
                    sleep(2000);
                } catch (InterruptedException e) {}
            }
        }
    }
    //画像を表示する
    private void mydraw(Canvas canvas) {
        canvas.drawColor(Color.WHITE);

        int width  = canvas.getWidth() - bitmapWidth;
        int height = canvas.getHeight() - bitmapHeight;

        x = random.nextInt(width);
        y = random.nextInt(height);

        canvas.drawBitmap(bitmap, x, y, new Paint());
    }
    //-----画面が生成された時に呼び出される            ⑤
    public void surfaceCreated(SurfaceHolder holder) {
        thread = new DrawThread();
        thread.start();
    }
    //-----画面のサイズ等が変化した時に呼び出される    ⑥
    public void surfaceChanged(SurfaceHolder holder,
                            int format, int width, int height) {
    }
    //-----画面が削除された時に呼び出される            ⑦
    public void surfaceDestroyed(SurfaceHolder holder) {
       thread = null;
    }
}



このMyViewクラスのインスタンスをActivityクラスのonCreate内のsetContentViewに渡せば表示されます。


Activityクラス
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(new MyView(this));
 }



■■■■画像をタッチしたらカウントしてみる■■■■

上のMyViewクラスのフィールドに、画像をタッチできたらカウントしてその数を表示するようにしてみます。


public class MyView extends SurfaceView implements Callback {
    ------フィールド追加------
    int count = 0; 

    private void mydraw(Canvas canvas) {
        ------最後に次の3行を追加------
        Paint p = new Paint();
        p.setTextSize(35);
        canvas.drawText("タッチできた数"+count, 50, 50, p);
    }

    -------タッチした時に呼び出されるメソッドを追加------
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int cx = (int)event.getX();
        int cy = (int)event.getY();
        if(x <= cx && cx <= x+bitmapWidth && y < cy && cy <= y+bitmapHeight) {
            count++;
        }
        return super.onTouchEvent(event);
    }
}



にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年1月27日火曜日

Googleマイマップ をブログに埋め込む

目次へ



Google のマイマップを作成し、地図上にラインなどを描画したものをWebサイトやブログに貼りつける方法です。


■■■■マイマップを作成■■■■

Googleアカウントでログインし、Google Mapの検索ボックスをクリックするとマイマップ作成リンクがあるのでそれをクリック。
その後、作成リンクをクリックします。




この後、下のようなボタンが表示され、マーカを作成、ライン描画、ルート表示、などができるようになります。




できあがったら、無題の地図と表示されているところをクリックし、タイトルなどを入力し、保存ボタンを押せばマイマップが作成できます。


■■■■マイマップを表示■■■■

Google Mapの検索ボックスをクリック、マイマップをクリック、 表示されるマイマップのタイトルをクリックで、保存したマイマップを表示することができます。


■■■■マイマップを埋め込む■■■■

まず、一般公開の設定です。
共有(赤い矢印)をクリックしし、共有設定のウィンドウで、非公開と表示されている部分の右にある、「変更」をクリックします。
新しく表示されたリンクの共有ウィンドウで、「ウェブ上で一般公開」を選択し、保存をします。
これで、一般公開ができるようになりました。

次は、マイマップを埋め込むためのコードを取得します。
下の図の黒い矢印の部分をクリックします。すると、メニューが出てきますので、その中の、「自分のウェブサイトに埋め込む」をクリックします。
すると、「<iframe src=・・・」と書かれたHTMLが表示されますので、それをコピーして、自分のブログなどに貼り付ければOKです。





■■■■マイマップを削除■■■■

上の図の黒い矢印をクリックしたときに出てくるメニューの中に、「この地図を削除する」があるので、それをクリックすれば、その時表示されているマイマップを削除することができます。





にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村

2015年1月11日日曜日

Conversion to Dalvik format failed の対処

目次へ



EclipseでAndroidプロジェクトを作成している時にコンパイルエラーが表示されているわけでもないのに実行してみると「Conversion to Dalvik format failed」と表示され実行できない時の対処です。


■■■■対処法■■■■

Android プロジェクトを実行をしてみると Conversion to Dalvik format failed のエラーが出ました。 コンパイルエラーが表示されていないのでわけが分からず検索をしてみました。 http://ksggk.hateblo.jp/entry/2013/12/08/213316 のページを参考にさせていただきました。 自分の場合1から順番に試してみたところ、eclipseのクリーンを実行したところで、うまくいきましたので、4,5は試していません。
  1. プロジェクト→クリーン
    プロジェクトをクリックし、メニューの[プロジェクト]-[クリーン]をクリック
  2. プロジェクトを右クリックし[Androidツール]-[プロジェクト・プロパティーを修正]
  3. eclipseのクリーン
    eclipseフォルダ内のeclipse.exe -clean.cmd(eclipse.exe -cleanを実行と同じ)を使ってeclipseを再起動
  4. binとgenフォルダの削除
    これ
  5. プロジェクトのビルド・パスの構成→順序およびエクスポートの調整



ところで、eclipseの-cleanオプションははどのような時に使うかというと、プラグインを追加した直後の起動では、このオプションの指定が必須だそうです。
また、毎回付加しても問題のないオプションです。ただちょっと起動が遅くなります。


にほんブログ村 IT技術ブログ IT技術メモへ
にほんブログ村