2015年2月6日金曜日

Androidアプリ開発

開発時の注意点

activity_main.xml:画面のレイアウト

fragment_main.xml:端末の断片化に対応した画面レイアウト
→面倒なのでとりあえず対応しない

※Activityクラスのサブクラスは以下の記述だけでよい

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




レイアウト

activity_main.xml→アウトラインのcontainerを右クリック→レイアウトの変更
→レイアウトの方法を変えられる

RelativeLayout:相対的なポジションで場所を決められる
LinearLayout:縦または横一列に配置する




画面

Activityのサブクラスで画面を制御する



ライフサイクル

onCreate:最初に呼ばれる
onStart:onCreateの後、またはonStopの後に画面がアクティブになった場合
onPause:他の画面がアクティブになった場合
onResume:onPauseの後に画面がアクティブになった場合
onStop:しばらく画面がアクティブにならない場合



画面上のオブジェクトへのアクセス

genフォルダに自動生成される「Rクラス」を利用する
→R.javaの各オブジェクト毎のidを使う

例)button1のidを使う

R.id.button1




レイアウト上のオブジェクトを取得

findViewById(R.id.取得するオブジェクトのID);



ボタンクリック

ButtonオブジェクトにsetOnClickListenerでリスナーを設定する
→引数はOnClickListenerインターフェイスの実装クラスのインスタンス

引数のオブジェクトの「public void onClick(View v)」メソッドにクリック後の処理を記載する
※onClickの引数にはクリックされたオブジェクトが格納されている


例)button1がクリックされた場合

Button btn = (Button) findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
  public void onClick(View v) {
    Log.d("TAG", v.getId() + " Click!");
  }
});



ボタンクリック2

View→On Clickにクリック時に呼ばれるメソッド名を記載

そのメソッドにクリック時の処理を記載
→引数はViewクラスのインスタンスとする

例)
public void OnBtnClick(View v) {
  Log.d("TAG", "Btn Click!");
}




ボタンクリック3

ActivityでOnClickListenerをimplementsする

ButtonクラスのsetOnClickListenerの引数を自分自身(this)とする





サイズの単位

dp:密度
sp:文字のサイズ




文字入力の更新を監視

EditTextのインスタンス.addTextChangedListener(TextWatcherを実装したインスタンス)




画面の回転

onDestroyが呼ばれる
→設定した値が無くなる

値を保存しておく必要がある


onSaveInstanceState(Bundle outState)で保存
onRestoreInstanceState(Bundle savedInstanceState)で再設定



@Override
protected void onSaveInstanceState(Bundle outState) {
  super.onSaveInstanceState(outState);
  outState.putString("txtResult", tv.getText().toString());
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  tv.setText(savedInstanceState.getString("txtResult"));
}




ソフトウェアキーボードを消す

InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

 ※vはandroid.view.Viewクラスのインスタンス



Context

アプリケーションのグローバルな環境情報を受け渡すために使用されるもの

以下の方法で取得することができる

・アクティビティ.this
・getApplication()
・getApplicationContext()

※アクティビティ.thisはメモリリークの原因になるので使わない




ユーザーへの通知

Toast.makeText(コンテキスト, メッセージ, 時間※).show();


※時間
Toast.LENGTH_SHORT:短時間
Toast.LENGTH_LONG:長時間

例)MainActivityにMsg!と通知する
Toast.makeText(MainActivity.this, "Msg!", Toast.LENGTH_SHORT).show();



ビューのカスタマイズ

Viewを設定(setView)することでカスタマイズできる

例)
TextView textView = new TextView(this);
textView.setText("カスタマイズ");
Toast toast = Toast.makeText(this, "左", Toast.LENGTH_LONG);
toast.setView(textView);



ラジオボタン

RadioGroupを使用する


ラジオボタンクリック時の処理

setOnCheckedChangeListenerを設定する
→引数はOnCheckedChangeListenerを実装したインスタンス


onCheckedChanged(RadioGroup group, int checkedId)に処理を記載
→checkedIdにチェックしたラジオボタンのidが格納されている



選択されているラジオボタンの取得

ラジオグループ.getCheckedRadioButtonId()
→選択されているラジオボタンのIDを返す




シークバー

setOnSeekBarChangeListenerを設定する
→引数はOnSeekBarChangeListenerの実装したインスタンス

onStopTrackingTouch(SeekBar seekBar)
→つまみを離した時

public void onStartTrackingTouch(SeekBar seekBar)
→つまみをタッチした時

onProgressChanged(SeekBar seekBar, int progress, boolean fromUser)
→値を更新したとき(progressに値が格納)





