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

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

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

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

Android Studio

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

Q&A

解決済

1回答

1746閲覧

TextViewのsetTextで起こるエラー(メソッドでActivityをいじるのはよくないのか)

iruma

総合スコア11

Java

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

Android Studio

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

0グッド

0クリップ

投稿2021/07/03 13:26

編集2021/07/03 14:36

前提・実現したいこと

TextViewに取得したBluetoothDeviceの名前を表示させたいです
サブクラスでデバイスを取得してデバイス名をメインクラスで表示させようとしています

アクティビティをセットしてあるクラスです
メソッドでいじるのはよくないのでしょうか?

発生している問題・エラーメッセージ

E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.esp32ble, PID: 29278 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference at com.example.esp32ble.MainActivity.setTextName(MainActivity.java:174) at com.example.esp32ble.SubsidyBle.scanAndConnect(SubsidyBle.java:121) at com.example.esp32ble.MainActivity.chartChange(MainActivity.java:160) at com.example.esp32ble.-$$Lambda$TW4Z-_TbHlSaQ3_9pMVQ_fCEm0w.onClick(Unknown Source:2) at android.view.View.performClick(View.java:7217) at android.view.View.performClickInternal(View.java:7191) at android.view.View.access$3500(View.java:828) at android.view.View$PerformClick.run(View.java:27679) at android.os.Handler.handleCallback(Handler.java:900) at android.os.Handler.dispatchMessage(Handler.java:103) at android.os.Looper.loop(Looper.java:219) at android.app.ActivityThread.main(ActivityThread.java:8349) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

該当のソースコード

java

