質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

3回答

3348閲覧

変数が【NullPointerException】。その対処方法に関して

mamonPro

総合スコア38

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

1クリップ

投稿2017/12/06 00:54

現在、とある機器からデータをMain Activityの配列で取得して
それをNextActivityにIntentで流して、
それとはさらにChartActivityにてCanvasとPaintを使って
グラフを描こうとしています。

ChartActivityは横向き(landscape)表示でx,y,z値の3本を表示させます。

ここで、TextViewを使って都度可変するグラフの目盛の表示を変えて
併せて表示したいのですが、普通にCanvasとPaintにTextViewを乗せると
エラーで終了してしまいます。(CanvasとPaintでのグラフのみの描画は成功しています)

そこでこちらの情報をもとに
TestViewクラスを作成しレイアウトにタグを追加してみたのですが
MainActivityやIntentでNextActivityに流したデータが
【NullPointerException】で取得が出来ずNextActivityに切り替えると強制終了してしまいます。

###やってみたこと:
MainActivityをNewして変数を取りに行ってみましたが
宣言している段階で代入されていれば、それはNullPointerExceptionになりません(当然ですが)
グローバル変数にして、やってみましたが同じ状態です。

どのように対応すれば、CanvasとPaintにTextViewを乗せることができるでしょうか。
よろしくお願いします。

Java

1MainActivity 2 3public class MainActivity extends AppCompatActivity { 4 5 int data1[] ; //これだとNullPointerException 6 int data2[] ={55,60,100}; //エラーにならない 7 common Common; //グローバル変数 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 setContentView(R.layout.activity_main); 12 } 13 public void onNext(View view){ 14 Intent intent = new Intent(this,NextActivity.class); 15 16 data1 = new int [3]; 17 data1[0]=55; 18 data1[1]=60; 19 data1[2]=100; 20 intent.putExtra("data",data1); 21 startActivity(intent); 22 } 23}

Java

1NextActivity 2 3public class NextActivity extends AppCompatActivity { 4 5 Intent intent =getIntent(); 6 private TextView label; 7 private TestView testView; 8 public int data[] = intent.getIntArrayExtra("data"); 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_next); 14 15 label = (TextView) this.findViewById(R.id.label); 16 label.setText("abcd123456789cdefg\n" + "1234567893456978\n" + 17 "hijklmnopq012698745rst4565848uvwxlmnopq\n" + 18 "\n\n\n012698745rst4565848\nuvwx" ); 19 20 testView = (TestView) this.findViewById(R.id.test_view); 21 22 } 23}

Java

1TestView.java 2 3public class TestView extends View { 4 Paint paint; 5 MainActivity ma = new MainActivity(); 6 7 public TestView(Context context, AttributeSet attrs) { 8 super(context, attrs); 9 paint = new Paint(); 10 } 11 12 @Override 13 protected void onDraw(Canvas canvas) { 14 15 // 背景、半透明 16 canvas.drawColor(Color.argb(125, 0, 0, 255)); 17 18 // 円 19 paint.setColor(Color.argb(255, 68, 125, 255)); 20 paint.setStrokeWidth(30); 21 paint.setAntiAlias(true); 22 paint.setStyle(Paint.Style.STROKE); 23 // (x1,y1,r,paint) 中心x1座標, 中心y1座標, r半径 24 canvas.drawCircle(450, 450, 100, paint); 25 26 // 矩形 27 paint.setColor(Color.argb(255, 255, 0, 255)); 28 paint.setStrokeWidth(10); 29 paint.setStyle(Paint.Style.STROKE); 30 // (x1,y1,x2,y2,paint) 左上の座標(x1,y1), 右下の座標(x2,y2) 31 canvas.drawRect(480, 480, 850, 880, paint); 32 33 // 線 34 paint.setStrokeWidth(15); 35 paint.setColor(Color.argb(255, 0, 255, 120)); 36 // (x1,y1,x2,y2,paint) 始点の座標(x1,y1), 終点の座標(x2,y2) 37 canvas.drawLine(350, 850, 750, 630, paint); 38 39 // 線 40 paint.setStrokeWidth(15); 41 paint.setColor(Color.argb(255, 0, 255, 120)); 42 // (x1,y1,x2,y2,paint) 始点の座標(x1,y1), 終点の座標(x2,y2) 43 canvas.drawLine(ma.data1[0], ma.data1[1], ma.data1[2], 630, paint); //ここがエラー 44 45 } 46} 47

エラーメッセージ(activity_next.xml):
java.lang.NullPointerException
at com.example.zd2565.testchart20171204_2.TestView.onDraw_Original(TestView.java:53)
at com.example.zd2565.testchart20171204_2.TestView.onDraw(TestView.java)
at android.view.View.draw(View.java:17071)
at android.view.View.draw(View.java:16979)
at android.view.ViewGroup.drawChild_Original(ViewGroup.java:3764)
at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:61)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.draw(View.java:16977)
at android.view.ViewGroup.drawChild_Original(ViewGroup.java:3764)
at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:61)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.draw(View.java:16977)
at android.view.ViewGroup.drawChild_Original(ViewGroup.java:3764)
at android.view.ViewGroup_Delegate.drawChild(ViewGroup_Delegate.java:61)
at android.view.ViewGroup.drawChild(ViewGroup.java:3764)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3550)
at android.view.View.draw(View.java:17074)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:401)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.renderAndBuildResult(RenderSessionImpl.java:539)
at com.android.layoutlib.bridge.impl.RenderSessionImpl.render(RenderSessionImpl.java:422)
at com.android.layoutlib.bridge.BridgeRenderSession.render(BridgeRenderSession.java:104)
at com.android.ide.common.rendering.api.RenderSession.render(RenderSession.java:154)
at com.android.ide.common.rendering.api.RenderSession.render(RenderSession.java:136)
at com.android.tools.idea.rendering.RenderTask.lambda$renderInner$3(RenderTask.java:752)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