リストビュー

Adapterパターンを使用している
→ArrayAdapterなどにデータを入れる

データを設定してリストビューにセット(setAdapter)する


ArrayAdapter

new ArrayAdapter<型>(コンテキスト, レイアウト, データ);


例)
ArrayList<String> data = new ArrayList<String>();
data.add("abc");
lv = (ListView)findViewById(R.id.listView1);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data);
lv.setAdapter(adapter);



リストビューのアイテムをクリック

リストビューにsetOnItemClickListenerでリスナーを設定する

→onItemClick(AdapterView<?> av, View view, int position, long id)をオーバーライドしてクリック後の処理を記載

view:クリックされたItem
position:ItemのIndex




リストビューのアイテムを長押し

リストビューにsetOnItemLongClickListenerでリスナーを設定

→onItemLongClickをオーバーライドして、長押し時の処理を書く

※戻り値のbooleanはクリックイベントを消費するかどうか
 (trueにするとクリックイベントは発生しない)






リストビューのレイアウトを作成


1.layoutフォルダに一行分のレイアウト(XML)を作成

2.アダプターを作成
→レイアウトと表示するデータを受け取る

3.レイアウトとデータを設定
→アダプターの「getView」をオーバーライドしそこで行う

※getViewはリストビューの列を表示しようとする度に呼ばれる
  (positionは列のインデックス、convertViewは再利用可能なview)


4.アダプターをリストビューにセット


例)アダプタの作成例
public class MyAdapter extends ArrayAdapter<String> {

  LayoutInflater inflater;
  int resource;
  List<String> objects;

  public MyAdapter(Context context, int resource, List<String> objects) {
    //レイアウトとデータを受け取りフィールドにセット
    this.resource = resource;
    this.objects = objects;

    inflater = ((Activity)context).getLayoutInflater();
  }

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

    //対象となる行数のデータを取得
    String str = objects.get(position);
    View v;

    if (convertView != null) {
      //再利用する
      v = convertView;
    } else {
      //レイアウトをinflate
      v = inflater.inflate(resource, null);
    }
    //データをビューにセット
    ((TextView)v.findViewById(R.id.textView1)).setText(str);

    return v;
  }
}


ViewHolderパターン

上記の例ではfindViewByIdがリストビューの列数回呼ばれる
→処理が重くなる

findViewByIdした結果を保持するクラスを作成し、そのインスタンスをタグに持たせる
→Viewの再利用時はタグから保持クラスを取得する

例)保持クラスの例
class ViewHolder {
  TextView tv1;
  public ViewHolder(View v) {
    tv1 = (TextView)v.findViewById(R.id.textView1);
  }
}


例)保持クラスを利用した例
public View getView(int position, View convertView, ViewGroup parent) {

  String str = data.get(position);
  ViewHolder holder;
  View v;

  if (convertView != null) {
    v = convertView;
 
    //タグから保持クラスを取得
    holder = (ViewHolder)v.getTag();
  } else {
    v = inflater.inflate(resource, null);
 
    //保持クラスを生成しタグにセット
    holder = new ViewHolder(v);
    v.setTag(holder);
  }

  //保持クラスを利用して値をセット
  holder.tv1.setText(str);

  return v;
}




画像の取り扱い

res→drawable-○○○フォルダ
→解像度毎に画像を分けて入れる

※1つの画像のみを使用する場合は「drawable-hdpi」に置く



画像を表示

ImageViewを使用する

setImageResourceで画像をセットすると表示を切り替えられる
→画像の指定は「R.drawable.画像名」とする


※Android標準の画像を使うこともできる
android.R.drawable.イメージ名




ビューの表示/非表示

ビュー.setVisibility(visibility)

※visibility
View.VISIBLE:表示
View.INVISIBLE:非表示(スペースは空いたまま)
View.GONE:非表示(スペースを詰める)




ビューの動的生成

ビューのインスタンスを生成して設定する

例)
TextView textView = new TextView(this);
textView.setTextColor(Color.GREEN);
textView.setTextSize(100);
textView.setText("カスタマイズ");



レイアウトファイルから生成する

インフレーターを取得し、レイアウトをinflateする
→項目を修正する場合はレイアウトからfindViewByIdで取得する


例)

//インフレーターを取得
LayoutInflater inflater = getLayoutInflater();

//レイアウトをinflateする
View layout = inflater.inflate(R.layout.toastlayout, null);

//TextViewを取得し、変更
TextView text = (TextView)layout.findViewById(R.id.textView1);
text.setText("変更");




