前々々々回 Android アプリを Xamarin.Android に移植する (1) で UI を移植しました。
出来上がった画面。
今回 3 つ目のクラスの移植を行って行きます。一番のメイン、Activity クラスです。
■ 今回移植するクラス
今回は
・com.example.android.mediarecorder.MainActivity
クラス
を C# で書き換えます。
■ MainActivity クラスの編集
MainActivity クラス
MainActivity クラスは既に生成されているクラスを書き換えて行きます。
using の追加
今回も必要な using
は最初に追加してしまいます。ファイルの先頭の using
の部分が次のようになるようコピー&ペーストしてください。
using System;
using Android.App;
using Android.Content.PM;
using Android.Hardware;
using Android.OS;
using Android.Views;
using Java.IO;
using Android.Media;
using Android.Widget;
using Java.Lang;
using Android.Util;
using System.Collections.Generic;
using String = System.String;
データメンバー の移植
Java のクラスの先頭で定義されているデータメンバーを移植します。
MainActivity.java の 46 行目からの次のコードを、C# の MainActivity.cs の同じ位置 (クラスの宣言と OnCreate
メソッドの宣言の間) に追加します。
下記の C# のコードをコピー&ペーストしてください。
・Java のコード
private Camera mCamera;
private TextureView mPreview;
private MediaRecorder mMediaRecorder;
private File mOutputFile;
private boolean isRecording = false ;
private static final String TAG = "Recorder" ;
private Button captureButton;
・C# のコード
private Camera mCamera;
private TextureView mPreview;
private Android.Media.MediaRecorder mMediaRecorder;
private File mOutputFile;
private bool isRecording = false ;
private static readonly string TAG = "Recorder" ;
private Button captureButton;
コントロールのインスタンス取得の追加
OnCreate
での処理を追加します。OnCreate
は画面生成時の処理で、今回は画面上のコントロールの実態をデータメンバーに保持します。
SetContentView(Resource.Layout.sample_main);
の下に下記の C# コードをコピー&ペーストします。これまで同様、Java では小文字始まりだったメソッド名が、大文字始まりになります。 ・Java のコード
mPreview = (TextureView) findViewById(R.id.surface_view);
captureButton = (Button) findViewById(R.id.button_capture);
・C# のコード
mPreview = (TextureView)FindViewById(Resource.Id.surface_view);
captureButton = (Button)FindViewById(Resource.Id.button_capture);
OnCreate
は次のようになります。
protected override void OnCreate(Bundle savedInstanceState)
{
base .OnCreate(savedInstanceState);
SetContentView(Resource.Layout.sample_main);
mPreview = (TextureView)FindViewById(Resource.Id.surface_view);
captureButton = (Button)FindViewById(Resource.Id.button_capture);
}
OnCaptureClick メソッドのコピー&ペースト
既に作成済みの OnCaptureClick
メソッドに実装を追加します。作成済みの OnCaptureClick
メソッドは次のようになっているはずです。
[Java.Interop.Export("onCaptureClick" )]
public void OnCaptureClick(View view)
{
}
このメソッドの中に、MainActivity.java の 71 行目 onCaptureClick
メソッドの内容をコピー&ペーストします。
いくらかのエラーが出ますが、構わず先へ進みます。
その他のメソッド等のコピー&ペースト
OnCaptureClick
の下に、MainActivity.java の 105 行目 setCaptureButtonText
メソッド以降のコードを最後の }
を除いてコピー&ペーストします。
メソッド名の変更
Java ではメソッド名は小文字で始まりますが、C# では大文字で始まります。
小文字で始まっているメソッド名を、大文字始まりに一気に変更して行きます。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・mMediaRecorder.stop()
→ mMediaRecorder.Stop()
・mOutputFile.delete()
→ mOutputFile.Delete()
・mCamera.lock
→ mCamera.Lock
・mMediaRecorder.reset()
→ mMediaRecorder.Reset()
・mMediaRecorder.release()
→ mMediaRecorder.Release()
・mCamera.release()
→ mCamera.Release()
・mCamera.getParameters()
→ mCamera.GetParameters()
・CamcorderProfile.get(
→ CamcorderProfile.Get(
・parameters.setPreviewSize(
→ parameters.SetPreviewSize(
・mCamera.setParameters(
→ mCamera.SetParameters(
・mCamera.setPreviewTexture(
→ mCamera.SetPreviewTexture(
・mCamera.unlock()
→ mCamera.Unlock()
・mMediaRecorder.set
→ mMediaRecorder.Set
・mMediaRecorder.prepare()
→ mMediaRecorder.Prepare()
・mMediaRecorder.start()
→ mMediaRecorder.Start()
string クラスへの変更
Java の String クラスは C# の string を使用するよう変更します。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・String
→ string
プロパティへの変更 (setter)
Java の setter メソッドはなるべく、プロパティに変更されています。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・captureButton.setText(title)
→ captureButton.Text = title
メソッドの orverride の変更
Java ではスーパークラスのメソッドをサブクラスで orverride する場合はアノテーションを設定しました。C# では return 値の型の前に orverride
キーワードを記述します。
スーパークラスは C# に移植されたクラスのため、メソッド名の先頭が大文字になる点に注意してください。
・Java のコード
@Override
protected void onPause()
・C# のコード
protected override void OnPause()
base への書き換え
Java ではスーパークラスのメソッドを呼び出す場合、super
キーワードを使用します。C# では同様の機能は base
になります。
スーパークラスは C# に移植されたクラスのため、メソッド名の先頭が大文字になる点に注意してください。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・super.onPause()
→ base.OnPause()
bool への変更
Java では真偽値型は boolean
キーワードですが、C# では bool
になります。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・boolean
→ bool
・Boolean
→ bool
IList への書き換え
List<>
は Java のインタフェースですが、C# ではインタフェースは頭に I が付いた IList<>
という名前になります。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・List<
→ IList<
プロパティへの変更
Java の getter メソッドはなるべく、プロパティに変更されています。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・parameters.getSupportedPreviewSizes()
→ parameters.SupportedPreviewSizes
・parameters.getSupportedVideoSizes()
→ parameters.SupportedVideoSizes
・mPreview.getWidth()
→ mPreview.Width
・mPreview.getHeight()
→ mPreview.Height
・mPreview.getSurfaceTexture()
→ mPreview.SurfaceTexture
・e.getMessage()
→ e.Message
・mOutputFile.getPath()
→ mOutputFile.Path
プロパティ名の変更
Java では公開データメンバは小文字で始まりますが、C# ではプロパティになり、大文字始まりになります。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・profile.videoFrameWidth
→ profile.VideoFrameWidth
・profile.videoFrameHeight
→ profile.VideoFrameHeight
・optimalSize.width
→ optimalSize.Width
・optimalSize.height
→ optimalSize.Height
列挙体への変更
Java では公開フォールドはなるべく列挙体に変更されています。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・CamcorderProfile.QUALITY_HIGH
→ CamcorderQuality.High
・MediaRecorder.AudioSource.DEFAULT
→ AudioSource.Default
・MediaRecorder.VideoSource.CAMERA
→ VideoSource.Camera
メソッド定義の変更
MainActivity.cs の 133 行目あたりの次の文でエラーが発生しているはずです。
これは、CameraHelper
クラス移植の際に手数を減らすために、本来行うべき Java の List<>
から C# の IList<T>
への置き換えを行っていないために発生しました。
※まずは、CameraHelper
を一度ビルドできる状態にするため省略しました。
Camera.Size optimalSize = CameraHelper.getOptimalVideoSize(mSupportedVideoSizes,
mSupportedPreviewSizes, mPreview.Width, mPreview.Height);
メソッド名 getOptimalVideoSize
にカーソルをあわせて F12 キーを押し、メソッドの定義へ移動します。
移動した先のメソッド定義を次のように変更します。
public static Camera.Size getOptimalVideoSize(IList<Camera.Size> supportedVideoSizes,
IList<Camera.Size> previewSizes, int w, int h)
この書き換えにより、10 行程下の行でエラーが発生します。このエラーを正すために、エラー行の 3 つ上の行の型定義も IList<Camera.Size>
に変更します。
・変更前
List<Camera.Size> videoSizes;
・変更後
IList<Camera.Size> videoSizes;
CameraHelper.cs にエラーがないことを確認し、MainActivity.cs に戻ります。
デバッグ出力メソッドの変更
デバッグ出力メソッドのメソッド名 d
は Debug
になっているので変更します。
また、エラー出力のメソッド名 e
は Error
になります。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・Log.d(
→ Log.Debug(
・Log.e(
→ Log.Error(
クラス継承のキーワードの変更
Java ではクラスの継承は extends
キーワードですが、C# では :
になります。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・extends
→ :
型引数 Void の変更
AsyncTask<>
の型引数 Void
は Java.Lang.Void
であることを明示します。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・AsyncTask<Void, Void, bool>
→ AsyncTask<Java.Lang.Void, Java.Lang.Void, bool>
MediaPrepareTask クラスの変更
MediaPrepareTask
クラスは Android API のクラスで、非同期処理を行う AsyncTask
クラスのサブクラスです。
この MediaPrepareTask
クラス内の変更も基本はこれまでのパターンで良いのですが、このクラスがインナークラスとして実装されているという大きな違いがあります。
Java のインナークラスは親クラスのインスタンスを参照できますが、C# ではそのようなことができません。
C# へ置き換える際に、MediaPrepareTask
クラスが親クラスである MainActivity
クラスのインスタンスを明示的に持つよう変更します。
少し複雑な書き換えを行うため MediaPrepareTask
クラスは完成コードをまるごとコピー&ペーストします。
次のコードへコピー&ペーストで置き換えてください。
class MediaPrepareTask : AsyncTask<Java.Lang.Void, Java.Lang.Void, bool >
{
private readonly WeakReference<MainActivity> _activity;
public MediaPrepareTask(MainActivity activity)
{
_activity = new WeakReference<MainActivity>(activity);
}
protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] voids)
{
MainActivity activity;
_activity.TryGetTarget(out activity);
if (activity.prepareVideoRecorder())
{
activity.mMediaRecorder.Start();
activity.isRecording = true ;
}
else
{
activity.releaseMediaRecorder();
return false ;
}
return true ;
}
protected override void OnPostExecute(bool result)
{
MainActivity activity;
_activity.TryGetTarget(out activity);
if (!result)
{
activity.Finish();
}
activity.setCaptureButtonText("Stop" );
}
protected override bool RunInBackground(params Java.Lang.Void[] @params )
{
throw new NotImplementedException();
}
}
MediaPrepareTask クラス使用の変更
MediaPrepareTask
クラスを MainActivity
クラスのインスタンスを保持するよう変更しました。
そのため、MediaPrepareTask
クラスの使用されている場所で、MainActivity
クラスのインスタンスを設定するよう変更します。
置換は Mac の場合は option+command+F
、Windows の場合は ctrl+H
で行えます。
・new MediaPrepareTask().execute(null, null, null);
→ new MediaPrepareTask(this).Execute(null, null, null);
■ MainActivity クラスの完成
これで MainActivity
クラスは完成です。
ビルドを行いエラーが出ないことを確認してください。(警告は大量に出ますが、今回はそのままにします)
エラーが出た場合は、エラーの内容と上記の書き換えを見比べて頑張ってエラーに対処してください。
■ 実行
ここまでで、一度アプリを実行してみましょう。
Visual Studio (for Mac) のツールバーの 右三角 アイコンをクリックします。
次の画面が表示されるはずです。
前回出来上がった画面
ここで、[capture] ボタンをタップするとエラーが発生します。
これはまだこのアプリがカメラ等を使うためのパーミッションを設定していないためです。
パーミッションを正しく設定していない場合、該当する機能を使用しようとするとエラーが発生するのがスマートデバイスの特徴です。
■ 設定ファイルの設定
編集する設定ファイルは、Properties
フォルダー内の AndroidManifest.xml
ファイルです。
・ソリューションエクスプローラー上で AndroidManifest.xml
をダブルクリックします。
・エディターで XML ファイルが開くので次のように編集します。ソースが開かない場合、[ソース]タブを選択してください。
・<manifest>
タグの中に次の要素を追加します。
<uses-permission android name ="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android name ="android.permission.RECORD_VIDEO" />
<uses-permission android name ="android.permission.RECORD_AUDIO" />
<uses-permission android name ="android.permission.CAMERA" />
<uses-feature android name ="android.hardware.camera" />
AndroidManifest.xml
全体は例えば次のようになります。
xml version ="1.0" encoding ="utf-8"
<manifest xmlns android ="http://schemas.android.com/apk/res/android" android versionCode ="1" android versionName ="1.0" package ="com.example.android.XamMediaRecorder" >
<uses-sdk android minSdkVersion ="16" />
<uses-permission android name ="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android name ="android.permission.RECORD_VIDEO" />
<uses-permission android name ="android.permission.RECORD_AUDIO" />
<uses-permission android name ="android.permission.CAMERA" />
<uses-feature android name ="android.hardware.camera" />
<application android allowBackup ="true" android icon ="@drawable/ic_launcher" android label ="@string/app_name" />
</manifest>
■ 実行
これでアプリが正しく動作するはずです。
もし、activity.mMediaRecorder.Start();
で例外が発生する場合は、AndroidManifest.xml
の <uses-sdk
の設定値を確認してみてください。
お疲れ様でした! これで Android アプリの Xamarin.Android への移植ができました。
この経験をもとにぜひ Xamarin で Android アプリを開発してください!