まずは結論

設計を変えた方が良いと思います。
TestViewの中にupdateViewのようなメソッドを定義し、その引数にdataを入れて渡してあげます。
ActivityやIntentの扱いに関しては他のお二方のおっしゃる通りですので、そちらを参考になさってください。

問題点

問題はTestViewの中の以下の部分です。

java

1canvas.drawLine(ma.data1[0], ma.data1[1], ma.data1[2], 630, paint); //ここがエラー

基本的に、ViewはActivityがなんであるかを知りません。これはインターフェースを考える上で重要ですね。例えばですが、他のActivityからTestViewをもしも使いたくなった時に、TestViewがMainActivityに依存していると実装をやり直さなければなりません。
そこで、そもそもとしてViewの中に特定のActivityを持たせないのが基本方針になります。
参考url: 疎結合って何?

ソフトウェアの拡張性とは「いかに変更に容易に適応できるかどうか」である。

依存関係が多いと、あるプログラムの変更が他のプログラムに影響を及ぼし、変更を行うごとに大量のテストが必要になる。

具体的な解決策

ではどうすれば良いのでしょうか???
それは、View側にActivityからデータを渡してあげるのです。
ここが重要で、質問者様は「ViewからActivityのデータを取りに行く」コードを書いていますが、「ActivityからViewにデータを渡す」のです。

具体的には、TestViewの中にpublicで以下のようなメソッドを定義します。
TestView

java