データの保存


SharedPreferences

Key/Valueの方式でデータを保存できる
→端末内部にXMLファイルを生成しそこに保存している


生成

getSharedPreferences(名前, モード);
→SharedPreferencesのインスタンスを返す



モード(Activityの定数)

MODE_PRIVATE:そのアプリのみアクセス可
MODE_WORLD_READABLE:他のアプリから読み取り可
MODE_WORLD_WRITEABLE:他のアプリから書き込み可
MODE_MULTI_PROCESS:複数のプロセスからアクセス可


データの取得

get○○○(キー名, デフォルト値);
→○○○は取得したいデータの型(String,Int,…)

※getAll()で全てのデータをMapで返す


データの保存

1.edit()でEditorインスタンスを取得する

2.エディターのput○○○(キー, 保存する値)で保存
→○○○は保存するデータの型(String,Int,…)

3.エディターのcommit()で保存の確定



例)

//生成
SharedPreferences sp = getSharedPreferences("SP", MODE_PRIVATE);

//取得
String str = sp.getString("KEY1", "");

//保存
Editor editor = sp.edit();
editor.putString("KEY1", "abc");
editor.commit();




ファイルの読み書き

基本的にはJavaのファイル読み書きと同じで以下が異なるだけ

InputStreamの取得
openFileInput(ファイル名);


OutputStreamの取得
openFileOutput(ファイル名, モード);

モード
MODE_APPEND:追記書き込み
MODE_PRIVATE:そのアプリのみアクセス可
MODE_WORLD_READABLE:他のアプリから読み取り可
MODE_WORLD_WRITEABLE:他のアプリから書き込み可



例)読み込み

InputStream in = openFileInput("myfile.txt");
InputStreamReader isr = new InputStreamReader(in, "UTF-8");
BufferedReader br = new BufferedReader(isr);
String lineStr;
StringBuilder sb = new StringBuilder();
while ((lineStr = br.readLine()) != null) {
sb.append(lineStr);
}
br.close();



例)書き込み

OutputStream out = openFileOutput("myfile.txt", MODE_PRIVATE);
OutputStreamWriter osw = new OutputStreamWriter(out, "UTF-8");
PrintWriter pw = new PrintWriter(osw);
pw.append("ABC");
pw.close();



assetsフォルダ内のファイルを読み込み

AssetManagerを取得し、ファイルをopenしてInputStreamを取得する

例)
AssetManager am = getResources().getAssets();
InputStream is = am.open("myfile.txt");



画面遷移


新規レイアウトの追加

layoutフォルダにxmlファイルを追加する



新規Activityの追加

新規→その他→Android→Androidアクティビティー

※上記方法を使わない場合はAndroidManifest.xmlの修正が必要



マニフェストファイル

activityタグ内に以下の記載があるものが最初に起動する画面

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>


アプリケーションタブ→Application Nodes→追加で新規Activityを追加する


※Activityの起動モード

デフォルトでは遷移の度に新しいActivityを生成する

Application NodesでActivityを選択しLaunch modeで変更できる
→singleInstanceで生成するActivityを1つだけにできる



インテント(Intent)を生成する

new Intent(遷移元のActivity, 遷移先のクラスファイル名)



インテントを使用する

startActivity(intent);



Activityを消す

finish()でActivityを消せる
→Launch modeをsingleInstanceにするのと同様の処理が可能



例)MainActivityからNextActivityへ遷移
Intent intent = new Intent(MainActivity.this, NextActivity.class);
startActivity(intent);
finish();





画面遷移時のデータの受け渡し


データを渡す

IntentのputExtraメソッドでデータを渡す

インテント.putExtra(キー, 値);

例)
Intent intent = new Intent(this, NextActivity.class);
intent.putExtra("name", "Ken");



データを受け取る

getIntent()でインテントを取得し、get○○Extra(キー)で取得
→○○は受け取るデータの型名

例)
Intent intent = getIntent();
String name = intent.getStringExtra("name");



オブジェクトを受け渡しする場合

受け渡しするオブジェクトはSerializableをimplementsする

受け取るときはgetSerializableExtra(キー)で取得
→戻り値がObject型なのでキャストが必要




画面遷移した結果を受け取る

画面遷移時に次画面へrequestCodeを送り、それに対して送信元へ結果を返すことができる



Requestの送信と画面遷移

startActivityForResult(インテント, リクエストコード);
→リクエストコードはint型



次画面で結果のセット

setResult(結果コード, Intent型のデータ);
→Intent型のデータは省略可

