AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (2/2) AWSコンソールでの作業
AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (1/2) ローカルPC上の準備 - AWS Mobile Application Developmentに続き、AWS LambdaのS3への画像ファイルアップロード後にリサイズを行うファンクションの作成です。
[目次]
AWS S3 bucketの作成
加工前の画像が入るファイルのバッケットを「android-pic-tank」とし、加工後のファイルを「android-pic-tank-risize」として作成します。
・android-pic-tank
・android-pic-tank-resize
Lambda関数の作成
Lambda管理画面から新規作成
「Blank Function」をクリック。
トリガーとなる条件を記載。「android-pic-tank」に「put」(アップロード)されたファイルが「jpg」という名前が入っていればファイヤー。
以下みたいな感じで、設定。「Lambda Function Code」の方に前のステップで作成したzipファイルを指定。
今の状態では、S3のデータの読み込み権限しかないので、S3に書き込めるポリシーをアタッチします。
「AmazonS3FullAccess」をアタッチ。
これを設定していない場合、以下の権限エラーが発生します。
2016-11-28T01:01:33.431Z 3296e5ca-b506-11e6-95d7-b790461b4b89 Unable to resize android-pic-tank/604fb235-s.jpg and upload to android-pic-tank-resize/resized-604fb235-s.jpg due to an error: AccessDenied: Access Denied
Lambdaの関数設定画面に戻って、トリガーを「enable」にします。
確認画面で「enable」にした後、以下のように「disable」に設定できる状態であることを確認します。
S3の「android-pic-tank」バケットにファイルをアップロードします。
S3の「android-pic-tank-resize」に自動的に小さいファイルが作成されていることを確認します。
これで終了。うまくいかない場合は以下のようなテストを実行してみてエラーログなどを確認します。
Lambdaでのテスト
テストはまず以下のナビゲーションからテスト用のデータ設定をします。
テストデータ入力画面がでるので赤枠部分に値を設定します。「Save and Test」で実行します。
エラーでが出る場合というか出たのでタイムアウト値を変更します。
{ "errorMessage": "2016-11-25T06:51:29.366Z 95e036c5-b2db-11e6-a945-f5f796929e8e Task timed out after 3.00 seconds" }
10に設定。
設定後「test」ボタンで成功
LambdaxS3 を使う場合の注意点
トリガー設定を行うに当たって、S3の1つのバケット内に変換元ファイル、変換後ファイルをフォルダでわけるなどする場合は注意が必要です。トリガー設定の箇所でprefixでバケット配下のフォルダをチャント指定していないと、変換後に作成されたファイルの作成自体を検知して、無限ループが発生します。
ですので、設計として、バケット内のフォルダを複数階層にしない、バケットを複数もってそれぞれを変換元、変換先として用意したほうが安全です。知らないうちにクラウド破産になりかねません。
おしまい。
AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (1/2) ローカルPC上の準備
Androidからアップロードした画像ファイルのサムネイルを作成する目的でAWS Lambdaを使用してみましたので、簡単な動作確認までをご紹介。
[目次]
AWS Lambdaとは
AWS LambdaはNode.js(javascript)、python、javaでクラウド上の自動化処理の用途でプログラミングをすることができます。
AWS Lambda は、コードを AWS Lambda にアップロードすると、サービスが AWS インフラストラクチャを使用してコードの実行を代行するコンピューティングサービスです。コードをアップロードして、Lambda 関数と呼ばれる関数を作成することで、AWS Lambda がコードを実行するサーバーのプロビジョニングおよび管理を行います。AWS Lambda は次のように使用できます。 ・Amazon S3 バケットまたは Amazon DynamoDB テーブルのデータ変更などのイベントに対応して AWS Lambda がコードを実行するイベント駆動型コンピューティングサービスとして。 ・Amazon API Gateway を使用した HTTP リクエストまたは AWS SDK を使用した API 呼び出しに対応してコードを実行するコンピューティングサービスとして。
料金
遊ぶ分には無料で使えますな。
リクエストのうち毎月最初の 1,000,000 件は無料 その後は 0.20 USD/1,000,000 件のリクエスト(0.0000002 USD/リクエスト)
ローカルでのNode.js環境作成
今回はNode.jsベースで動かしてみたので、まずNode.jsをローカルのPCにインストールします。ちなみにAWSマニュアルにはNode.js v4.3で対応とありますので、Node.jsのサイトからv4.3をダウンロードします。
Note The code sample is compliant with the Node.js runtime v4.3. For more information, see Programming Model (Node.js)
Step 2.1: Create a Deployment Package - AWS Lambda
Node.jsのダンロード
https://nodejs.org/download/release/v4.3.2/
私の環境はwindows x64のPCなので「node-v4.3.2-x64.msi」をダウンロードました。
Node.jsのインストール
全てデフォルトの設定値で、インストールします。
Lambdaプログラムアップロード用ファイルを作成
どこでもいいので「createThumbnail」フォルダを作成して、配下で「npm install async gm」を実行して、asyncとgmモジュールをダウンロードし展開します。
C:\>mkdir createThumbnail C:\>cd createThumbnail C:\createThumbnail>npm install async gm gm@1.23.0 node_modules\gm ├── array-parallel@0.1.3 ├── array-series@0.1.5 ├── debug@2.2.0 (ms@0.7.1) └── cross-spawn@4.0.2 (lru-cache@4.0.1, which@1.2.12) async@2.1.4 node_modules\async └── lodash@4.17.2
「createThumbnail」フォルダ内に「index.js」というファイル名で以下のプログラムを貼り付けます。
「createThumbail.js」という風にAWSのマニュアルは書いてありますが、Lambdaファンクションを作成する際のハンドラのデフォルト値が「index.handler」なのでこれとファイル名がマッチする必要があります。マッチしない場合は以下のようにLambdaファンクション実行した際にエラーになります。
{ "errorMessage": "Cannot find module '/var/task/index'", "errorType": "Error", "stackTrace": [ "Function.Module._load (module.js:276:25)", "Module.require (module.js:353:17)", "require (internal/module.js:12:17)" ] }
コード(index.js)
// dependencies var async = require('async'); var AWS = require('aws-sdk'); var gm = require('gm') .subClass({ imageMagick: true }); // Enable ImageMagick integration. var util = require('util'); // constants var MAX_WIDTH = 100; var MAX_HEIGHT = 100; // get reference to S3 client var s3 = new AWS.S3(); exports.handler = function(event, context, callback) { // Read options from the event. console.log("Reading options from event:\n", util.inspect(event, {depth: 5})); var srcBucket = event.Records[0].s3.bucket.name; // Object key may have spaces or unicode non-ASCII characters. var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " ")); var dstBucket = srcBucket + "-resize"; var dstKey = "resized-" + srcKey; //★ // Sanity check: validate that source and destination are different buckets. if (srcBucket == dstBucket) { callback("Source and destination buckets are the same."); return; } // Infer the image type. var typeMatch = srcKey.match(/\.([^.]*)$/); if (!typeMatch) { callback("Could not determine the image type."); return; } var imageType = typeMatch[1]; if (imageType != "jpg" && imageType != "png") { callback('Unsupported image type: ${imageType}'); return; } // Download the image from S3, transform, and upload to a different S3 bucket. async.waterfall([ function download(next) { // Download the image from S3 into a buffer. s3.getObject({ Bucket: srcBucket, Key: srcKey }, next); }, function transform(response, next) { gm(response.Body).size(function(err, size) { // Infer the scaling factor to avoid stretching the image unnaturally. var scalingFactor = Math.min( MAX_WIDTH / size.width, MAX_HEIGHT / size.height ); var width = scalingFactor * size.width; var height = scalingFactor * size.height; // Transform the image buffer in memory. this.resize(width, height) .toBuffer(imageType, function(err, buffer) { if (err) { next(err); } else { next(null, response.ContentType, buffer); } }); }); }, function upload(contentType, data, next) { // Stream the transformed image to a different S3 bucket. s3.putObject({ Bucket: dstBucket, Key: dstKey, Body: data, ContentType: contentType }, next); } ], function (err) { if (err) { console.error( 'Unable to resize ' + srcBucket + '/' + srcKey + ' and upload to ' + dstBucket + '/' + dstKey + ' due to an error: ' + err ); } else { console.log( 'Successfully resized ' + srcBucket + '/' + srcKey + ' and uploaded to ' + dstBucket + '/' + dstKey ); } callback(null, "message"); } ); };
Step 2.1: Create a Deployment Package - AWS Lambdaのコードになりますが一部、バケット名などを個別に指定するために変更しています。★の部分。
ファイルの圧縮
index.jsとnode_modulesのフォルダをzipで圧縮します。
http://aws-mobile-development.hatenablog.com/AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (2) AWSコンソールでの作業 - AWS Mobile Application Development へ続きます。
AsyncTaskで取得してきたデータをアクティビティに引き渡す方法
stackoverlowで良いサンプルがあったのですメモ。Activity外の外出個別クラスから、Activityクラスへデータを返す方法を探してたら、データを、返すんではなく外出しクラスへActivityを受け渡すやり方。
つまり、件名とはやってることは違いますが最終的やりたいことは同じ。
Asynctask側のコンストラクタにActivity自体を渡してます。それでAsynctask側のメソッドでActivity側のメンバlistをAsynctask側から更新する。
一般的なgetやAWS S3とかDynamodbのデータをAsynctaskでとってきたあと、Activityに結果を、反映する用途で使えますね。
・YourActivity.java
public class YourActivity extends Activity { private List<String> list = new ArrayList<String>(); public void onCreate(Bundle state) { //... } public void setList(List<String> list) { this.list = list; } private void fireYourAsyncTask() { new LoadStringsAsync(this).execute(); } }
・LoadStringsAsync.java
public class LoadStringsAsync extends AsyncTask<Void, Void, List<String>> { List<String> str; private YourAcitivity activity; public LoadStringsAsync(YourAcitivity activity) { this.activity = activity; } @Override protected List<String> doInBackground(Void... arg0) { } @Override protected void onPostExecute(List<String> str) { super.onPostExecute(events); activity.setList(str); } }
android - AsyncTask return List to Activity - Stack Overflow
AndroidとDynamoDB実装方法 (4/4) - コーディング -
AWSのNoSQLデータベースDynamoDBをDBとしてデータ操作を行うための基本的な設定のご紹介です。
AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -に続き、プログラミングになります。
MainActivity.javaと、DynamoDBのテーブルクラスを定義したBooks.javaの2ファイルからの構成となるプログラミングを行います。
[目次]
コード
Books.java
package com.example.sample.dynamodb_sample; import com.amazonaws.auth.CognitoCachingCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.dynamodbv2.*; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*; /* Dynammoテーブル名*/ @DynamoDBTable(tableName = "Books") public class Books { private String author; private String title; private int price; private String releasedate; /* パーティションキーで指定した属性名 */ @DynamoDBHashKey(attributeName = "Author") public String getAuthor() {return author; } public void setAuthor(String author) { this.author = author; } /* ソートキーで指定した属性名 */ @DynamoDBRangeKey(attributeName = "Title") public String getTitle() {return title; } public void setTitle(String title) { this.title = title; } /* 任意の属性名 AWSコンソールで事前定義不要*/ @DynamoDBAttribute(attributeName = "Price") public int getPrice() {return price; } public void setPrice(Integer price) { this.price = price; } /* 任意の属性名 AWSコンソールで事前定義不要*/ @DynamoDBAttribute(attributeName = "Releasedate") public String getReleasedate() {return releasedate; } public void setReleasedate(String releasedate) { this.releasedate = releasedate; } }
プログラム内で記載している以下はAWSコンソールで事前定義をしたDynamoDBのマッピング定義で必ず定義が必要なアノテーションです。
@DynamoDBTable(tableName = "Books")
@DynamoDBHashKey(attributeName = "Author")
@DynamoDBRangeKey(attributeName = "Title")
以下は、AWSコンソールで事前定義をしたものではなく、本アプリで使用し得る属性名として定義しているアノテーションです。
@DynamoDBAttribute(attributeName = "Price")
@DynamoDBAttribute(attributeName = "Releasedate")
他にも色々とアノテーションを定義するルールが以下に記載されています。
docs.aws.amazon.com
MainActivity.java
package com.example.sample.dynamodb_sample; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import com.amazonaws.auth.CognitoCachingCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.regions.Region; import com.amazonaws.services.dynamodbv2.*; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*; import java.util.Date; public class MainActivity extends AppCompatActivity { private Books book; private Runnable runnable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // (1) Cognitoで出力した認証定義です CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider( getApplicationContext(), "ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxxxxx ", // Identity Pool ID Regions.AP_NORTHEAST_1 // Region ); // (2) DynamoDBのクライアントセッションを作成します AmazonDynamoDBClient ddbClient = new AmazonDynamoDBClient(credentialsProvider); // (3) デフォルトではUS-EASTがリージョンで指定されてしまうため意図的にAP_NORTHEASTにしています Region apNortheast1 = Region.getRegion(Regions.AP_NORTHEAST_1); ddbClient.setRegion(apNortheast1); // (4) マッパーのインスタンス作成 final DynamoDBMapper mapper = new DynamoDBMapper(ddbClient); // (5) インターネットのアクセスを行うためにスレッドを作成し、その中でインサート処理を定義します runnable = new Runnable() { public void run() { Books book = new Books(); book.setAuthor("Charles Dickens"); book.setTitle("Great Expectations"); book.setPrice(20000); Date date = new Date(); book.setReleasedate(date.toString()); mapper.save(book); }; }; Thread mythread = new Thread(runnable); mythread.start(); } }
コード解説
(1) AWSの認証
AndroidとDynamoDB実装方法 (2) - Cognito初期設定 - - AWS Mobile Application Developmentで取得した「Get AWS Credentials」を定義して認証処理を行います。
(2) DynamoDBのクライアントセッション作成
(1)でDynamoDB用のクライアントセッションを作成します。
(3) リージョンの指定
デフォルトではUS-EASTがリージョンで指定されてしまうため、これを設定しないと以下のエラーが発生します。その為、意図的にAP_NORTHEASTにしています。
E/AndroidRuntime: FATAL EXCEPTION: Thread-9 Process: com.example.sample.dynamodb_sample, PID: 2269 com.amazonaws.AmazonServiceException: User: arn:aws:sts::xxxxxxxxxxxxx:assumed-role/Cognito_DynamoTestUnauth_Role/CognitoIdentityCredentials is not authorized to perform: dynamodb:UpdateItem on resource: arn:aws:dynamodb:us-east-1:xxxxxxxxxxxxxx:table/Books (Service: AmazonDynamoDB; Status Code: 400; Error Code: AccessDeniedException; Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)
(5) 別スレッドでDB処理を行う
Androidではインターネット処理をメインスレッド(UIスレッド)で行ってはいけません。ワーカスレッドを作成しそれ上で処理を行う必要があります。これを行わなかった場合以下のエラーが発生します。
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.sample.dynamodb_sample, PID: 3056 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sample.dynamodb_sample/com.example.sample.dynamodb_sample.MainActivity}: android.os.NetworkOnMainThreadException
Mainスレッドとは別でインターネットの処理し結果をメインスレッドへコールバックをすることがAndroidの基本です。実現方法法として、「Runnable」と「AsyncTask」がありますので「Runnable」は上記に書いていますので「AsyncTask」実装例を以下に記載します。
package com.example.sample.dynamodb_sample; import android.os.AsyncTask; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; import com.amazonaws.auth.CognitoCachingCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.regions.Region; import com.amazonaws.services.dynamodbv2.*; import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*; import java.util.Date; public class MainActivity extends AppCompatActivity { private CognitoCachingCredentialsProvider credentialsProvider; private static final String TAG = MainActivity.class.getSimpleName(); private Books book; private DynamoDBMapper mapper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // (1) Cognitoで出力した認証定義です CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider( getApplicationContext(), "ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxx", // Identity Pool ID Regions.AP_NORTHEAST_1 // Region ); // (2) DynamoDBのクライアントセッションを作成します AmazonDynamoDBClient ddbClient = new AmazonDynamoDBClient(credentialsProvider); // (3) デフォルトではUS-EASTがリージョンで指定されてしまうため意図的にAP_NORTHEASTにしています Region apNortheast1 = Region.getRegion(Regions.AP_NORTHEAST_1); ddbClient.setRegion(apNortheast1); // (4) マッパーのインスタンス作成 mapper = new DynamoDBMapper(ddbClient); new db().execute(""); } //AsyncTask<Params, Progress, Result> private class db extends AsyncTask<String, Integer, String> { /** doInBackgroundメソッドの実行前にメインスレッドで実行されます。 非同期処理前に何か処理を行いたい場合に使用。 */ @Override protected void onPreExecute() { Log.i(TAG,"onPreExecuted ...."); } /** メインスレッドとは別のスレッドで実行されます。 非同期で処理したい内容を記述します。記載必須。 */ @Override protected String doInBackground(String... params) { Log.i(TAG,"doInBackground ...."); Books book = new Books(); int i = 0; for(i = 0; i < 20; i++){ try { Thread.sleep(1500); book.setAuthor("村上春樹"); book.setTitle("1Q24" + "第" + i + "版"); book.setPrice(20000); Date date = new Date(); book.setReleasedate(date.toString()); mapper.save(book); publishProgress(i); }catch(InterruptedException e){ Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT).show(); } } /* onPostExecute(String s) の s に "Executed" が入ります */ return "Executed"; } /**メインスレッドで実行されます。 非同期処理の進行状況をプログレスバーで 表示したい時などに使うことができます。 */ @Override protected void onProgressUpdate(Integer... values) { Log.i(TAG,"onProgressUpdate .... " + values[0]); } /**doInBackgroundメソッドの実行後にメインスレッドで実行されます。 doInBackgroundメソッドの戻り値をこのメソッドの引数として受け取り、 その結果を画面に反映させることができます。 */ @Override protected void onPostExecute(String s) { Log.i(TAG,"onPostExecute ....return value is " + s); } } }
[参考]
関連記事
AndroidとDynamoDB実装方法 (1/4) - AWS SDKの準備 -
AndroidとDynamoDB実装方法 (2/4) - Cognito初期設定 -
AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -
AndroidとDynamoDB実装方法 (4/4) - プログラミング -
参考
- AWS DynamoDBへサンプルデータを投入しクエリーを出す(Java) | infoScoop開発者ブログ
- AWS DynamoDBの項目の取得(Java) | infoScoop開発者ブログ
- amazon web services - "the provided key element does not match the schema" in the sample from AWS Android SDK - Stack Overflow
- 【AWS】今更ながらDynamoDB入門 - Qiita
- Store and Query App Data in DynamoDB — Android Developer Guide
- DynamoDB 用の Java 注釈 - Amazon DynamoDB
- Store and Retrieve App Data in Amazon DynamoDB — Android Developer Guide
- Step 1: Create Example Tables - Amazon DynamoDB
- AsyncTaskを使った非同期処理のきほん | Developers.IO
AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -
AWSのNoSQLデータベースDynamoDBをDBとしてデータ操作を行うための基本的な設定のご紹介です。
AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -に続き、AWS DynamoDBの設定を行います。
[目次]
設定の前にまずDynamoDBについて基本から抑えておき、設定まで進みます。
DynamoDBの基本
まずDynamoDBの基本ですが、DynamoDBはNoSQL型のデータベースで以下で詳細に紹介されていますが、かいつまんで構造に関する部分のみ列挙します。
データの特徴
name/value型でjsonのようなデータの構造になっている
DynamoDB設定手順
DynamoDBのテーブル作成
DynamoDBでサンプルのテーブル「Books」を作ってみます。AWSコンソールにログインしてDynamoDBを選択します。
続いて、「Create Table」をクリックします。
「Table name」、「Primary key」を入力後、「add sort key」をクリックし以下の通り入力します。その後「Create」をクリックしテーブルを作成します。
この「Primary key(ハッシュプライマリキー)」はRDBでいう、そのままですがプライマリキーで、「Sort Key」というのがテーブルに1つだけ設定できるデータをソートするための列です。DynamoDBではこのソートキーでしたソートができません。
作成後、詳細が表示されるますが次のステップではこのテーブルへの権限設定をするため、「Amazon Resource Name (ARN)」の文字列にてこのテーブルを指定するためテキストとしてコピーしておきます。
IAMでのポリシー作成
AWSコンソールにログインして「Identity & Access Management」を選択します。左側のメニューのロールを選択します。前ステップで作成したDyanmoDBテーブル名が含まれたエントリが2つありますので、「Unauth」の文字列がある方をクリックします。
表示される画面の中で以下の「Create Role Policy」を選択します。
「Policy Generator」を選択した状態で「Select」を選択します。
以下の設定を行います。前ステップで作成したARN(DyanmoDBの作成したテーブル)へフルアクセスを可能とするポリシーという意味になります。「Add Statement」をクリックし、「Next Step」をクリックします。
生成されるjson形式のポリシーが表示されますので「Apply Policy」をクリックして終了します。
以上で、Cognito経由でDynamoDBへアクセスするための権限設定が完了です。
続いてプログラミングです。
【Android基礎】BitbucketとAndroid Studioの連携設定
Android Studioで作ったプログラムを管理するリポジトリとして、リポジトリをクローズドな形で管理できるBitbucketとの連携手順です。
[目次]
事前作業
Bitbucketのアカウント登録
bitbucket.org
こちらよりアカウント登録を行います。登録だけだと無料です。
Android Studioインストール
developer.android.com
こちらより事前にインストールをしておきます。
連携設定
Android Studioのメニュー > VCS > Enable Version Control Integration... を選択
Gitを選択
Android Studioに戻って「Vesion Control」の箇所で、「Unversioned」を右リックから「Git」> 「Add」を選択。
「Vesion Control」の箇所で、「Unversioned」を右リックから「Git」> 「Commit Files」を選択。
Commit Messageに何か記載して、「Commit」をクリック。
「Commit」をクリック。
Bitbucketから先ほどの作成したレポジトリのURLを取ってきて、貼り付け「OK」をクリック。
「Push」をクリック
Bitbucketのソース部分にアップロードされていることが確認できます。
ご参考
【Android基礎】 外部のクラスファイルが利用できない時の対処法
MainActivity.javaと同じディレクトリのHello.javaというクラスファイルを定義してそれをMainActivity.javaから読もうとすると、「Unknown Class」、「Invalid Method declaration」、「return type required」と表示されたりする。
あくまで一例ですが、原因のその一つにメソッドやコンストラクタ以外のところで、プログラムを書いている可能性があります。
例えば、以下のような独自のクラスがあるとして、
Hello.java
package com.example.azwoo.test; public class Hello { public String love; public String death; public void setLove(String love){ this.love = love; } public void setDeath(String death){ this.death = death; } }
ちゃんとonCreateメソッド(例)内でインスタンスを作成していればエラーは起きませんが、
MainActivity.java
package com.example.azwoo.test; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private Hello hello; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); hello = new Hello(); hello.setLove("I love you"); hello.setDeath("I love you"); Log.e("test","love = " + hello.love); Log.e("test","death = " + hello.death); } }
こんな感じでメソッドでもなくコンストラクタでもないところで書いているとエラーになります。
MainActivity.java
package com.example.azwoo.test; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { private Hello hello; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } hello = new Hello(); hello.setLove("I love you"); hello.setDeath("I love you"); Log.e("test","love = " + hello.love); Log.e("test","death = " + hello.death); }