|
<Number>: [00000852]
<Date>: 2015/01/11 00:50:41
<Title>:
<Name>: amanojaku@管理人
|
|
|
Java SE Development Kit 8
「Java SE(Java Platform, Standard Edition) Development Kit 8」
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
↑(サーバー側のアプリ開発はできないが)「Java SE Development Kit 8」でも"Android"用アプリの開発なら特に問題は無いのではないかと思われる。
Java EE Development Kit 7
「Java EE(Java Platform, Enterprise Edition) SDK(Software Development Kit) 7 with JDK(Java Development Kit)」
http://www.oracle.com/technetwork/java/javaee/downloads/java-ee-sdk-7-jdk-7u21-downloads-1956231.html
↑もし、「Java 7 (Version 1.7)」系でも良いのなら、こちらの「Java EE(Java Platform, Enterprise Edition)」もあるが、すでに Java 8(Version 1.8)系がインストールされている場合はウマくインストールできないかもしれない。
(現時点で) JRE の正式版の Version は Java 8(Version 1.8) となってるので、わざわざ古い Version を使う必要もないだろうけど…。
Oracle. Java Technology Products.
http://www.java.com/ja/download/manual.jsp
↑(現時点で) JRE 正式版の Version は Java 8(Version 1.8) となってる。
「ADT Plugin for Eclipse、Android SDK」のダウンロードとインストールなど
ADT Plugin for Eclipseのインストール
http://www.javadrive.jp/android/adt/
Android SDKのダウンロードとインストール
http://www.javadrive.jp/android/install/index1.html
ADT Pluginのインストール
http://www.javadrive.jp/android/adt/index1.html
SDK ロケーションの設定
http://www.javadrive.jp/android/adt/index2.html
Eclipse ADTでつくるAndroidエミュレータ開発環境構築メモ(Windows)
http://futurismo.biz/archives/2025
現在、(Google が?)「Android Studio」へ完全に移行させたいのか、公式サイトから「adt-bundle-windows〜.zip」がダウンロードできなくなった模様。
下記は当方がアップした「adt-bundle-windows-x86-20140702.zip」(「プレビューに問題が発生しました」と言うエラーが出るかもしれないが無視して良い)。
> 「adt-bundle-windows-x86-20140702.zip」(Windows 32bit版)
> https://drive.google.com/file/d/0BwisuiuM51wiS0w1RVZRVTl3Ykk/view?usp=sharing
「adt-bundle-windows〜.zip」を解凍する場合、ファイル名と同じフォルダーを作らない設定しないと、2重に同じフォルダーが出来てしまうので要注意。
ファイル名と同じフォルダーを作らない設定でルートに解凍しても「ファイル名が長すぎる」と言うエラーが出る場合があるようなのだが、"+Lhaca"アーカイバ(下記参照)ならウマく解凍できるらしい。
> +Lhaca
> http://www.vector.co.jp/soft/dl/win95/util/se130263.html
(あくまでも現時点においての話)「Tools:Android SDK Tools:Rev.23.0.5」を"Rev.24.0.1"に Update すると正常に Project を生成できなくなるようだ、また「Tools:Android SDK Platform-tools:Rev.20」も"Rev.21"に「Android OS 5」も「Android OS 5.0.1」に、「Android OS 4.4W」も"4.4W.2"に、「Extras:Android Support Library:Rev.20」も"Rev.2"に Update しない方が良い雰囲気。
「Android OS 4.4.2」をインストールすると自然に「Android OS 4.4W」が消えるようだが、特に問題は無いような感じ(「Android OS Version 4.4.2 Emulator」を使わないのだったら特に「Android OS 4.4.2」をインストールする必要もないだろう)。
断定はできないが、『「Tools:Android SDK Platform-tools」、「Tools:Android SDK Build-tools」、「Extras:Android Support Library」』の Revision の整数値は「API Level」を表わしているような雰囲気なので「Tools:Android SDK Build-tools」の"Rev.21.x"も Install しない方が良い雰囲気。
もし、Update してしまっいる場合は上記の Update 前のデータ(当方の Windows XP 32bit 環境のデータなので Windows 32bit 環境なら使えるだろうと思われる)"ADT-SDK_WindowsXP-32bit_007.lzh"(1.07GB)を次のアドレス「 https://drive.google.com/file/d/0BwisuiuM51wiU0VmZE1NbjJjM1k/view?usp=sharing 」から(「表示できるプレビューがありません」と言うエラーが出るかもしれないが無視して良い)ダウンロードし、"sdk"フォルダー内のフォルダーを全て削除(ファイルの使用中で削除できない場合は一旦 ログアウトし、またログインしてから削除)し、"sdk"フォルダー内に"ADT-SDK_WindowsXP-32bit_007.lzh"を入れて(ファイル名と同じフォルダー作らない設定で)解凍してやる。
その後、「SDK Manager」で「Deselect All」をクリックしチェックを全て OFF にしてから、「Extras:Google USB Driver」をインストールする。
それで正常に Project を生成できない場合は、<User>内の".android"フォルダーを削除し(<User>は"My Documents"ではない)、新しく空の"workspace"作成し(古いファイルをコピーしない空の状態で)スケルトンを作成し、"appcompat_v7"を選択し"Refresh"([F5]キー)してやる。
また「Android Virtual Device Manager」で作成した「仮想 Device」が「run configurations」:「Target」タブの「仮想 Device」リストに反映されていない場合は、「Package Explorer」ビューの"Project"を右クリックし(ショートカット・メニュー)「Run As」→「Android Application」を実行すれば「run configurations」:「Target」タブの「仮想 Device」リストに「仮想 Device」が反映されるようだ。
(複数の Eclipse がインストールされている場合は)必ず adt-bundle-windows〜.zip で展開された adt-bundle-windows〜 フォルダー内の Eclipse を使用する。
(現時点の adt-bundle-windows〜.zip では)「eclipse」フォルダーに「eclipse.ini」ファイルが有るので、(順番に依存するので)先頭に「-vm」オプションで「JDK(Java Development Kit)」の「Java\jdk〜\bin\javaw.exe」のフル・パスを設定してやる(下記参照)。
-vm
C:\Program Files\Java\jdk〜\bin\javaw.exe
「eclipse.ini」の基本形データをバックアップしておくのも悪くないかもしれない(当方の「eclipse.ini」の基本形データを参考までに下記にアップしておく)。
なお、「eclipse.ini」ファイルは"メモ帳"で開いてはならない、"Unix"系の改行コードと"Windows"系の改行コードとの違いにより、一見 改行してないように表示されてしまう場合があるようだ、次のような Editor なら正常に表示されるようだ。
> MKEditor for Windows
> http://www.vector.co.jp/magazine/softnews/090124/n0901241.html
>
> EmEditor Free
> https://jp.emeditor.com/text-editor-features/history/emeditor-free/
eclipse.exeの-cleanオプションをショートカットに設定する
http://www.hitachi.co.jp/Prod/comp/soft1/cosminexus/useful/tips/081205_eclipseexe-clean-shortcut.html
「res\layout\activity_main.xml」を開き、下の「Graphical Layout」タブを選択すると、レイアウト・ビルダーが表示される(エミュレータではない)が、ここで「API Level:Android OS Version」を指定でき、使える GUI 部品が変わる(エミュレータのバージョンを指定してる訳ではない)。
ちなみに「Android OS Version 1.x」は指定できない、それは「Version 1.x」は開発できない事を意味しているので、「Android OS Version 1.x」はインストールする必要はない。
「Android OS Version 4.4W」は「Android Wear」と言う「スマートウォッチ(腕時計型ウェアラブルデバイス)」用に開発された Android OS らしいので、「Version 4.4W.x」もインストールする必要は無いような気もするが、(「Android SDK」の Version や環境によって違う場合もあるだろうが)「Android OS Version 5.0」をインストールすると、デフォルトでインストール済の「Version 4.4W.x」の「SDK Platform」が「Not Installed」になって JavaFX 用のプロジェクトに"×"が表示されてしまう場合があるようだ。
その場合、「Version 4.4W.x」の「SDK Platform」を再インストールすれば良いようだが、「Android OS Version 5.0」をインストール時に何回も警告が出る場合があるので、その時は一旦「Android OS Version 5.0」のインストールのチェックを全て OFF にしてから、「Version 4.4W.x」の「SDK Platform」を再インストールし、その後 (未インストールの)「Android OS Version 5.0」をインストールすれば良いようだ。
(Win) x86版Android エミュレータを使えるようにするまで
http://52c.tumblr.com/post/34218675318/win-x86-android
↑下記の措置は必須ではないようで、AVD Managerのリストに"x86"("CPU/ABI"?)のイメージが表示されない場合の措置と言うことらしい。
> android-sdk\add-onsディレクトリに「addon-intel_atom_x86_system_image-intel_corporation-16」というフォルダを作成
(現時点の adt-bundle-windows〜.zip では)「sdk\add-ons」フォルダーに「addon-intel_atom_x86_system_image-intel_corporation-16」というフォルダを作成
> 先ほどのフォルダ内にimagesフォルダとmanifest.iniというテキストファイルを作成
manifest.ini は作成する必要もない雰囲気ではあるが、一応 そのサイトの通りテキストをコピペしておけば良いだろう。
> Android-SDK\system-images\android-16\ 以下を images\ 以下へコピー
(現時点の adt-bundle-windows〜.zip では)「android-16」フォルダーは存在していないので、「sdk\system-images」フォルダー以下を「addon-intel_atom_x86_system_image-intel_corporation-16\images」フォルダー以下へコピー。
> x86\source.properties を manifest.iniと同じ位置に移動します
「x86\source.properties」の所在は不明なのでコピーできない。
Android SDK の高速エミュレータ、使ってますか?
http://www.webtech.co.jp/blog/developer-news/5966/
↑「Android SDK Manager」で「Intel x86 Emulator Accelarator」がインストールできない場合は、他のチェックをハズし、「Intel x86 Emulator Accelarator」単体でインストールしてみる。
仮想化支援機構(Intel(R) Virtualization Technology)を CPU がサポートし、仮想化支援機構を BIOS がサポートし、BIOS で仮想化支援機構をイネーブルに設定してやらないと「Intel x86 Emulator Accelarator」は実行できない。
(現時点の adt-bundle-windows〜.zip では)場所は「sdk\extras\intel\Hardware_Accelerated_Execution_Manager\intelhaxm-android.exe」となってるようだ。
「Android SDK」がアップデートされ、以前の"workspace"との不整合が生じ、新たなプロジェクトを作成するとプロジェクトに×が付く場合があるようだ。
(「Android SDK」のアップデートの場合に限らず) Eclipse の調子が悪くなったら、とりあえず"workspace"を変更し、(古い"workspace"内のデータをコピペしてはならない)スケルトンのプロジェクトが正常に作成できるか試してみる。
それでダメなら「ADT Plugin for Eclipse、Android SDK」の上書き、それでダメなら「ADT Plugin for Eclipse、Android SDK」を削除してから再インストールと言う感じになる(これらの場合も、以前のデータが存在する"workspace"を使用してはならない)。
ちなみに正常に"workspace"をインポートできないような感じ(以前のプログラムを移行したい場合はスケルトンのプロジェクトを作成し、そこにソースをコピペするしかないのか)。
00000852.0.txt:(Size=471Byte) Name = eclipse.ini 2014.11.23-23.32.txt
|
|
|
<Number>: [00000855]
<Date>: 2015/01/11 01:29:40
<Title>:
<Name>: amanojaku@管理人
|
|
|
|
|
<Number>: [00000856]
<Date>: 2014/12/28 14:42:15
<Title>:
<Name>: amanojaku@管理人
|
|
|
アプリの多重起動
Android アプリでは[Home]キーを押した場合"Stop"待機状態になるようなのだが、(Android 2.2 エミュレータでは そのような問題は起こらなかったのだが)問題は(Android 4.3 の実機で)[Home]キーを押した後 そのアプリを再実行すると前のタスクとは別の さらに新しいタスクが加えられて行くようだ(下記サイト参照)。
図で理解するActivityのスタック
http://techblog.qoncept.jp/?p=102
launchMode="singleInstance"に設定することで起動するインスタンスを1つに限定できる。
『AndroidManifest.xml』の下記の部分を変更する、「<application」ではなく「<activity」である事に注意。
> <activity
> android:name=".MainActivity"
> android:label="@string/app_name" >
下記が変更後、最後の行の末尾の">"(グレーターザン:大なり)記号が付け替えられてる事に注意。
> <activity
> android:name=".MainActivity"
> android:label="@string/app_name"
> android:launchMode="singleInstance" >
|
|
|
<Number>: [0000085D]
<Date>: 2015/01/08 08:01:25
<Title>:
<Name>: amanojaku@管理人
|
|
|
Button イベント (改)
とりあえず、アプリケーション名は"Hello003_JFX"、プロジェクト名は"Hello003_Prj"パッケージ名は"com.example.hello003_pkg"としている、その他はデフォルトでスケルトンを作成。
『src/com.example.hello003_pkg/MainActivity.java』
package com.example.hello003_pkg;
import android.support.v7.app.ActionBarActivity;
import android.content.res.Resources;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends ActionBarActivity {
String vsDisplayHello;
String vsMessage = "";
EditText cetMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vsDisplayHello = getString(R.string.display_hello);
/* ボタンを取り出す */
Button cbHello = (Button)findViewById(R.id.cb_hello);
/* ボタンにリスナーを登録する */
cbHello.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
vsMessage = vsMessage+vsDisplayHello+"\n";
cetMessage.setText(vsMessage);
}
});
/* エディット・テキストを取り出す */
cetMessage = (EditText)findViewById(R.id.cet_message);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
『res\layout\activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.hello003_pkg.MainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<Button
android:id="@+id/cb_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cb_hello" />
<EditText
android:id="@+id/cet_message"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="top"
android:inputType="textMultiLine" >
</EditText>
</LinearLayout>
『res\values\strings.xml』
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Hello003_JFX</string>
<string name="action_settings">Settings</string>
<string name="display_hello">Hello world!</string>
<string name="cb_hello">Hello</string>
</resources>
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hello003_pkg"
android:versionName="1.0"
android:versionCode="1" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
|
|
|
<Number>: [00000871]
<Date>: 2015/01/10 00:13:49
<Title>:
<Name>: amanojaku@管理人
|
|
|
SurfaceView(2) 改(2)
サンプル動画 http://www.youtube.com/v/-khejT0BwXw&autoplay=1
《参考》
SurfaceView(2) 改(3)
http://artemis.rosx.net/sjis/smt.cgi?r+izanami/&bid+0000083C&tsn+000008F9&bts+2014/10/28%2002%3A03%3A17&
"SurfaceView"の"Destroy"
Android アプリの待機状態には「Pause、Stop」が有り、[Home]キーを押した場合"Stop"状態になるようなのだが、問題は その時(恐らく「onStop(…)」メソッドの実行後)に"SurfaceView"が"Destroy"してしまう事だ。
Android アプリは"Stop"状態から起動する場合、「onCreate(…)」メソッドは呼ばれずに、その代わり「onRestart(…)」メソッドが呼ばれる。
つまり、「onRestart(…)」メソッドを"Override"し そこで"SurfaceView"を"Create"してやらなければならないのだが、「onRestart(…)」メソッドを"Override"できない。
"AndroidManifest.xml"に 何か設定してやるとか書いてあるが、サッパリできん…(^_^;)
後、"SurfaceView"が"Destroy"される前、(恐らく)「onStop(…)」メソッドで"Thread"を破棄し"Canvas"への描画を停止させる必要があるが、当然「onStop(…)」メソッドも"Override"できない。
> "AndroidManifest.xml"に 何か設定してやるとか書いてあるが、サッパリできん
現行バージョンの開発環境ならデフォルトで OK のようだ。
単に「onCreate(…)」メソッドと同じ引数を持つと思い込んで、勘違いしていた。
「onCreate(…)」メソッド以外は引数は無し。
> つまり、「onRestart(…)」メソッドを"Override"し そこで"SurfaceView"を"Create"してやらなければならない
良く考えたら"SurfaceView"を"Create"するのは「onStart( )」メソッドにするべき。
> [Home]キーを押した場合"Stop"状態になるようなのだが、問題は その時(恐らく「onStop(…)」メソッドの実行後)に"SurfaceView"が"Destroy"してしまう
「onStop(…)」メソッドの実行後では無く、「onStop(…)」メソッドの実行・前後のようらしい。
今回、Android 用 JavaFX プログラミングで参考にしたサイト。
アクティビティ - ソフトウェア技術ドキュメントを勝手に翻訳
http://www.techdoctranslator.com/android/guide/activities
Activityのライフサイクル - アンドロイド道場
https://sites.google.com/site/androidappdojo/home/devmemo/memo04
Androidアクティビティのライフサイクル解釈 - clock-up-blog
http://blog.clock-up.jp/entry/2014/03/18/112955
Object (Java Platform SE 6) wait
https://docs.oracle.com/javase/jp/6/api/java/lang/Object.html#wait%28%29
Object (Java Platform SE 6) notify
https://docs.oracle.com/javase/jp/6/api/java/lang/Object.html#notify%28%29
synchronized で何を Monitor に指定すれば良いのか?、恐らく この場合は操作される側の Runnable インターフェイスを継承しているインスタンス(この場合は RunningDriver のインスタンス)を Monitor にするのが良いような雰囲気。
とりあえずアプリケーション名は"A009_JFX"、プロジェクト名は"A009_Prj"、パッケージ名は"com.example.a009_pkg"としている、その他はデフォルトでスケルトンを作成。
ボタン"Accept"(アクセプト)は"Through"(スルー)状態の Runner を再スタートさせる。
ボタン"Through"(スルー)は Runner を"Through"(スルー)状態(runningEngine は動いているが Runner はスルーとなる)にする。
ボタン"notify"は"Wait"状態の Runner を再スタートさせる。
ボタン"Wait"は Runner を"Wait"状態にする。
ボタン"Create"(クリエイト)は"runningEngine"(Thread)を生成しスタートさせる。
ボタン"Destroy"(デストロイ)は"runningEngine"(Thread)を破棄する。
『src/com.example.a009_pkg/MainActivity.java』
package com.example.a009_pkg;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView.BufferType;
import android.util.Log;
public class MainActivity extends ActionBarActivity implements
SurfaceHolder.Callback {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
// ↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
// 全部 大文字で記述するの事が推奨されているようだ。
// 「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される事になる。
Thread running = null;
boolean runningSW = true; // false; //
static int appLaunchMode;
public static final int LAUNCH_CREATE = 1;
public static final int LAUNCH_RESTART = 2;
MainActivity app;
int screenWidth, screenHeight;
boolean surfaceChangedSW = false; // true; //
String vsMessage = "";
EditText cetMessage;
RunningDriver runningDriver;
// Canvas canvas;
int[] cPalette = {
Color.RED,Color.YELLOW,Color.MAGENTA,Color.GREEN,Color.CYAN,Color.BLUE };
// ↑ カラーの実態は Color オブジェクトではなく int。
public abstract class RunnerPrimitive {
boolean ThroughSW = false; // true; //
public void run( ){ }
}
public abstract class RunnerFigure extends RunnerPrimitive {
RunningDriver runningDriver;
Color color;
Paint paint = new Paint( );
int cx,cy,dx,dy;
}
public class RunnerCircle extends RunnerFigure {
int radius = 30;
public RunnerCircle(RunningDriver RD) {
runningDriver = RD;
if(DEBUG)Log.i(tag,
"RunnerCircle( )"+"\n"+
"screenWidth="+screenWidth+"\n"+
"screenHeighth="+screenHeight+"\n"+
"");
cx = (int)Math.round(Math.random( )*screenWidth);
cy = (int)Math.round(Math.random( )*screenHeight);
if(DEBUG)Log.i(tag,
"cx="+cx+"\n"+
"cy="+cy+"\n"+
"");
dx = (int)Math.signum(Math.round(Math.random( ))-.5)*10;
dy = (int)Math.signum(Math.round(Math.random( ))-.5)*10;
if(DEBUG)Log.i(tag,
"dx="+dx+"\n"+
"dy="+dy+"\n"+
"");
int c = cPalette[(int)Math.round(Math.random( )*(cPalette.length-1))];
paint.setStyle(Style.FILL);
paint.setColor(c);
if(DEBUG)Log.i(tag,
"paint.set"+"\n"+
"");
}
@Override
public void run( ) {
synchronized(runningDriver) {
runningDriver.canvas.drawCircle(
cx, cy, radius,paint);
if( ! ThroughSW ) {
if( (cx+dx)<0 | screenWidth<(cx+dx) ){
dx = -dx;
}
cx += dx;
if( (cy+dy)<0 | screenHeight<(cy+dy) ){
dy = -dy;
}
cy += dy;
}
}
}
}
public class RunningDriver implements
Runnable {
RunnerFigure[] runnerMembers = new RunnerFigure[5];
// ↑ 手抜きで配列にしているが、本来ならノードで連結させるのが筋。
public Canvas canvas;
public SurfaceHolder surfaceHolder;
// ↑ 本来なら これら「canvas、surfaceHolder」は ここで記述するべきではなく、
// 別クラスを継承しで そこで記述してやるのが筋。
int runnerNumber;
public Thread runningEngine = null;
public boolean runningEngineSW = false; // true; //
public boolean waitSW = false; // true; //
long interval = 50;
public RunningDriver( ){ }
public void launch(int LaunchMode){
switch (LaunchMode){
case LAUNCH_CREATE:
initialize( );
runningEngineCreate( );
break;
case LAUNCH_RESTART:
runningEngineCreate( );
break;
default:
}
}
public void initialize( ){
// ↑ 本来なら この「initialize( )」メソッドは
// この"RunningDriver"クラスでは抽象メソッドとし、
// 別クラスで それらのメソッドをオーバーライドしてやるのが筋。
for( int i = 0; i<runnerMembers.length; i++){
runnerMembers[i] = new RunnerCircle(this);
}
// runningEngineCreate( );
}
public void runnerAcceptAll( ){
for( int i = 0; i<runnerMembers.length; i++){
if( runnerMembers[i]!=null ){
runnerMembers[i].ThroughSW = false; // true; //
}
}
}
public void runnerThroughAll( ){
for( int i = 0; i<runnerMembers.length; i++){
if( runnerMembers[i]!=null ){
runnerMembers[i].ThroughSW = true; // false; //
}
}
}
public void runningEngineCreate( ) {
runnerAcceptAll( );
runningEngineSW = true; // false; //
waitSW = false; // true; //
// runningEngine = null;
runningEngine = new Thread(this);
runningEngine.start( );
}
public void runningEngineDestroy( ){
try{
runningEngine.interrupt( );
} catch(NullPointerException e) {
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:runningEngineDestroy( ):NullPointerException;");
}
}
public synchronized void runningHeader( ){
// ↑ Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
Paint bgPaint = new Paint();
bgPaint.setStyle(Style.FILL);
bgPaint.setColor(Color.WHITE);
canvas = surfaceHolder.lockCanvas( );
canvas.drawRect(
0, 0, screenWidth, screenHeight,
bgPaint);
}
public synchronized void runningFooter( ){
// ↑ Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
surfaceHolder.unlockCanvasAndPost(canvas);
}
public void run( ){
if(DEBUG)Log.i(tag, "RunningDriver.run( );");
while(
runningEngine!=null &
runningEngineSW
){
synchronized(this) {
// ↑ この this は runningEngine では無く RunningDriver のインスタンス。
try{
// 本来なら下記「runningHeader( )、runningFooter( )」メソッドは
// この"RunningDriver"クラスでは抽象メソッドとし、
// 別クラスで それらのメソッドをオーバーライドしてやるのが筋。
runningHeader( );
for( runnerNumber = 0; runnerNumber<runnerMembers.length; runnerNumber++){
if( runnerMembers[runnerNumber]!=null ){
runnerMembers[runnerNumber].run( );
}
}
runningFooter( );
} catch(NullPointerException e) {
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:run( ):NullPointerException;");
runningEngineSW = false; // true; //
}
while(waitSW){
try{
this.wait( );
// ↑ この this は runningEngine では無く RunningDriver のインスタンス。
}catch(InterruptedException e){
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:run( ):InterruptedException;");
runningEngineSW = false; // true; //
}
}
if( runningEngineSW ){
try{
Thread.sleep(interval);
// ↑ 「sleep(interval)」は指定された時間以上に待たされる場合があるようなので、
// 1回のループは「プログラムの処理時間+sleep(interval+α)」 となるから、
// 正確(完璧に正確無比と言う意味ではない)なタイマーを作りたい場合は
//「long time = System.currentTimeMillis( )」を使って一工夫が必要となる。
} catch(InterruptedException e) {
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:run( ):InterruptedException;");
runningEngineSW = false; // true; //
}
}
}
}
runningEngine = null;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(DEBUG)Log.i(tag, "onCreate( );");
app = this;
appLaunchMode = LAUNCH_CREATE;
cetMessage = (EditText)findViewById(R.id.cet_message);
vsMessage = vsMessage+"onCreate\n";
cetMessage.setText(vsMessage, BufferType.NORMAL);
runningDriver = new RunningDriver( );
// 「MainActivity」クラスの この「onCreate( )」コンストラクターでは
// まだ"SurfaceView"の生成が完了してない場合が有るようで、
// その時点で"Thread"が実行された場合
// 「surfaceHolder.lockCanvas( )」による"Canvas"の生成が"null"になってしまうので、
// 「RunningDriver( )」コンストラクターには
// 「runningEngineCreate( )」("Thread"の生成・実行)は内包しない。
// 又、「RunnerCircle( )」 コンストラクター実行時には
// 「screenWidth、screenHeight」が設定されていなければならないので
// 「RunningDriver( )」コンストラクターには内包せず、別途「initialize( )」に内包する。
// それら「initialize( )、runningEngineCreate( )」は「launch( )」に内包し「surfaceChanged( )」で実行する。
// ただし「launch( )」に内包された それら(「initialize( )、runningEngineCreate( )」)は"appLaunchMode"で実行の可否が決定される。
if(DEBUG)Log.i(tag, "runningDriver = new RunningDriver( );");
vsMessage = vsMessage+"runningDriver = new RunningDriver( )\n";
cetMessage.setText(vsMessage, BufferType.NORMAL);
/* ボタンを取り出す */
Button cbAcceptAll = (Button)findViewById(R.id.cb_accept_all);
/* ボタンにリスナーを登録する */
cbAcceptAll.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningDriver.runnerAcceptAll( );
}
});
/* ボタンを取り出す */
Button cbThroughAll = (Button)findViewById(R.id.cb_through_all);
/* ボタンにリスナーを登録する */
cbThroughAll.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningDriver.runnerThroughAll( );
}
});
/* ボタンを取り出す */
Button cbWait = (Button)findViewById(R.id.cb_wait);
/* ボタンにリスナーを登録する */
cbWait.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningDriver.waitSW = true; // false; //
}
});
/* ボタンを取り出す */
Button cbNotify = (Button)findViewById(R.id.cb_notify);
/* ボタンにリスナーを登録する */
cbNotify.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
try{
synchronized(runningDriver){
runningDriver.waitSW = false; // true; //
runningDriver.notify( );
}
}catch(IllegalMonitorStateException e){ }
}
});
/* ボタンを取り出す */
Button cbCreate = (Button)findViewById(R.id.cb_create);
/* ボタンにリスナーを登録する */
cbCreate.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningDriver.runningEngineCreate( );
}
});
/* ボタンを取り出す */
Button cbDestroy = (Button)findViewById(R.id.cb_destroy);
/* ボタンにリスナーを登録する */
cbDestroy.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningDriver.runningEngineDestroy( );
}
});
}
@Override
protected void onRestart( ) {
super.onRestart( );
if(DEBUG)Log.i(tag, "onRestart( );");
appLaunchMode = LAUNCH_RESTART;
}
@Override
protected void onStart( ) {
super.onStart( );
if(DEBUG)Log.i(tag, "onStart( );");
surfaceChangedSW = false; // true; //
SurfaceView SV = (SurfaceView)findViewById(R.id.SV);
SurfaceHolder SH = SV.getHolder();
SH.addCallback(app);
// SV.setFocusable(true);
// SV.requestFocus( );
runningDriver.surfaceHolder = SH;
}
@Override
protected void onResume( ) {
super.onResume( );
if(DEBUG)Log.i(tag, "onResume( );");
}
@Override
protected void onPause( ) {
super.onPause( );
if(DEBUG)Log.i(tag, "onPause( );");
}
@Override
protected void onStop( ) {
super.onStop( );
if(DEBUG)Log.i(tag, "onStop( );");
runningDriver.runningEngineDestroy( );
runningDriver.surfaceHolder.removeCallback(app);
}
@Override
protected void onDestroy( ) {
super.onDestroy( );
if(DEBUG)Log.i(tag, "onDestroy( );");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void surfaceCreated(SurfaceHolder holder) { }
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
screenWidth = width;
screenHeight = height;
if(DEBUG)Log.i(tag,
"surfaceChanged( );"+"\n"+
"screenWidth="+screenWidth+"\n"+
"screenHeighth="+screenHeight+"\n"+
"");
vsMessage = vsMessage+
"screenWidth="+screenWidth+"\n"+
"screenHeighth="+screenHeight+"\n"+
"";
cetMessage.setText(vsMessage, BufferType.NORMAL);
vsMessage = vsMessage+"surfaceChanged( )\n";
cetMessage.setText(vsMessage, BufferType.NORMAL);
if( ! surfaceChangedSW ){
surfaceChangedSW = true; // false; //
// "surfaceChangedSW"がクリアーされない限りは、「surfaceChanged( )」 が2回以上呼ばれても、ここは1回しか実行されない。
runningDriver.launch(appLaunchMode);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) { }
}
『res\layout\activity_main.xml』
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<SurfaceView
android:id="@+id/SV"
android:layout_width="match_parent"
android:layout_height="200dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/cb_accept_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/AcceptAll" />
<Button
android:id="@+id/cb_through_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ThroughAll" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/cb_notify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Notify" />
<Button
android:id="@+id/cb_wait"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Wait" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/cb_create"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Create" />
<Button
android:id="@+id/cb_destroy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Destroy" />
</LinearLayout>
<EditText
android:id="@+id/cet_message"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</LinearLayout>
『res\values\strings.xml』
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">A009_JFX</string>
<string name="action_settings">Settings</string>
<string name="AcceptAll">Accept</string>
<string name="ThroughAll">Through</string>
<string name="Notify">Notify</string>
<string name="Wait">Wait</string>
<string name="Create">Create</string>
<string name="Destroy">Destroy</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.a009_pkg"
android:versionName="1.0"
android:versionCode="7" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
|
|
|
<Number>: [0000087A]
<Date>: 2014/11/22 00:13:40
<Title>:
<Name>: amanojaku@管理人
|
|
|
|
|
<Number>: [0000087B]
<Date>: 2014/12/27 12:19:32
<Title>:
<Name>: amanojaku@管理人
|
|
|
Widget での Click Event
とりあえずアプリケーション名は"W0063_JFX"、プロジェクト名は"W0063_Prj"、パッケージ名は"com.android.appwidget.w0063_pkg"としている、「Create Activity」は OFF にして、その他はデフォルトでスケルトンを作成。
"src"フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[Package]で"com.android.appwidget.w0063_pkg"(Package)を作成。
「src/com.android.appwidget.w0063_pkg」Package フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[File]で[File Name]:"MainWidget.java"(Java File)を作成(この場合、ファイル拡張子まで入力)。
「res/layout」フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[Android XML File]で[Resources Type]:[Layout]とし[File]:"widget_main"(XML File)を作成。
「res」フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[Folder]で[Folder Name]:"xml"(Folder)を作成。
「res/xml」フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[File]で[File Name]:"widget_info.xml"(XML File)を作成(この場合、ファイル拡張子まで入力)。
『src/com.android.appwidget.w0063_pkg/MainWidget.java』
package com.android.appwidget.w0063_pkg;
import java.util.Date;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.widget.RemoteViews;
/** クリックを使用するサンプル。 */
public class MainWidget extends AppWidgetProvider {
private static final String ACTION_MY_CLICK = "com.android.appwidget.w0063_pkg.IntentFilter.ACTION_MY_CLICK";
static long ilCounter;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_main);
remoteViews.setTextViewText(R.id.ctvDate, "onUpdate");
remoteViews.setTextViewText(R.id.ctvCounter, "Clic:"+ilCounter);
// ウィジェットの更新
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
Intent serviceIntent = new Intent(context, MyService.class);
context.startService(serviceIntent);
}
public static class MyService extends Service {
@SuppressWarnings("deprecation")
@Override
public void onStart(Intent intent, int startId) {
ComponentName thisWidget = new ComponentName(this, MainWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.widget_main);
if(ACTION_MY_CLICK.equals(intent.getAction( ))) {
remoteViews.setTextViewText(R.id.ctvDate, new Date().toLocaleString( ));
ilCounter++;
remoteViews.setTextViewText(R.id.ctvCounter, "Clic:"+ilCounter);
}
Intent clickIntent = new Intent();
clickIntent.setAction(ACTION_MY_CLICK);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, clickIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.ctvDate, pendingIntent);
remoteViews.setOnClickPendingIntent(R.id.button1, pendingIntent);
manager.updateAppWidget(thisWidget, remoteViews);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
}
『res/layout/widget_main.xml』
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/linearLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/ctvDate"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#333333"
android:gravity="center"
android:text="Date"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="#ffffff" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/ctvCounter"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#333333"
android:text="ClicCounter"
android:textAppearance="?android:attr/textAppearanceMedium" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Please click!" />
</LinearLayout>
</LinearLayout>
『res/xml/widget_info.xml』
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="300dip"
android:minHeight="70dip"
android:updatePeriodMillis="0"
android:initialLayout="@layout/widget_main" />
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.appwidget.w0063_pkg"
android:versionName="1.0"
android:versionCode="10" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="12" />
<!-- ↑ targetSdkVersion が 14以上だと Widget のサイズの計算法が変わるそうで、 -->
<!-- 古い Version と互換性を持たせたい場合は targetSdkVersion を 13以下にすれば良いらしい。 -->
<!-- (「API Level 13」以下とするなら)当方は「API Level 12」(Android OS 3.1)までしか -->
<!-- インストールしてないので targetSdkVersion は 12 とする(警告が出るが放置で良い)。 -->
<application
android:allowBackup="true"
android:label="@string/app_name"
android:icon="@drawable/ic_launcher" >
<receiver
android:label="@string/app_name"
android:name=".MainWidget" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
<service android:name=".MainWidget$MyService">
<intent-filter>
<action android:name="com.android.appwidget.w0063_pkg.IntentFilter.ACTION_MY_CLICK" />
</intent-filter>
</service>
</application>
</manifest>
|
|
|
<Number>: [0000087E]
<Date>: 2014/12/27 12:21:26
<Title>:
<Name>: amanojaku@管理人
|
|
|
Widget から Activity を起動
とりあえずアプリケーション名は"W0121_JFX"、プロジェクト名は"W0121_Prj"、パッケージ名は"com.moonlight_aska.android.w0121_pkg"、「Create Activity」は ON 、"Activity"名は"MainActivity"、"Layout"名は"activity_main"としている、その他はデフォルトでスケルトンを作成。
「src/com.android.appwidget.w0121_pkg」Package フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[File]で[File Name]:"MainWidget.java"(Java File)を作成(この場合、ファイル拡張子まで入力)。
「res/layout」フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[Android XML File]で[Resources Type]:[Layout]とし[File]:"widget_main"(XML File)を作成。
「res」フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[Folder]で[Folder Name]:"xml"(Folder)を作成。
「res/xml」フォルダーをマウスの右・クリックでショートカット・メニューから[New]→[File]で[File Name]:"widget_info.xml"(XML File)を作成(この場合、ファイル拡張子まで入力)。
なお、Activity のボタンはダミー。
『src/com.moonlight_aska.android.w0121_pkg/MainActivity.java』
package com.moonlight_aska.android.w0121_pkg;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
『src/com.moonlight_aska.android.w0121_pkg/MainWidget.java』
package com.moonlight_aska.android.w0121_pkg;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
public class MainWidget extends AppWidgetProvider {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
// ↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
// 全部 大文字で記述するの事が推奨されているようだ。
// 「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される。
@Override
public void onEnabled(Context context) {
if(DEBUG)Log.i(tag, "W0121/MainWidget.onEnabled( );");
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO Auto-generated method stub
super.onUpdate(context, appWidgetManager, appWidgetIds);
if(DEBUG)Log.i(tag, "W0121/MainWidget.onUpdate( );");
// アクティビティの指定
Intent intent = new Intent(context, MainActivity.class);
// PendingIntentの取得
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_main);
// インテントによるアクティビティ起動
remoteViews.setOnClickPendingIntent(R.id.btnGoActivity, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
}
『res/layout/activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.moonlight_aska.android.w0121_pkg.MainActivity" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!" />
</LinearLayout>
『res/layout/widget_main.xml』
<?xml version="1.0" encoding="utf-8"?>
<Button
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/btnGoActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Go Activity" />
『res/xml/widget_info.xml』
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:updatePeriodMillis="0"
android:minHeight="48dip"
android:minWidth="100dip"
android:initialLayout="@layout/widget_main" />
『AndroidManifest.xml』
※この場合 <activity>タグに"launchMode"は設定できないようだ、この場合 「launchMode="singleInstance"」を設定しなくても Activity のインスタンスは1つだけに限定されるようだ。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.moonlight_aska.android.w0121_pkg"
android:versionName="1.0"
android:versionCode="17" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="12" />
<!-- ↑ targetSdkVersion が 14以上だと Widget のサイズの計算法が変わるそうで、 -->
<!-- 古い Version と互換性を持たせたい場合は targetSdkVersion を 13以下にすれば良いらしい。 -->
<!-- (「API Level 13」以下とするなら)当方は「API Level 12」(Android OS 3.1)までしか -->
<!-- インストールしてないので targetSdkVersion は 12 とする(警告が出るが放置で良い)。 -->
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<receiver
android:name=".MainWidget"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/widget_info" />
</receiver>
<!-- アクティビティの登録 -->
<activity
android:name=".MainActivity" >
</activity>
</application>
</manifest>
|
|
|
<Number>: [000008AA]
<Date>: 2014/12/27 14:55:44
<Title>:
<Name>: amanojaku@管理人
|
|
|
Alarm (1)
今回、Android 用 JavaFX プログラミングで参考にしたサイト。
http://android.keicode.com/basics/services-schedule-with-alarmmanager.php
とりあえずアプリケーション名は"Alarm0017_JFX"、プロジェクト名は"Alarm0017_Prj"、パッケージ名は"com.keicode.android.alarm0017_pkg"、"Activity"名は"AlarmActivity"、"Layout"名は"activity_main"としている、その他はデフォルトでスケルトンを作成。
「res\menu」フォルダー内のファイル名が"main.xml"になっていなかったら、そのファイルをマウスの右・クリックでショートカット・メニューから[Refactor]→[Rename]でファイル名を"main.xml"に変更。
なお、基本的に(Alarm スレッドのような)メインのスレッドとは別のスレッドから「GUI:Graphical User Interface」(=Java で言う所の UI Control:User Interface Control)を操作できないようだ。
Handler を使えば何とかなるらしいが、ここでは Handler は使わずに、Log 出力とする。
『src/com.keicode.android.alarm0017_pkg/AlarmActivity.java』
package com.keicode.android.alarm0017_pkg;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class AlarmActivity extends ActionBarActivity {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
//↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
//全部 大文字で記述するの事が推奨されているようだ。
//「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される事になる。
Button cbSchedule;
Button cbCancel;
long interval = 3000;
public static class MyService extends IntentService {
static final String serviceName = MyService.class.getSimpleName( );
// getName( ) // パッケージ名を含むクラス名
// getSimpleName( ) // クラス名のみ
public MyService( ) {
super(serviceName);
if(DEBUG)Log.i(tag, serviceName);
}
@Override
protected void onHandleIntent(Intent intent) {
if(DEBUG)Log.i(tag, "onHandleIntent( );");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(DEBUG)Log.i(tag, "onCreate( );");
setContentView(R.layout.activity_main);
cbSchedule = (Button)findViewById(R.id.cb_schedule);
cbSchedule.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
scheduleService( );
}
});
cbCancel = (Button)findViewById(R.id.cb_cancel);
cbCancel.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
cancelService( );
}
});
}
@Override
protected void onPause( ) {
super.onPause( );
}
@Override
protected void onStop( ) {
super.onStop( );
cancelService( );
// ↑ Activity が Stop したら「Alarm Service」を停止している。
}
@Override
protected void onDestroy( ) {
super.onDestroy( );
}
protected void scheduleService( ){
if(DEBUG)Log.i(tag, "scheduleService( );");
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.RTC,
System.currentTimeMillis( ),
interval, pendingIntent);
}
protected void cancelService( ){
if(DEBUG)Log.i(tag, "cancelService( );");
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)
context.getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater( ).inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId( );
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
『res\layout\activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.keicode.android.alarm0017_pkg.AlarmActivity" >
<TextView
android:id="@+id/ctv_counter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AlarmManager" />
<Button
android:id="@+id/cb_schedule"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="schedule" />
<Button
android:id="@+id/cb_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="cancel" />
</LinearLayout >
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.keicode.android.alarm0017_pkg"
android:versionName="1.0"
android:versionCode="9" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".AlarmActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".AlarmActivity$MyService"></service>
</application>
</manifest>
|
|
|
<Number>: [000008AD]
<Date>: 2014/12/27 14:59:59
<Title>:
<Name>: amanojaku@管理人
|
|
|
Alarm (1) 改
とりあえずアプリケーション名は"Alarm0018_JFX"、プロジェクト名は"Alarm0018_Prj"、パッケージ名は"com.keicode.android.alarm0018_pkg"、"Activity"名は"AlarmActivity"、"Layout"名は"activity_main"としている、その他はデフォルトでスケルトンを作成。
「res\menu」フォルダー内のファイル名が"main.xml"になっていなかったら、そのファイルをマウスの右・クリックでショートカット・メニューから[Refactor]→[Rename]でファイル名を"main.xml"に変更。
基本的に(Alarm スレッドのような)メインのスレッドとは別のスレッドから「GUI:Graphical User Interface」(=Java で言う所の UI Control:User Interface Control)を操作できないようなので、Handler を使って「GUI:Graphical User Interface」(=Java で言う所の UI Control:User Interface Control)を操作する。
『src/com.keicode.android.alarm0018_pkg/AlarmActivity.java』
package com.keicode.android.alarm0018_pkg;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class AlarmActivity extends ActionBarActivity {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
//↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
//全部 大文字で記述するの事が推奨されているようだ。
//「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される事になる。
TextView ctvCounter;
Button cbSchedule;
Button cbCancel;
long interval = 1000;
static Handler hdrCFlash;
static long ilCounter;
public static class MyService extends IntentService {
static final String serviceName = MyService.class.getSimpleName( );
// getName(); // パッケージ名を含むクラス名
// getSimpleName() // クラス名のみ
public MyService( ) {
super(serviceName);
if(DEBUG)Log.i(tag, serviceName);
}
@Override
protected void onHandleIntent(Intent intent) {
if(DEBUG)Log.i(tag, "onHandleIntent( );");
ilCounter++;
hdrCFlash.sendEmptyMessage(0);
}
}
@Override @SuppressLint("HandlerLeak")
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(DEBUG)Log.i(tag, "onCreate( );");
setContentView(R.layout.activity_main);
ctvCounter = (TextView)findViewById(R.id.ctv_counter);
hdrCFlash = new Handler( ){
public void handleMessage(Message msg){
ctvCounter.setText("Counter:"+ilCounter);
}
};
cbSchedule = (Button)findViewById(R.id.cb_schedule);
cbSchedule.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
scheduleService( );
}
});
cbCancel = (Button)findViewById(R.id.cb_cancel);
cbCancel.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
cancelService( );
}
});
}
@Override
protected void onPause( ) {
super.onPause( );
}
@Override
protected void onStop( ) {
super.onStop( );
cancelService( );
// ↑ Activity が Stop したら「Alarm Service」を停止している。
}
@Override
protected void onDestroy( ) {
super.onDestroy( );
}
protected void scheduleService( ){
if(DEBUG)Log.i(tag, "scheduleService( );");
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.RTC,
System.currentTimeMillis( ),
interval, pendingIntent);
}
protected void cancelService( ){
if(DEBUG)Log.i(tag, "cancelService( );");
ilCounter = 0;
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)
context.getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater( ).inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId( );
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
『res\layout\activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.keicode.android.alarm0018_pkg.AlarmActivity" >
<TextView
android:id="@+id/ctv_counter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="AlarmManager" />
<Button
android:id="@+id/cb_schedule"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="schedule" />
<Button
android:id="@+id/cb_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="cancel" />
</LinearLayout >
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.keicode.android.alarm0018_pkg"
android:versionName="1.0"
android:versionCode="10" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".AlarmActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".AlarmActivity$MyService"></service>
</application>
</manifest>
|
|
|
<Number>: [000008B2]
<Date>: 2014/12/26 02:57:48
<Title>:
<Name>: amanojaku@管理人
|
|
|
Alarm (3)
今回、Android 用 JavaFX プログラミングで参考にしたサイト。
http://techbooster.jpn.org/andriod/multimedia/3417/
キッチン・タイマー:指定された秒数をカウント・ダウンし、ゼロになったらシステム音を鳴らす。
とりあえずアプリケーション名は"Alarm0019_JFX"、プロジェクト名は"Alarm0019_Prj"、パッケージ名は"com.example.alarm0019_pkg"、"Activity"名は"MainActivity"、"Layout"名は"activity_main"としている、その他はデフォルトでスケルトンを作成。
『src/com.example.alarm0019_pkg/MainActivity.java』
package com.example.alarm0019_pkg;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
//↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
//全部 大文字で記述するの事が推奨されているようだ。
//「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される事になる。
static MainActivity app;
static Handler hdrCFlash;
static volatile long ilCounter; // volatile:最適化の抑制。
// ↑ "volatile"(最適化の抑制)により「Event、他の Thread」からの変数の可視性が保障されます。
// ただ"volatile"(最適化の抑制)で「Event、他の Thread」からの変数の正しい操作が保障されるわけではないので、過信するのは禁物です。
// 例えば「volatile int i」と宣言されていたとして「i++」と言う単純な命令が「メモリーからレジスターに読み取り、レジスターに1を加算、レジスターからメモリーに書き出し」と言う3個の命令として実行されるので、そこに"Atomic"性はありません。
// つまり 一見 単純に見える命令でも取りあえずは"Atomic"性は保障されないと考えておくベキ。
// "Atomic"性を確保したい場合は"synchronized"を使用する必要があります。
EditText cetCounter;
Button cbStart;
Button cbCancel;
long interval = 1000;
public static class MyService extends IntentService {
static final String serviceName = MyService.class.getSimpleName( );
// getName(); // パッケージ名を含むクラス名
// getSimpleName() // クラス名のみ
public MyService( ) {
super(serviceName);
if(DEBUG)Log.i(tag, serviceName);
}
@Override
protected void onHandleIntent(Intent intent) {
if(DEBUG)Log.i(tag, "onHandleIntent( );");
synchronized(app) {
// ↑ この synchronized によって「ilCounter--」、「if(ilCounter<=0)」、「app.cancelService( )」内の「ilCounter = 0」と それに関連する Process 、「if(ilCounter<=0)」などの一連の Process の"Atomic"性を確保している。
// 恐らく変数にアクセスされる側(この場合は app)を Monitor にすれば良いと思われる、Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
// こんな簡単な Program で わざわざ synchronized を使う事も無いのだけど、
// 少し 複雑になって来ると必要になる事もあるので、その場合のサンプル的な意味合い。
ilCounter--;
if(ilCounter<=0){
app.cancelService( );
}
hdrCFlash.sendEmptyMessage(0);
if(ilCounter<=0) beep( );
}
}
}
static public void beep( ){
ToneGenerator tg
= new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
for(int i = 0; i<7; i++){
tg.startTone(ToneGenerator.TONE_DTMF_0, 150); // 150ms の鳴動
try {
Thread.sleep(150); // 150ms の Sleep
} catch (InterruptedException e){ }
}
}
@Override @SuppressLint("HandlerLeak")
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(DEBUG)Log.i(tag, "onCreate( );");
app = this;
setContentView(R.layout.activity_main);
cetCounter = (EditText)findViewById(R.id.cet_counter);
hdrCFlash = new Handler( ){
public void handleMessage(Message msg){
cetCounter.setText(String.valueOf(ilCounter));
}
};
cetCounter.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
cetCounter.setText("");
}
});
cbStart = (Button)findViewById(R.id.cb_start);
cbStart.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
try {
ilCounter = Integer.parseInt(cetCounter.getText( ).toString( ));
} catch ( NumberFormatException e) {
ilCounter = 0;
}
if(0<ilCounter ){
scheduleService( );
}
}
});
cbCancel = (Button)findViewById(R.id.cb_cancel);
cbCancel.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
cancelService( );
}
});
}
protected void scheduleService( ){
if(DEBUG)Log.i(tag, "scheduleService( );");
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.RTC,
System.currentTimeMillis( ),
interval, pendingIntent);
}
protected void cancelService( ){
if(DEBUG)Log.i(tag, "cancelService( );");
synchronized(app) {
// ↑ この synchronized によって「ilCounter = 0」と それに関連する一連の Process の"Atomic"性を確保している。
// 注.「ilCounter = 0」と それに関連する一連の Process には非常に希薄ではあるが依存関係がある事に留意。
// 恐らく変数にアクセスされる側(この場合は app)を Monitor にすれば良いと思われる、Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
// こんな簡単な Program で わざわざ synchronized を使う事も無いのだけど、
// 少し 複雑になって来ると必要になる事もあるので、その場合のサンプル的な意味合い。
ilCounter = 0;
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)
context.getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
hdrCFlash.sendEmptyMessage(0);
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater( ).inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId( );
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
『res\layout\activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.alarm0019_pkg.MainActivity" >
<EditText
android:id="@+id/cet_counter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:gravity="right"
android:imeOptions="normal"
android:inputType="numberDecimal"
android:text="0"
android:textAlignment="gravity"
android:textColor="#000000" >
<requestFocus />
</EditText>
<Button
android:id="@+id/cb_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/cb_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Cancel" />
</LinearLayout >
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.alarm0019_pkg"
android:versionName="1.0"
android:versionCode="12" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MainActivity$MyService"></service>
</application>
</manifest>
|
|
|
<Number>: [000008C5]
<Date>: 2014/12/26 02:55:44
<Title>:
<Name>: amanojaku@管理人
|
|
|
Alarm (3) 改
>キッチン・タイマー:指定された秒数をカウント・ダウンし、ゼロになったらシステム音を鳴らす。
"分"の入力を可能に、beep をバックグラウンド処理に。
とりあえずアプリケーション名は"Alarm0020_JFX"、プロジェクト名は"Alarm0020_Prj"、パッケージ名は"com.example.alarm0020_pkg"、"Activity"名は"MainActivity"、"Layout"名は"activity_main"としている、その他はデフォルトでスケルトンを作成。
『src/com.example.alarm0020_pkg/MainActivity.java』
package com.example.alarm0020_pkg;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View.OnFocusChangeListener;
import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
//↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
//全部 大文字で記述するの事が推奨されているようだ。
//「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される事になる。
static MainActivity app;
static Handler hdrCFlash;
static long ilMinute;
static long ilSecond;
static volatile long ilCounter; // volatile:最適化の抑制。
// ↑ "volatile"(最適化の抑制)により「Event、他の Thread」からの変数の可視性が保障されます。
// ただ"volatile"(最適化の抑制)で「Event、他の Thread」からの変数の正しい操作が保障されるわけではないので、過信するのは禁物です。
// 例えば「volatile int i」と宣言されていたとして「i++」と言う単純な命令が「メモリーからレジスターに読み取り、レジスターに1を加算、レジスターからメモリーに書き出し」と言う3個の命令として実行されるので、そこに"Atomic"性はありません。
// つまり 一見 単純に見える命令でも取りあえずは"Atomic"性は保障されないと考えておくベキ。
// "Atomic"性を確保したい場合は"synchronized"を使用する必要があります。
EditText cetMinute;
EditText cetSecond;
Button cbStart;
Button cbCancel;
long ilInterval = 1000;
public static class MyService extends IntentService {
static final String serviceName = MyService.class.getSimpleName( );
// getName(); // パッケージ名を含むクラス名
// getSimpleName() // クラス名のみ
public MyService( ) {
super(serviceName);
if(DEBUG)Log.i(tag, serviceName);
}
@Override
protected void onHandleIntent(Intent intent) {
if(DEBUG)Log.i(tag, "onHandleIntent( );");
synchronized(app) {
// ↑ この synchronized によって「ilCounter--」、「if(ilCounter<=0)」、「app.cancelService( )」内の「ilCounter = 0」と それに関連する Process 、などの一連の Process の"Atomic"性を確保している。
// 恐らく変数にアクセスされる側(この場合は app)を Monitor にすれば良いと思われる、Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
// こんな簡単な Program で わざわざ synchronized を使う事も無いのだけど、
// 少し 複雑になって来ると必要になる事もあるので、その場合のサンプル的な意味合い。
ilCounter--;
if(ilCounter<=0){
app.cancelService( );
beepThread( );
}
}
hdrCFlash.sendEmptyMessage(0);
}
}
static public void beep( ){
ToneGenerator tg
= new ToneGenerator(AudioManager.STREAM_SYSTEM, ToneGenerator.MAX_VOLUME);
for(int i = 0; i<7; i++){
tg.startTone(ToneGenerator.TONE_DTMF_0, 150); // 150ms の鳴動
try {
Thread.sleep(150); // 150ms の Sleep
} catch (InterruptedException e){ }
}
}
static public void beepThread( ){
(new Thread(new Runnable( ){
@Override
public void run( ){
// バックグランド処理
beep( );
}
})).start( );
}
@Override @SuppressLint("HandlerLeak")
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(DEBUG)Log.i(tag, "onCreate( );");
app = this;
setContentView(R.layout.activity_main);
cetMinute = (EditText)findViewById(R.id.cet_minute);
cetMinute.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
cetMinute.setText("");
}
});
cetMinute.setOnFocusChangeListener(new OnFocusChangeListener( ){
@Override
public void onFocusChange(View v, boolean hasFocus){
if(hasFocus){
cetMinute.setText("");
}
}
});
cetSecond = (EditText)findViewById(R.id.cet_second);
cetSecond.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
cetSecond.setText("");
}
});
cetSecond.setOnFocusChangeListener(new OnFocusChangeListener( ){
@Override
public void onFocusChange(View v, boolean hasFocus){
if(hasFocus){
cetSecond.setText("");
}
}
});
hdrCFlash = new Handler( ){
public void handleMessage(Message msg){
cetMinute.setText(String.valueOf((long)Math.floor(ilCounter/60)));
cetSecond.setText(String.valueOf(ilCounter%60));
}
};
cbStart = (Button)findViewById(R.id.cb_start);
cbStart.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
try {
ilMinute = Integer.parseInt(cetMinute.getText( ).toString( ));
} catch ( NumberFormatException e) {
ilMinute = 0;
}
try {
ilSecond = Integer.parseInt(cetSecond.getText( ).toString( ));
} catch ( NumberFormatException e) {
ilSecond = 0;
}
ilCounter = ilMinute*60+ilSecond;
if(0<ilCounter ){
scheduleService( );
}
}
});
cbCancel = (Button)findViewById(R.id.cb_cancel);
cbCancel.setOnClickListener(new OnClickListener( ){
@Override
public void onClick(View v){
cancelService( );
}
});
}
protected void scheduleService( ){
if(DEBUG)Log.i(tag, "scheduleService( );");
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)context.getSystemService(ALARM_SERVICE);
alarmManager.setInexactRepeating(
AlarmManager.RTC,
System.currentTimeMillis( ),
ilInterval, pendingIntent);
}
protected void cancelService( ){
if(DEBUG)Log.i(tag, "cancelService( );");
synchronized(app) {
// ↑ この synchronized によって「ilCounter = 0」と それに関連する一連の Process の"Atomic"性を確保している。
// 注.「ilCounter = 0」と それに関連する一連の Process には非常に希薄ではあるが依存関係がある事に留意。
// 恐らく変数にアクセスされる側(この場合は app)を Monitor にすれば良いと思われる、Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
// こんな簡単な Program で わざわざ synchronized を使う事も無いのだけど、
// 少し 複雑になって来ると必要になる事もあるので、その場合のサンプル的な意味合い。
ilCounter = 0;
Context context = getBaseContext( );
Intent intent = new Intent(context, MyService.class);
PendingIntent pendingIntent
= PendingIntent.getService(
context, -1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager
= (AlarmManager)
context.getSystemService(ALARM_SERVICE);
alarmManager.cancel(pendingIntent);
}
hdrCFlash.sendEmptyMessage(0);
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater( ).inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId( );
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
『res\layout\activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.alarm0020_pkg.MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText
android:id="@+id/cet_minute"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:ems="10"
android:gravity="right"
android:imeOptions="normal"
android:inputType="numberDecimal"
android:text="0"
android:textAlignment="gravity"
android:textColor="#000000" />
<EditText
android:id="@+id/cet_second"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:ems="10"
android:gravity="right"
android:imeOptions="normal"
android:inputType="numberDecimal"
android:text="0"
android:textAlignment="gravity"
android:textColor="#000000" />
</LinearLayout>
<Button
android:id="@+id/cb_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start" />
<Button
android:id="@+id/cb_cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Cancel" />
</LinearLayout >
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.alarm0020_pkg"
android:versionName="1.0"
android:versionCode="12" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MainActivity$MyService"></service>
</application>
</manifest>
|
|
|
<Number>: [000008D2]
<Date>: 2014/12/28 09:58:19
<Title>:
<Name>: amanojaku@管理人
|
|
|
ActionBar「API Level 8」(Android OS 2.2)
端末にハードウェア・メニュー・キー(注.ハードウェア・キーボードではない)が有ると、ActionBarActivity のセールス・ポインットである、画面右上のメニュー・アイコン(three dots icon)が消えてしまうが(これは仕様だと言う事です)、消えないようにしたいし、ActionBarActivity は Android OS 3.0 以上からサポートされているが、Android OS 2.2 以上から使えるようにしたい。
ただし、アイコンが違うとか、メニューの表示位置が違うとかの違いはあるし、当然 機能も限定されるようだが…。
今回、Android 用 JavaFX プログラミングで参考にしたサイト。
Android - ActionBarにメニューの「…」を常時表示してサブメニューにアイコンを表示する - Qiita
http://qiita.com/takke/items/26993bcabd6866244fba
【Android】ActionBarを使ってみる @ (メニューボタン) - It’s now or never
http://inon29.hateblo.jp/entry/2014/03/09/162616
Androidで用意されているアイコン一覧 - 技術脳塗
https://sites.google.com/site/technoute/android/icon/drawable
とりあえずアプリケーション名は"ActionBar_API8_JFX"、プロジェクト名は"ActionBar_API8_Prj"、パッケージ名は"com.example.actionbar_api8_pkg"、"Activity"名は"MainActivity"、"Layout"名は"activity_main"としている、その他はデフォルトでスケルトンを作成。
『src/com.example.actionbar_api8_pkg/MainActivity.java』
package com.example.actionbar_api8_pkg;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends ActionBarActivity {
private MainActivity app;
private Menu mainMenu;
private RelativeLayout clRootLayout;
private TextView ctvMessage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = this;
setContentView(R.layout.activity_main);
clRootLayout = (RelativeLayout)findViewById(R.id.cl_root_layout);
ctvMessage = (TextView)findViewById(R.id.ctv_message);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater( ).inflate(R.menu.main, menu);
mainMenu = menu;
return true;
}
@Override
public boolean onKeyUp(int keyCode,KeyEvent event) {
// boolean result = false; // true; //
switch (keyCode) {
case KeyEvent.KEYCODE_MENU:
if (mainMenu != null) {
mainMenu.performIdentifierAction(R.id.menu_primary, 0);
}
return true; // false; //
// break;
default:
return super.onKeyUp(keyCode, event);
}
// return false; // true; //
// ↑ イベントを消費した後、そのイベントを後続に引き継がせるかどうかを示す boolean 値
// つまり、 イベントのハンドリングが完了した後ここで動作を止めるよう指示する場合は true を返却します。
// イベントのハンドリングをしない場合、かつ(または) そのイベントを他のキーイベントリスナに引き継がせるよう指示する場合は false を返却します。
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// 「UI(User Interface) Control」 のサイズが変化する場合、(Root Layout の)「invalidate( )」メソッドを実行してやらなければならないようだ。
// boolean refresh = false; // true; //
String vsMessageText;
// ↑ 実際は"vsMessageText"変数は必用無いのだけど 、あまりダラダラ長いと少々 解かりづらいので意図的に使っている。
synchronized(app) {
// ↑ この synchronized によって「R.id.mitem_〜」のデータを「ctvMessage」へ代入する一連の Process の"Atomic"性を確保している。
// 恐らく変数にアクセスされる側(この場合は app)を Monitor にすれば良いと思われる、Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
// こんな簡単な Program で わざわざ synchronized を使う事も無いのだけど、
// 少し 複雑になって来ると必要になる事もあるので、その場合のサンプル的な意味合い。
switch (item.getItemId( )) {
case R.id.mitem_smile:
vsMessageText = ((MenuItem)mainMenu.findItem(R.id.mitem_smile)).getTitle( ).toString( );
ctvMessage.setText(vsMessageText);
clRootLayout.invalidate( ); // 描画反映
return true; // false; //
// break;
case R.id.mitem_eyesturn:
vsMessageText = ((MenuItem)mainMenu.findItem(R.id.mitem_eyesturn)).getTitle( ).toString( );
ctvMessage.setText(vsMessageText);
clRootLayout.invalidate( ); // 描画反映
return true; // false; //
// break;
case R.id.mitem_crying:
vsMessageText = ((MenuItem)mainMenu.findItem(R.id.mitem_crying)).getTitle( ).toString( );
ctvMessage.setText(vsMessageText);
clRootLayout.invalidate( ); // 描画反映
return true; // false; //
// break;
default:
return super.onOptionsItemSelected(item);
}
}
// return false; // true; //
}
}
『res\layout\activity_main.xml』
<RelativeLayout
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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.actionbar_api8_pkg.MainActivity"
android:id="@+id/cl_root_layout"
android:background="#ffffff" >
<TextView
android:id="@+id/ctv_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#bbbbbb"
android:text="@string/hello_world"
android:textColor="#000000" />
</RelativeLayout>
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.actionbar_api8_pkg"
android:versionName="1.0"
android:versionCode="1" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
|
|
|
<Number>: [000008F9]
<Date>: 2015/01/10 11:22:52
<Title>:
<Name>: amanojaku@管理人
|
|
|
SurfaceView(2) 改(3)
《参考》
SurfaceView(2) 改(2)
http://artemis.rosx.net/sjis/smt.cgi?r+izanami/&bid+0000083C&tsn+00000871&bts+2014/10/28%2002%3A03%3A17&
※「SurfaceView(2) 改(3)」との違いを見てみるのも良いかもしれません。
簡単に言えば「SurfaceView(2) 改(3)」において「canvas、surfaceHolder」に関する処理が 全て「RunningSurfaceView」クラスに記述されている、つまり「RunningDriver」クラスには一切「canvas、surfaceHolder」に関する処理が記述されてない。
つまり「RunningDriver」クラスを継承して別のクラスを記述すれば、ムダなく(この場合は「RunningDriver」クラスを)再利用できる事になる。
> 本来なら これら「canvas、surfaceHolder」は ここで記述するべきではなく、
> 別クラスを継承しで そこで記述してやるのが筋。
> 本来なら この「initialize( )」メソッドは
> この"RunningDriver"クラスでは抽象メソッドとし、
> 別クラスで それらのメソッドをオーバーライドしてやるのが筋。
> 本来なら下記「runningHeader( )、runningFooter( )」 メソッドは
> この"RunningDriver"クラスでは抽象メソッドとし、
> 別クラスで それらのメソッドをオーバーライドしてやるのが筋。
これらを実際にコーディングしている例。
とりあえずアプリケーション名は"A011_JFX"、プロジェクト名は"A011_Prj"、パッケージ名は"com.example.a011_pkg"としている、その他はデフォルトでスケルトンを作成。
ボタン"Accept"(アクセプト)は"Through"(スルー)状態の Runner を再スタートさせる。
ボタン"Through"(スルー)は Runner を"Through"(スルー)状態(runningEngine は動いているが Runner はスルーとなる)にする。
ボタン"notify"は"Wait"状態の Runner を再スタートさせる。
ボタン"Wait"は Runner を"Wait"状態にする。
ボタン"Create"(クリエイト)は"runningEngine"(Thread)を生成しスタートさせる。
ボタン"Destroy"(デストロイ)は"runningEngine"(Thread)を破棄する。
『src/com.example.a011_pkg/MainActivity.java』
package com.example.a011_pkg;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView.BufferType;
import android.util.Log;
public class MainActivity extends ActionBarActivity implements
SurfaceHolder.Callback {
static final String tag = "Log.Debug"; // フィルタリング用タグ
static final boolean DEBUG = true; // false; //
// ↑ この"DEBUG"は予約語では無い、"Java"において"final"(定数)の場合は
// 全部 大文字で記述するの事が推奨されているようだ。
// 「DEBUG=true」に設定すれば「if(DEBUG)Log.i(〜)」によって"LogCat"に出力される事になる。
Thread running = null;
boolean runningSW = true; // false; //
static int appLaunchMode;
public static final int LAUNCH_CREATE = 1;
public static final int LAUNCH_RESTART = 2;
MainActivity app;
int screenWidth, screenHeight;
boolean surfaceChangedSW = false; // true; //
String vsMessage = "";
EditText cetMessage;
RunningSurfaceView runningSurfaceView;
// Canvas canvas;
int[] cPalette = {
Color.RED,Color.YELLOW,Color.MAGENTA,Color.GREEN,Color.CYAN,Color.BLUE };
// ↑ カラーの実態は Color オブジェクトではなく int。
public abstract class RunnerPrimitive {
boolean ThroughSW = false; // true; //
public void run( ){ }
}
public abstract class RunnerFigure extends RunnerPrimitive {
RunningSurfaceView runningSurfaceView;
Color color;
Paint paint = new Paint( );
int cx,cy,dx,dy;
}
public class RunnerCircle extends RunnerFigure {
int radius = 30;
public RunnerCircle(RunningSurfaceView RSV) {
runningSurfaceView = RSV;
if(DEBUG)Log.i(tag,
"RunnerCircle( )"+"\n"+
"screenWidth="+screenWidth+"\n"+
"screenHeighth="+screenHeight+"\n"+
"");
cx = (int)Math.round(Math.random( )*screenWidth);
cy = (int)Math.round(Math.random( )*screenHeight);
if(DEBUG)Log.i(tag,
"cx="+cx+"\n"+
"cy="+cy+"\n"+
"");
dx = (int)Math.signum(Math.round(Math.random( ))-.5)*10;
dy = (int)Math.signum(Math.round(Math.random( ))-.5)*10;
if(DEBUG)Log.i(tag,
"dx="+dx+"\n"+
"dy="+dy+"\n"+
"");
int c = cPalette[(int)Math.round(Math.random( )*(cPalette.length-1))];
paint.setStyle(Style.FILL);
paint.setColor(c);
if(DEBUG)Log.i(tag,
"paint.set"+"\n"+
"");
}
@Override
public void run( ) {
synchronized(runningSurfaceView) {
runningSurfaceView.canvas.drawCircle(
cx, cy, radius,paint);
if( ! ThroughSW ) {
if( (cx+dx)<0 | screenWidth<(cx+dx) ){
dx = -dx;
}
cx += dx;
if( (cy+dy)<0 | screenHeight<(cy+dy) ){
dy = -dy;
}
cy += dy;
}
}
}
}
public abstract class RunningDriver
implements Runnable {
RunnerFigure[] runnerMembers = new RunnerFigure[5];
// ↑ 手抜きで配列にしているが、本来ならノードで連結させるのが筋。
int runnerNumber;
public Thread runningEngine = null;
public boolean runningEngineSW = false; // true; //
public boolean waitSW = false; // true; //
long interval = 50;
public RunningDriver( ){ }
public void launch(int LaunchMode){
switch (LaunchMode){
case LAUNCH_CREATE:
initialize( );
runningEngineCreate( );
break;
case LAUNCH_RESTART:
runningEngineCreate( );
break;
default:
}
}
public abstract void initialize( );
public abstract void runningHeader( );
public abstract void runningFooter( );
public void runnerAcceptAll( ){
for( int i = 0; i<runnerMembers.length; i++){
if( runnerMembers[i]!=null ){
runnerMembers[i].ThroughSW = false; // true; //
}
}
}
public void runnerThroughAll( ){
for( int i = 0; i<runnerMembers.length; i++){
if( runnerMembers[i]!=null ){
runnerMembers[i].ThroughSW = true; // false; //
}
}
}
public void runningEngineCreate( ) {
runnerAcceptAll( );
runningEngineSW = true; // false; //
waitSW = false; // true; //
// runningEngine = null;
runningEngine = new Thread(this);
runningEngine.start( );
}
public void runningEngineDestroy( ){
try{
runningEngine.interrupt( );
} catch(NullPointerException e) {
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:runningEngineDestroy( ):NullPointerException;");
}
}
public void run( ){
if(DEBUG)Log.i(tag, "RunningDriver.run( );");
while(
runningEngine!=null &
runningEngineSW
){
synchronized(this) {
// ↑ この this は runningEngine では無く RunningDriver を継承している オブジェクトのインスタンス。
try{
runningHeader( );
for( runnerNumber = 0; runnerNumber<runnerMembers.length; runnerNumber++){
if( runnerMembers[runnerNumber]!=null ){
runnerMembers[runnerNumber].run( );
}
}
runningFooter( );
} catch(NullPointerException e) {
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:run( ):NullPointerException;");
runningEngineSW = false; // true; //
}
while(waitSW){
try{
this.wait( );
// ↑ この this は runningEngine では無く RunningDriver を継承している オブジェクトのインスタンス。
}catch(InterruptedException e){
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:run( ):InterruptedException;");
runningEngineSW = false; // true; //
}
}
if( runningEngineSW ){
try{
Thread.sleep(interval);
// ↑ 「sleep(interval)」は指定された時間以上に待たされる場合があるようなので、
// 1回のループは「プログラムの処理時間+sleep(interval+α)」 となるから、
// 正確(完璧に正確無比と言う意味ではない)なタイマーを作りたい場合は
//「long time = System.currentTimeMillis( )」を使って一工夫が必要となる。
} catch(InterruptedException e) {
// e.printStackTrace( );
if(DEBUG)Log.i(tag, "RunningDriver:run( ):InterruptedException;");
runningEngineSW = false; // true; //
}
}
}
}
runningEngine = null;
}
}
public class RunningSurfaceView extends RunningDriver {
public Canvas canvas;
public SurfaceHolder surfaceHolder;
public RunningSurfaceView( ){
super( );
}
@Override
public void initialize( ){
for( int i = 0; i<runnerMembers.length; i++){
runnerMembers[i] = new RunnerCircle(this);
}
}
@Override
public synchronized void runningHeader( ){
// ↑ Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
Paint bgPaint = new Paint();
bgPaint.setStyle(Style.FILL);
bgPaint.setColor(Color.WHITE);
canvas = surfaceHolder.lockCanvas( );
canvas.drawRect(
0, 0, screenWidth, screenHeight,
bgPaint);
}
@Override
public synchronized void runningFooter( ){
// ↑ Method に直に指定した場合は「synchronized(this)」と等価になるらしい。
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(DEBUG)Log.i(tag, "onCreate( );");
app = this;
appLaunchMode = LAUNCH_CREATE;
cetMessage = (EditText)findViewById(R.id.cet_message);
vsMessage = vsMessage+"onCreate\n";
cetMessage.setText(vsMessage, BufferType.NORMAL);
runningSurfaceView = new RunningSurfaceView( );
// 「MainActivity」クラスの この「onCreate( )」コンストラクターでは
// まだ"SurfaceView"の生成が完了してない場合が有るようで、
// その時点で"Thread"が実行された場合
// 「surfaceHolder.lockCanvas( )」による"Canvas"の生成が"null"になってしまうので、
// 「RunningSurfaceView( )」コンストラクターには
// 「runningEngineCreate( )」("Thread"の生成・実行)は内包しない。
// 又、「RunnerCircle( )」 コンストラクター実行時には
// 「screenWidth、screenHeight」が設定されていなければならないので
// 「RunningSurfaceView( )」コンストラクターには内包せず、別途「initialize( )」に内包する。
// それら「initialize( )、runningEngineCreate( )」は「launch( )」に内包し「surfaceChanged( )」で実行する。
// ただし「launch( )」に内包された それら(「initialize( )、runningEngineCreate( )」)は"appLaunchMode"で実行の可否が決定される。
if(DEBUG)Log.i(tag, "runningSurfaceView = new RunningSurfaceView( );");
vsMessage = vsMessage+"runningSurfaceView = new RunningSurfaceView( )\n";
cetMessage.setText(vsMessage, BufferType.NORMAL);
/* ボタンを取り出す */
Button cbAcceptAll = (Button)findViewById(R.id.cb_accept_all);
/* ボタンにリスナーを登録する */
cbAcceptAll.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningSurfaceView.runnerAcceptAll( );
}
});
/* ボタンを取り出す */
Button cbThroughAll = (Button)findViewById(R.id.cb_through_all);
/* ボタンにリスナーを登録する */
cbThroughAll.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningSurfaceView.runnerThroughAll( );
}
});
/* ボタンを取り出す */
Button cbWait = (Button)findViewById(R.id.cb_wait);
/* ボタンにリスナーを登録する */
cbWait.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningSurfaceView.waitSW = true; // false; //
}
});
/* ボタンを取り出す */
Button cbNotify = (Button)findViewById(R.id.cb_notify);
/* ボタンにリスナーを登録する */
cbNotify.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
try{
synchronized(runningSurfaceView){
runningSurfaceView.waitSW = false; // true; //
runningSurfaceView.notify( );
}
}catch(IllegalMonitorStateException e){ }
}
});
/* ボタンを取り出す */
Button cbCreate = (Button)findViewById(R.id.cb_create);
/* ボタンにリスナーを登録する */
cbCreate.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningSurfaceView.runningEngineCreate( );
}
});
/* ボタンを取り出す */
Button cbDestroy = (Button)findViewById(R.id.cb_destroy);
/* ボタンにリスナーを登録する */
cbDestroy.setOnClickListener(new OnClickListener( ) {
@Override
public void onClick(View v) {
runningSurfaceView.runningEngineDestroy( );
}
});
}
@Override
protected void onRestart( ) {
super.onRestart( );
if(DEBUG)Log.i(tag, "onRestart( );");
appLaunchMode = LAUNCH_RESTART;
}
@Override
protected void onStart( ) {
super.onStart( );
if(DEBUG)Log.i(tag, "onStart( );");
surfaceChangedSW = false; // true; //
SurfaceView SV = (SurfaceView)findViewById(R.id.SV);
SurfaceHolder SH = SV.getHolder();
SH.addCallback(app);
// SV.setFocusable(true);
// SV.requestFocus( );
runningSurfaceView.surfaceHolder = SH;
}
@Override
protected void onResume( ) {
super.onResume( );
if(DEBUG)Log.i(tag, "onResume( );");
}
@Override
protected void onPause( ) {
super.onPause( );
if(DEBUG)Log.i(tag, "onPause( );");
}
@Override
protected void onStop( ) {
super.onStop( );
if(DEBUG)Log.i(tag, "onStop( );");
runningSurfaceView.runningEngineDestroy( );
runningSurfaceView.surfaceHolder.removeCallback(app);
}
@Override
protected void onDestroy( ) {
super.onDestroy( );
if(DEBUG)Log.i(tag, "onDestroy( );");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void surfaceCreated(SurfaceHolder holder) { }
@Override
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
screenWidth = width;
screenHeight = height;
if(DEBUG)Log.i(tag,
"surfaceChanged( );"+"\n"+
"screenWidth="+screenWidth+"\n"+
"screenHeighth="+screenHeight+"\n"+
"");
vsMessage = vsMessage+
"screenWidth="+screenWidth+"\n"+
"screenHeighth="+screenHeight+"\n"+
"";
cetMessage.setText(vsMessage, BufferType.NORMAL);
vsMessage = vsMessage+"surfaceChanged( )\n";
cetMessage.setText(vsMessage, BufferType.NORMAL);
if( ! surfaceChangedSW ){
surfaceChangedSW = true; // false; //
// "surfaceChangedSW"がクリアーされない限りは、「surfaceChanged( )」 が2回以上呼ばれても、ここは1回しか実行されない。
runningSurfaceView.launch(appLaunchMode);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) { }
}
『res\layout\activity_main.xml』
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.a011_pkg.MainActivity" >
<SurfaceView
android:id="@+id/SV"
android:layout_width="fill_parent"
android:layout_height="200dp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/cb_accept_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/AcceptAll" />
<Button
android:id="@+id/cb_through_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/ThroughAll" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/cb_notify"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Notify" />
<Button
android:id="@+id/cb_wait"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Wait" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/cb_create"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Create" />
<Button
android:id="@+id/cb_destroy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Destroy" />
</LinearLayout>
<EditText
android:id="@+id/cet_message"
android:gravity="top"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</LinearLayout>
『res\values\strings.xml』
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">A011_JFX</string>
<string name="action_settings">Settings</string>
<string name="AcceptAll">Accept</string>
<string name="ThroughAll">Through</string>
<string name="Notify">Notify</string>
<string name="Wait">Wait</string>
<string name="Create">Create</string>
<string name="Destroy">Destroy</string>
</resources>
『AndroidManifest.xml』
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.a011_pkg"
android:versionName="1.0"
android:versionCode="8" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleInstance" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
|
|
|