※データを作るときは引数無しのコンストラクタで生成
→new Intent();


結果の受け取り

Request送信元でonActivityResultメソッドをオーバーライドすると結果を受け取れる
→次画面で結果をセットするとRequest元のonActivityResultが呼ばれる

第一引数:リクエストコード
第二引数:結果コード
第三引数:Intent型のデータ




暗黙的インテント


暗黙的インテントを利用することで他のアプリケーションを起動できる
→startActivityForResultで起動する

Intent intent = new Intent(起動したい内容, 必要な情報);


例)ダイアラー起動
Uri uri = Uri.parse("tel:0120-123-123");
Intent intent = new Intent(Intent.ACTION_DIAL, uri);
startActivityForResult(intent, REQUEST_CODE);


例)ブラウザ起動
Uri uri = Uri.parse("http://google.co.jp/");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivityForResult(intent, REQUEST_CODE);




パーミッションの設定

電話をかける、通信などの機能は許可権限を記述する必要がある
→パーミッション無しでやろうとすると落ちる


パーミッションの付与

AndroidManifest.xml→下の「許可」タブ→追加→Uses Permission
→Nameに許可したい機能を選択する

例)通信の許可は「android.permission.INTERNET」





自作のアプリケーションで開く

アプリケーションから他のアプリケーションを起動する
→起動する「アプリケーションの選択」に自作アプリが表示される



呼び出し側

//データを他のActivityに送信する
Intent i = new Intent(Intent.ACTION_SEND);

//データの種類を指定
i.setType("text/plain");

//データを設定(EXTRA_TEXT:テキストデータ)
i.putExtra(Intent.EXTRA_TEXT, "ABC");

//起動
startActivity(i);




受け取り側

AndroidManifest.xmlの「intent-filter」を以下に変更

<intent-filter>
    <action android:name="android.intent.action.SEND" />
    <data android:mimeType="text/plain" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>


※受け取り側は先にインストールしておく必要がある




ダイアログ


ダイアログの表示

AlertDialog.Builder alert = new AlertDialog.Builder(this);
alert.setTitle("確認");
alert.setMessage("よろしいですか?");

alert.show();



OKボタンの追加とクリック時の処理

alert.setPositiveButton("はい", new DialogInterface.OnClickListener() {
  @Override
  public void onClick(DialogInterface arg0, int arg1) {
  Toast.makeText(MainActivity.this, "実行しました", Toast.LENGTH_SHORT).show();
  }
});



NGボタン

setNegativeButton


キャンセルボタン

setNeutralButton


※メッセージをリスト表示にすることもできる



その他のダイアログ

・日付:DatePickerDialog
・時間:TimePickerDialog
・進捗:ProgressDialog



ProgressDialog


※ProgressDialogは別スレッドからアクセスできる


例)スレッドで水平バーの進捗を管理

ProgressDialog p  = new ProgressDialog(this);

p.setTitle("処理中…");
p.setMessage("処理終了までお待ちください");

//水平バーを表示
p.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

//閉じられないようにする
p.setCancelable(false);

p.show();

//スレッドで進捗を管理
Thread t = new Thread(new Runnable() {

  @Override
  public void run() {
    int count = 1;
    while (true) {
      //進捗を増やす
      p.setProgress(count);
      count++;
      try {
        Thread.sleep(100);
      } catch (InterruptedException e) {
        Log.e("TAG", e.toString());
      }
      //進捗が最大値を超えたら終了
      if (count >= p.getMax()) {
        break;
      }
    }
    //ダイアログを閉じる
    mProgressDialog.dismiss();
  }
});
mThread.start();



スレッド

AndroidのUIは別のスレッドから操作することができない
→Handlerを利用する

Handler handler = new Handler();
handler.post(Rannableを実装したインスタンス);




定期処理

ScheduledExecutorServiceを利用する

scheduleAtFixedRate((Rannableを実装したインスタンス, delay時間, 繰り返しの時間, 時間の単位);
→処理を止める場合は「shutdown()」


例)2秒待ってから1秒毎に処理を行う
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(this, 2, 1, TimeUnit.SECONDS);



定期処理2

TimerTaskを利用しても実現できる

schedule(TimerTaskオブジェクト, delay時間, 更新時間(ms));
→処理を止める場合は「cancel()」


例)2秒待ってから1秒毎に処理を行う
mTimerTask = new MyTimerTask();
Timer timer = new Timer();
timer.schedule(mTimerTask, 2, 1000);




非同期処理

AsyncTaskを利用する
→AsyncTaskのサブクラスを作成する