1 public void updateView(int[] data) { 2 canvas.drawLine(data[0], data[1], data[2], 630, paint); 3 invalidate(); // これを呼ばないと描画内容が更新されない 4 } 5

そして、これをNextActivityの側から呼び出します。(Intentの受け取りは他の回答の通りに修正し、受け取れているとします。)
参考url: AndroidのViewに絵を描く
NextActivity

java

1 @Override 2 protected void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 setContentView(R.layout.activity_next); 5 6 Intent intent = getIntent(); 7 data = intent.getIntArrayExtra("data"); 8 9 // TestViewのインスタンス取得 10 testView = (TestView) this.findViewById(R.id.test_view); 11 // ここでデータをTestViewに付与する。 12 testView.updateView(data); 13 } 14

おそらく以上の説明だけだと不明な点も多々あると思うので、その都度質問頂ければと思います。

投稿2017/12/06 16:28

編集2017/12/06 16:35
hiramekun

総合スコア428

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mamonPro

2017/12/07 06:16

hiramekunさん ご回答いただきましてありがとうございます。 ご回答いただいた内容につきまして、私にて解釈してみたのですが 【// TestViewのインスタンス取得 testView = (TestView) this.findViewById(R.id.test_view);】 この部分で都度操作したいTestView_Classのインスタンスを取得して、 そのTestView_Classのメソッドに引数で変数を渡して、 Class内の変数に渡す。という解釈であっていますでしょうか。 すみません、つたない質問で大変恐れ入ります。
hiramekun

2017/12/07 13:33

大丈夫です、その解釈で合っていますよ!
mamonPro

2017/12/11 00:11

hiramekunさん ご回答いただきましてありがとうございます。 ご教示いただきました内容にて無事に変数の受け渡しが成功しました。 引数に直接渡していくので、直感的に扱えて大変便利ですね。 貴重な情報ご提供いただきましてありがとうございました。
guest

0

いろいろ不明点は多いですが、現段階で言えることを書きます。
###Activityは自分でnewしてはいけない
ActivityはAndroidのライフサイクルの中で初期化などの処理を行うため、自分でnewしてインスタンス生成するとおかしな挙動になります。
###Activity#getIntentはメソッド内で
上記の理由で、遷移先のActivityでIntentが有効になるのは、Activityの初期化処理が終わった後です。
メンバ変数の宣言の段階ではまだ初期化が完了していないため、getIntentしてもnullが返ってきます。

投稿2017/12/06 01:34

swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mamonPro

2017/12/06 02:28

分かりにくい質問を確認して、ご回答いただきありがとうございます。 2項目のご回答大変参考になりました。
guest

0

ベストアンサー

NextActivity.javaで、dataというフィールドをpublicで宣言していますが、こうしたやり方はあまり良くないとされます。下記のように変数はprivateで宣言し、それを取得するためのメソッドを用意するのがいいでしょう。

NextActivity.java

Java

1public class NextActivity extends AppCompatActivity { 2 3 private TextView label; 4 private TestView testView; 5 private int[] data; 6 7 @Override 8 protected void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState); 10 setContentView(R.layout.activity_next); 11 12 // Intentによるデータ取得はここで行う 13 Intent intent = getIntent(); 14 data = intent.getIntArrayExtra("data"); 15 16 // 中略 17 } 18 19 // dataを取得するためのgetter 20 int[] getData() { 21 return data; 22 } 23 24}

そのメソッドをTestViewから呼び出します。Viewを継承したクラスのコンストラクターの第1引数であるContext型の値は、このViewが描画されたActivity(この場合だとNextActivity)のインスタンスが示されます。これを利用して、NextActivityが持つメソッドを呼び出すことができます。

TestView.java

Java

1public class TestView extends View { 2 3 Paint paint; 4 private Context mContext; 5 6 public TestView(Context context, AttributeSet attrs) { 7 super(context, attrs); 8 paint = new Paint(); 9 mContext = context; // contextを保持しておく 10 } 11 12 @Override 13 protected void onDraw(Canvas canvas) { 14 // NextActivityのメソッドを呼び出す(ここが最重要ポイント) 15 int[] data = ((NextActivity) mContext).getData(); 16 17 // 中略 18 19 // 上記で受け取ったdataを使って描画 20 canvas.drawLine(data[0], data[1], data[2], 630, paint); 21 } 22}

こんな感じで目的を達することができるんじゃないでしょうか?

ただ、質問に記されたTestView.javaでは、MainActivityのインスタンスを作ろうとしていますよね。これは間違った方法ではあるのですが、意図していたのはIntentなどを介して情報をバケツリレーするのではなく、TestViewのコードでMainActivityの情報をダイレクトに参照したかったということなのでしょうか?

投稿2017/12/06 15:06

keicha_hrs

総合スコア6768

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hiramekun

2017/12/06 16:42 編集

Viewに特定のActivityを持たせるのは疎結合の観点から見て拡張性がないと思います。さらにContextをキャストして特定のActivityにしているのはかなり危ない設計だと思いますが、これらの点はいかがでしょうか?
mamonPro

2017/12/07 06:02

keicha_hrsさん 前回に引き続き、ご回答いただきましてありがとうございます。 大変参考になりました。 Contextというのは、いろいろ調べている上で目にしていたのですが ぼんやりとして、理解しきれていませんでした。 しかし、今回ご提供いただいたサンプルの動向がとても分かりやすく、 スッと落ちてきました。 大変感謝いたします!
mamonPro

2017/12/07 06:05

hiramekunさん keicha_hrsさんにコメント頂いた点で、もしご不都合なければ 無知な私に教えてください。 【Contextをキャストして特定のActivityにしているのはかなり危ない設計】というのは 例えば、具体的にどういったリスクが起こりうるのでしょうか。 よろしくお願いいたします。
hiramekun

2017/12/07 13:52 編集

Contextというものは、どのActivityからも取得できるものですね。 そして、TestViewを使いたい!と思ってActivityから呼び出したとします。しかし、もちろん他のActivityからは使えません。最悪でも引数などに特定のActivityを受け取るのなら、使うときに「あれ、このActivityからしか使えないのかな」と気付けるかもしれませんが、いつでもViewが参照しているContextを内部でキャストしてることには気づきにくく、バグの原因になり得ます。(引数で渡すことも疎結合の観点からやめたほうがいいです) おそらく今まで実装してきて特定のActivityでしか使えないViewというものは見たことがないでしょうし、私も見たことがありません。
keicha_hrs

2017/12/07 15:50 編集

これが一般的に行われる手法かと言われると正直そこまでの自信はありません。hiramekunさんのおっしゃる通り、私のやり方には問題がある可能性は高そうです。もう少し調べてはみますが、こうした作り方による資料をすぐに提示することはできそうもありません(見た記憶自体はあるのですが、それ自体が問題作であり、誤ったやり方を学んでしまったということなのかも)。blueHornetさんにおきましては、そのつもりでご覧いただけないかと思います。 (最初もう少し文量あったのですが、あまりに遜り過ぎて逆に不快を招きかねないと思ったので、少し簡素にしました。もし先に読んでいたら申し訳ありません。)
mamonPro

2017/12/08 00:14

hiramekunさん ご回答頂きありがとうございます。 疎結合の観点(オブジェクト指向の考え方)にならってということがよくわかりました。 コーディングをする上では、とても重要なところです。 実際、私はまだそこまでクオリティの高いコーディングはできてませんが 大変貴重なお話ありがとうございました。
mamonPro

2017/12/08 00:17

keicha_hrsさん コメント頂きありがとうございます。 今回keicha_hrsさんに教えて頂いた内容につきましても 私にとっては大変貴重な情報だったと感謝しております。 実際に試して、情報がきっちり受け渡されてきたときは とてもうれしかったです。 1つの方法として、身につけておきたいと思います。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問