1public class MainActivity extends AppCompatActivity implements MenuItem.OnMenuItemClickListener { 2 3 private int i = 0; 4 private LineChart chart; 5 private boolean connectState = false; 6 private Button changeButton; 7 private TextView nameText; 8 private final String NOW_CONNECT = "接続を終了"; 9 private final String NOW_DISCONNECT = "接続を開始"; 10 11 private BluetoothManager bluetoothManager; 12 private BluetoothAdapter bluetoothAdapter; 13 private final int duration = Toast.LENGTH_SHORT; 14 private SubsidyBle subBle; 15 16 private BtDialogFragment dialog; 17 private Intent intent; 18 19 @Override 20 protected void onCreate(Bundle savedInstanceState) { 21 super.onCreate(savedInstanceState); 22 setContentView(R.layout.activity_main); 23 24 Toolbar Toolbar = findViewById(R.id.main_toolbar); 25 setSupportActionBar(Toolbar); 26 27 changeButton = findViewById(R.id.chart_change); 28 changeButton.setOnClickListener(this::chartChange); 29 nameText = findViewById(R.id.device_name_text); 30 31 lineChart(); 32 intent = new Intent(); 33 subBle = new SubsidyBle(); 34 35 //BLEの設定 36 if( !getPackageManager().hasSystemFeature( PackageManager.FEATURE_BLUETOOTH_LE ) ) { 37 Log.d("BtActivity","Bluetooth is not supported"); 38 finish(); // アプリ終了宣言 39 return; 40 } 41 // Bluetoothアダプタの取得 42 bluetoothManager = (BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE); 43 bluetoothAdapter = bluetoothManager.getAdapter(); 44 if( null == bluetoothAdapter ) { 45 // Android端末がBluetoothをサポートしていない 46 Log.d("BtActivity","Bluetooth is not supported"); 47 finish(); // アプリ終了宣言 48 return; 49 } 50 bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 51 52 dialog = new BtDialogFragment(); 53 dialog.show(getSupportFragmentManager(),"my_dialog"); 54 } 55 56~~~~~~~~~~~~~~~ 57 58 //subClassで検出したデバイスの名前を受け取って表示 59 public void setTextName(String deviceName){ 60 Log.d("kiteru?",deviceName); 61 nameText.setText(deviceName); 62 }

java

1private MainActivity m = new MainActivity(); 2 3//ペアデバイスを取得してサーバーに接続する 4 public void scanAndConnect(Context context,BluetoothAdapter bluetoothAdapter){ 5 pairedDevices = bluetoothAdapter.getBondedDevices(); 6 if (pairedDevices.size() > 0) { 7 for (BluetoothDevice device : pairedDevices) { 8 Log.d("pairedDevice","Name:"+device.getName()+"Address:"+device.getAddress()); 9 Toast.makeText(context,"接続を開始します",Toast.LENGTH_SHORT).show(); 10 device = bluetoothAdapter.getRemoteDevice(device.getAddress()); 11 bluetoothGatt = device.connectGatt(context, false, bluetoothGattCallback); 12 m.setTextName("" + device.getName()); 13 } 14 } 15 if (bluetoothGatt == null) { 16 Toast.makeText(context, "ペアリングされたデバイスが存在しません", Toast.LENGTH_SHORT).show(); 17 } 18 Toast.makeText(context,"Bluetooth通信に異常が発生しています",Toast.LENGTH_LONG).show(); 19 }

試したこと

onCreateにfindViewByIdを書いてみた

補足情報(FW/ツールのバージョンなど)

Log.dで取得した文字列は確認できる
ViewのIdはあってる

android studio
java

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

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

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

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

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

jimbe

2021/07/03 13:52

>onCreateにfindViewByIdを書いてみた どのように考えられてその試験をし、どのように「書いてみた」のでしょうか。その結果何が起き、何が分かったのでしょう。
iruma

2021/07/03 13:57

もしかしたら、メソッドに書いているのが間違ってるのではないのかと思ったからです。 今試したところ、その検証はあっていました ただ、今回の本題のsetTextでエラーが発生します
jimbe

2021/07/03 14:07

onCreate に nameText = findViewById(R.id.device_name_text); を移動した形にされたのですね。 それで「その検証はあっていました」と言われるのは、移動により例外は無くなって想定通りの動作をしたということでしょうか。 そして、移動したら動作した(=移動しないと動作しない)のは何故か?というご質問ということで宜しいですか?
iruma

2021/07/03 14:16

おっしゃる通り例外が発生しなくなったということです。 しかし、今回の質問内容としてはfindViewByIdを記述する場所ではなく、setTextでエラーがどうして発生するのかについて知りたいです。お願いします。
jimbe

2021/07/03 14:28

例外が発生しなくなった・・・とのことですが、「発生している問題・エラーメッセージ」を更新されて(更新前とは少し違いますが) NullPointerException 例外が発生しているように見受けられますけども・・・どういうことでしょう? 回答ぽくなりますが、 > findViewById を記述する場所ではなく、setTextでエラーがどうして発生するのか という点に置きましては、各メソッドは個別に存在・動作するわけではなく、それぞれが内部で複雑に関係しているから…となります。実際にどう関係してエラーとなるのかは、細かく言えば状況によりますし、ざっくり言えば各メソッドの仕様・使い方通りに使えていないから…となります。 ちなみに、 SubsidyBle クラスの scanAndConnect メソッドからどのように setTextName を呼び出しているのか、scanAndConnect メソッドをご提示願えますか?
iruma

2021/07/03 14:37

返信に不備があり申し訳ありません。 正しくは、また別のエラーが発生したということになります サブクラスのコードを追加しました。よろしくお願いします
jimbe

2021/07/03 15:00

ありがとうございます。
guest

回答1

0

ベストアンサー

本件の一連の例外の原因は、SubsidyBle クラス内 scanAndConnect メソッドで行われている

m.setTextName("" + device.getName());

の m が、同じく SubsidyBle クラス内で

private MainActivity m = new MainActivity();

として宣言・生成されている為と思われます。

よくある勘違いですが、アプリを実行した時にシステムによって生成・表示された MainActivity オブジェクトと、この SubsidyBle クラス内で new MainActivity() として生成された MainActivity オブジェクトは「同じ構造の別のモノ」です。
そして、システムによって生成・表示された方の MainActivity オブジェクトにはシステムによって様々な設定が行われ、例えば findViewById によって View が取得できるようになっていますが、new MainActivity() として生成された MainActivity オブジェクトには設定が行われておらず、findViewById の内部で例外が発生します。

setTextName メソッド内に findViewById を書いていた時はその例外が発生しており、また findViewById を onCreate に移動した際には SubsidyBle クラス内で new MainActivity() しても onCreate は呼ばれない為、private TextView nameText が null のままとなっていて setText で例外が発生していると考えられます。

この対応としてましては、 SubsidyBle の生成時に MainActivity をコンストラクタのパラメータとして受け取り、 m に代入しておくのが簡単かと思います。

java

1class SubsidyBle { 2 private MainActivity m; 3 public SubsidyBle(MainActivity main) { 4 m = main; 5 } 6 : 7}

投稿2021/07/03 14:59

編集2021/07/03 15:07
jimbe

総合スコア12672

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

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

iruma

2021/07/03 15:17

ありがとうございます。 エラーを修正することができました!
iruma

2021/07/03 15:25

以前までは、MainActivityという構造のMainActivityとは別のものが生成されていて、それを編集しようとしていたからエラーが発生していた。なので、サブクラスのコンストラクタで生成済みのMainActivityを取得することで生成されたものに対して編集することができるようになった、という認識で問題ないでしょうか。
jimbe

2021/07/03 15:31

問題無いかと思います。 そうなれば、findViewById を元のように setTextName 内で行っても動作するのではないでしょうか。 もっとも、findViewById の結果のように「一度取得すれば変わることが無い」ようなものは、 onCreate で行ったほうが良いようには思いますが ^^;
jimbe

2021/07/03 15:44

失礼、ご質問とは関係ない蛇足になりますが、このような具体的なコードに対してのお話の場合、「サブクラス」「メインクラス」というキーワードでは(特に初見時は)分かり難くなりますので、具体的なクラス名を書かれたほうが良いですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問