AsyncTask<非同期で扱いたいオブジェクトの型, 進捗を管理するための型, 実行結果を受け取るための型>


実行前の処理

onPreExecute()


実行

AsyncTaskのサブクラスのインスタンス.execute(非同期で扱いたいオブジェクトの型)
→doInBackgroundが呼ばれる

※スレッドの部分なのでUIの変更はできない


進捗管理

doInBackground内でpublishProgress(進捗を管理するための型)を実行する
→onProgressUpdateが呼ばれる

※UIの変更はここで行う


終了

onPostExecute(実行結果を受け取るための型)が呼ばれる

※ここでもUIの変更可能



例)ログを100回表示(進捗を10回毎に表示)

//匿名クラスで非同期処理を行う
new AsyncTask<Integer, Integer, Boolean>() {

  @Override
  protected Boolean doInBackground(Integer... params) {
    for (int i = params[0]; i < 100; i++) {
      if (i % 10 == 0) {
        publishProgress(i);
      }
      Log.d("TAG", "i=" + i);
    }
    return true;
  }

  @Override
  protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
    Log.d("TAG", "onProgressUpdate:" + values[0]);
  }

  @Override
  protected void onPostExecute(Boolean result) {
    super.onPostExecute(result);
    Log.d("TAG", "onPostExecute:" + result);
  }
}.execute(1);




AsyncTaskLoaderでの非同期処理

スレッド本体の処理のみを記述し、前処理や終了後の処理はコールバック関数を呼び出す
→UIから独立した処理をAsyncTaskLoaderに、UIの操作はActivity(コールバック関数を実装)にそれぞれ記述することができる


※サンプルコードの注意点

p123 上のコード:FragmentActivity
→4系の場合はActivityでよい


p123 下のコード:getSupportLoaderManager()
→4系の場合はgetLoaderManager()でよい


AsyncTaskLoader


クラス定義

AsyncTaskLoader<処理を行うメソッドの戻り値>のサブクラスを定義


処理

戻り値 loadInBackground()



コールバック関数の定義

LoaderCallBacks<ローダーの戻り値>インターフェイスを実装


前処理の定義

onCreateLoader(ID値, バンドルに格納したパラメータ)


終了後処理の定義

onLoadFinished(ローダー, 処理の戻り値)


処理がリセットされた場合の処理

onLoaderReset(ローダー);


Bundle

パラメーターの入れ物

値の設定:set○○○(キー, 値)
値の取得:get○○○(キー)
※○○○は値の型


AsyncTaskLoaderの呼び出し

getLoaderManager().initLoader(ID値, Bundle, コールバック関数を実装したオブジェクト)
→onCreateLoaderメソッドが呼ばれるのでその中でローダーを生成する



AsyncTaskLoaderの生成

インスタンスを生成し(引数はコールバック関数を実装したオブジェクト)、「forceLoad()」メソッドを実行する
→AsyncTaskLoaderに記述した処理「loadInBackground()」が実行される




独自のViewを作成


Viewを継承したクラスを作成
→コンストラクタを定義する必要がある


Viewのコンストラクタ

・画面レイアウトのXMLを使用する場合は引数2つを利用
・独自のスタイルを利用する場合は引数3つ



独自の描画処理

OnDraw()をオーバーライドする
→Canvasを利用することで描画処理を行うことができる


Paint

Cancasに描画する筆のようなもの
→描画時の色やテキストサイズを設定できる

例)色を青に設定
Paint paint = new Paint();
paint.setColor(Color.BLUE);


テキストの描画

キャンバス.drawText(文字, X座標, Y座標, ペイント);


画面レイアウトに独自のViewを設定

レイアウトの一番下の「カスタム&ライブラリー・ビュー」に自分の作ったビューが表示される
→ドラッグ&ドロップでレイアウトに設置できる

※表示されない場合は「リフレッシュ」ボタンを押す



独自Viewに画像を表示

Bitmapオブジェクトを生成し、drawBitmapでキャンバスに描く


Bitmapオブジェクトの生成

BitmapFactory.decodeResource(getResources(), drawable内の画像のID)


Bitmapの描画

キャンバス.drawBitmap(Bitmapオブジェクト,  X座標, Y座標, ペイント);

例)
//drawableの画像を取得
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
canvas.drawBitmap(bitmap, 100, 100, null);



SurfaceViewの利用

ダブルバッファリング処理を行うことができる
→アニメーション時のチラツキを防ぐ


SurfaceViewの実装

1.SurfaceViewのサブクラスを作る


2.SurfaceHolder.Callbackインターフェイスを実装する
→メソッドを実装する

3.surfaceCreated以降に描画処理を記述



SurfaceViewへの描画


1.キャンバスの取得(ロック)

getHolder().lockCanvas();
→nullになる可能性があるのでチェックが必要


2.キャンバスに描画


3.キャンバスのロック解除と送信

getHolder().unlockCanvasAndPost(キャンバス);



SurfaceViewからの通知

SurfaceViewが破棄された場合などを通知してほしい
→SurfaceHolder.Callbackインターフェイスを実装する



コールバックの登録

通知を受け取るためには登録が必要
→コンストラクタに以下を記述

getHolder().addCallback(this);



コールバック

以下のメソッドがそれぞれのタイミングで呼ばれる

surfaceChanged:変更された時
surfaceCreated:作成されたとき
surfaceDestroyed:破棄されたとき




Viewのタッチ処理

Viewをタッチしたときに処理をしたい
→ViewクラスのonTouchEventをオーバーライドする

public boolean onTouchEvent(MotionEvent event) {

  //タッチした場所(X,Y)を取得
  float x = event.getX();
  float y = event.getY();

  //戻り値はイベント消費するかどうか
  return false;
}

イベントの取得

event.getAction()


イベントの種類

タッチ開始:MotionEvent.ACTION_DOWN
ドラッグ:MotionEvent.ACTION_MOVE
タッチ終了:MotionEvent.ACTION_UP

例)
switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
    //タッチ開始
    break;
 
  case MotionEvent.ACTION_MOVE:
    //ドラッグ
    break;
 
  case MotionEvent.ACTION_DOWN:
    //タッチ終了
    break;
 
}


排他制御

synchronizedブロックを利用することで排他制御ができる
→メインスレッドと他のスレッドで同じオブジェクトにアクセスする場合に使用する

synchronized (排他制御するオブジェクト) {
  排他制御するオブジェクトを操作する処理
}




線を描画する


Paintの設定

スタイル:setStyle
太さ:setStrokeWidth
先端の形:setStrokeCap
繋ぎ目の形:setStrokeJoin



Pathの設定

始点:moveTo(X座標, Y座標)
点:lineTo(X座標, Y座標)



Pathを描画

キャンバス.drawPath(パス, ペイント)




文字リソース

1ファイルに一元管理する
→「res→values→strings.xml」に記述する


例)「@string/action_settings」の場合
<string name="action_settings">Settings</string>




メニュー

画面上部のアクションバーにメニューが表示される


レイアウトファイルを使った場合

public boolean onCreateOptionsMenu(Menu menu) {
 
    //menu→main.xmlを見に行く
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}


public boolean onOptionsItemSelected(MenuItem item) {
    //押されたメニューの取得
    int id = item.getItemId();
 
    //メニューが押された場合の処理
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

main.xml

<item
    android:id="@+id/action_settings"
    android:orderInCategory="100"
    android:showAsAction="always"
    android:title="@string/action_settings"/>

※showAsActionで表示のやり方を変えられる



動的メニュー追加

onCreateOptionsMenuの中で、メニューを追加する

メニュー.add(メニュータイトル);
→MenuItemが戻り値



MenuItemのクリックイベント

メニューアイテム.setOnMenuItemClickListener
→引数は「OnMenuItemClickListener」型




通信



基本は以下のやり方

※パーミッションに「android.permission.INTERNET」を追加する

※通信は別スレッドで処理を行う


//HTTP通信する仕組み
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse res;
HttpEntity entity;

try {
  //HTTP通信する(リクエストを送信する)
  res = client.execute(get);

  //ステータスコードのチェック(200:OK)
  if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
 
    //ボディ部を抽出する
    entity = res.getEntity();
 
    //受信データを文字列に変換する
    str = EntityUtils.toString(entity, "UTF-8");
  }
} catch (ClientProtocolException e) {

} catch (IOException e) {

} finally {
  client.getConnectionManager().shutdown();
}



エミュレーターからローカルPCの通信

ホスト名を「10.0.2.2」



実機からローカルPCへの通信

1.Androidの実機とPCは同じWiFiに接続する
2.AndroidからPCに振られているIPアドレスでアクセスする




XMLの解析


XmlPullParser parser = Xml.newPullParser();
parser.setInput(new StringReader(XMLデータ));
int eventType = parser.getEventType();

while (eventType != XmlPullParser.END_DOCUMENT) {
  if (eventType == XmlPullParser.START_TAG) {
    if ("取得したいタグの名前".equals(parser.getName())) {
      eventType = parser.next();
      if (eventType == XmlPullParser.TEXT) {
        parser.getText()でタグの値を取得
      }
    }
  }
  eventType = parser.next();
}

※パーサー.nextText()で次の要素の値を取得できる


JSONの解析


JSONObject jsonObj = new JSONObject(JSONデータ);
JSONArray jsonArr = jsonObj.getJSONArray(root要素名);

for (int i = 0; i < jsonArr.length(); i++) {
  JSONObject jo = jsonArr.getJSONObject(i);
  if (jo.has(取得したい要素名)) { //要素の存在確認
    jo.getString(取得したい要素名)で値を取得
  }
}




サーバーへPOST

HttpPost request = new HttpPost(サーバーのURL);
client = new DefaultHttpClient();

//送信するデータのリスト
ArrayList<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();

//Key&Valueの方式で送りたいデータを作成
nameValuePair.add(new BasicNameValuePair("data1", "value1"));
request.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));

//サーバーへPOST
HttpResponse response = client.execute(request);





XMLの生成

//準備
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
db = dbf.newDocumentBuilder();
Document document = db.newDocument();

//データ登録
Element root = document.createElement(ルート名);
document.appendChild(root);

Element element = document.createElement(キー);
root.appendChild(element);
Text text = document.createTextNode(値);
element.appendChild(text);

//データ変換
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
DOMSource source = new DOMSource(document);
transformer.transform(source, result);

writer.toString(); //XMLをStringに変換




PHPでのXMLのパース

simplexml_load_string(XMLデータ)
→SimpleXMLElementのデータを返す



Jsonの生成

JSONObject addressObj = new JSONObject();
JSONArray personAry = new JSONArray();
for (Person p : list) {
JSONObject personObj = new JSONObject();
personObj.put("name", p.name);
personObj.put("age", p.age);
personObj.put("blood", p.blood);

personAry.put(personObj);
}
addressObj.put("address", personAry);
jsonString = addressObj.toString();




PHPでのJson出力

<?php
$ary = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4);
header('Content-type: application/json; charset="utf-8"');
echo json_encode($ary);



PHPでJsonから配列の変換

$str = file_get_contents(取得するJsonデータのURL);
$ary = json_decode($str, true);



画像を通信で取得


DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(url);
HttpResponse res = client.execute(get);

if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){

  //ボディ部を抽出する。
  HttpEntity entity = res.getEntity();

  //入力データを取得する
  InputStream is = entity.getContent();

  //画像データに変換する
  Bitmap bmp = BitmapFactory.decodeStream(is);
}



画像のリサイズ

float resizeScaleWidth = 0.0f;
float resizeScaleHeight = 0.0f;

Matrix matrix = new Matrix();
resizeScaleWidth = resizeWidth / bitmap.getWidth();
resizeScaleHeight = resizeHeight / bitmap.getHeight();
matrix.postScale(resizeScaleWidth, resizeScaleHeight);
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), this.bitmap.getHeight(), matrix, true);

※bitmapはリサイズしたいBitmap型のインスタンス




Web View


ブラウザでWebページを表示する

WebView wv = (WebView)findViewById(R.id.webView1);
wv.loadUrl("http://yahoo.co.jp/");



Web ViewでWebページを表示する

WebView wv = (WebView)findViewById(R.id.webView1);

wv.setWebViewClient(new WebViewClient() {

  @Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
    return false;
  }
});

wv.loadUrl("http://yahoo.co.jp/");




JavaScriptを使用できるようにする

WebSettings webSettings = wv.getSettings();
webSettings.setJavaScriptEnabled(true);




サウンド再生

//SoundPoolインスタンス作成引数は
//ロードするファイルの数,ストリームのタイプ,
//サンプリングレートのクオリティ(デフォルトは0)
sp= new SoundPool( 1, AudioManager.STREAM_MUSIC, 0 );

//ロード完了が知りたい場合。省略可
sp.setOnLoadCompleteListener(new OnLoadCompleteListener() {
  @Override
  public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
    //ロードが完了するとここを通る。boolean 変数を設定して、
    //後の処理に繋げることも可
    Toast.makeText(MainActivity.this, "soundOK", Toast.LENGTH_SHORT).show();
  }
});

//id取得
//引数はcontext,リソースid,1(規定)
//音声ファイルはwav,ogg形式。
//ファイル名の先頭はアルファベット小文字がよい
sounds_id = sp.load(this, R.raw.se1, 1 );



//再生。id,音量左0.0~1.0,音量右,優先度(0がMax),
//再生回数(-1で無限ループ、0でループしない)
//再生速度(0.5~2.0:0.5倍から2倍)
sp.play(sound_id, vol, vol, 0, 0, 1.0F);






SQLite


DBの生成、接続

SQLiteOpenHelperのサブクラスを利用する

public class MyOpenHelper extends SQLiteOpenHelper {

  public MyOpenHelper(Context context, String name, CursorFactory factory, int version) {
    super(context, name, factory, version);
  }

  //DBが生成されていない場合に呼ばれる
  public void onCreate(SQLiteDatabase db) {
    //テーブルの生成などの初期処理を行う
  }

  //DBがバージョンアップされた場合に呼ばれる
  public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  }

}


//ヘルパーの生成
SQLiteOpenHelper helper = new MyOpenHelper(getApplicationContext(), "my.db", null, 1);

//DB接続(書き込み可能)
SQLiteDatabase  db = helper.getWritableDatabase();
//読み込み専用の場合は「getReadableDatabase」



INSERT

//登録する値
ContentValues values = new ContentValues();
values.put(列名, 値);

//登録されているデータ数を返す(失敗は-1)
long rows = db.insert(テーブル名, NotNull列のデフォルト値, values);
if (rows != -1) {
  //登録成功
} else {
  //登録失敗
}


SELECT

//SELECT句
String[] columns = {"ID", "NAME"};

//WHERE句とBindする値
String where = "NAME LIKE ?";
String[] params = {"%" + text + "%"};

//クエリー実行※
Cursor cursor = db.query("TABLE1", columns, where, params, null, null, null, null);

//カーソルを次へ移動
if (cursor.moveToNext()) {
  //値を取得
  id = cursor.getInt(cursor.getColumnIndex("ID"));
  str = cursor.getString(cursor.getColumnIndex("NAME"));
}
//カーソルを閉じる
cursor.close();

※queryの引数
1.テーブル名
2.カラム名(SELECT句)
3.検索条件(WHERE句)
4.検索条件パラメータ(WHERE句のBindする値)
5.グループ化(GROUP BY句)
6.グループの絞込み(HAVING句)
7.ソート順(ORDER BY句)
8.取得件数(LIMIT句)



UPDATE

//更新する値
ContentValues values = new ContentValues();
values.put(列名, 値);

//WHERE句とBindする値
String where = "ID=?";
String[] whereArgs = {"1"};

//更新した列数を返す
int rows = db.update(テーブル名, values, where, whereArgs);
if (rows != 0) {
  //更新成功
} else {
  //更新失敗
}


DELETE

//WHERE句とBindする値
String where = "ID=?";
String[] whereArgs = {"1"};

//削除した件数を返す
int rows = db.delete(テーブル名, where, whereArgs);
if (rows != 0) {
  //1件以上削除
}


トランザクションを利用


//トランザクションスタート
db.beginTransaction();

//成功をセット
db.setTransactionSuccessful();
※セットされなければロールバック

//トランザクション終了
db.endTransaction();



SQL文を使用

SELECT以外
db.execSQL("SQL文" [,置き換え文字の配列]);


SELECT
db.rawQuery("SQL文" ,置き換え文字の配列);
→Cursorを返す




SQLiteStatementを利用

※SELECTはできない

//Statementを取得
SQLiteStatement stt = db.compileStatement(SQL文);

//文字をBind(Indexは1から始まる)
stt.bindString(インデックス, 値);

//INSERTを実行
stt.executeInsert();

//UPDATE,DELETEを実行
stt.executeUpdateDelete()




フラグメン

画面をいくつかの要素に分けて(断片化)、Activityでそれを組み合わせる


2種類の実装方法がある

1.Layoutファイルを使う
2.コード内で動的に生成


Layoutファイルを使う方法

1. Fragmentのサブクラスを作成

2. ActivityのLayoutにFragmentを追加

3. FragmentのサブクラスでonCreateViewをオーバーライド
  →戻り値でレイアウトをinflateする

  例)
  return inflater.inflate(R.layout.fragment1, container, false);

4.FragmentのサブクラスでonStartをオーバーライド
  →処理を記述する

  ※findする場合は「getActivity().findViewById(…」
    (同じActivity上の他のFragmentの要素にもアクセス可能)




フラグメントの動的生成

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(追加先のビュー, フラグメントのインスタンス);
ft.commit();



フラグメントの置き換え

FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(追加先のビュー, フラグメントのインスタンス);

//バックスタックに追加
ft.addToBackStack(null);

ft.commit();

1 件のコメント: