回答編集履歴

3

見づらいので改行位置を修正

2017/10/11 06:40

投稿

dodox86
dodox86

スコア9183

test CHANGED
@@ -44,9 +44,7 @@
44
44
 
45
45
  ###ActivityとService間の通信について追記(2017/10/11)
46
46
 
47
- ご質問の問題の中身とコメントの内容を再考してみますと、どうも混乱させてしまったようですので、
47
+ ご質問の問題の中身とコメントの内容を再考してみますと、どうも混乱させてしまったようですので、追記することで整理させていただきたいと思います。※混乱のひとつは私の回答のせいであります。
48
-
49
- 追記することで整理させていただきたいと思います。※混乱のひとつは私の回答のせいであります。
50
48
 
51
49
 
52
50
 
@@ -56,9 +54,7 @@
56
54
 
57
55
 
58
56
 
59
- この点の回答としては、abs123様のものが適切だと考えています。(K-Tomoya様、これはOKですよね?)
57
+ この点の回答としては、abs123様のものが適切だと考えています。(K-Tomoya様、これはOKですよね?)で、次に、私が最初に回答させてもらった件
60
-
61
- で、次に、私が最初に回答させてもらった件
62
58
 
63
59
  > 他のスレッドからTextViewの更新をしている為にエラーが起きています。
64
60
 

2

当初の回答に不足、不適切な事項があったので、追記。

2017/10/11 06:40

投稿

dodox86
dodox86

スコア9183

test CHANGED
@@ -39,3 +39,385 @@
39
39
  問題無いかどうかは、SensorEventListenerが違うスレッドで動作していて、
40
40
 
41
41
  OnSensorChanged()メソッドがそのスレッドで呼ばれているかどうかによります。
42
+
43
+
44
+
45
+ ###ActivityとService間の通信について追記(2017/10/11)
46
+
47
+ ご質問の問題の中身とコメントの内容を再考してみますと、どうも混乱させてしまったようですので、
48
+
49
+ 追記することで整理させていただきたいと思います。※混乱のひとつは私の回答のせいであります。
50
+
51
+
52
+
53
+ 当初の質問で示された以下のエラーに関してですが、
54
+
55
+ > java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View com.example.kimuratomoya.sensor_db_backup.MainActivity.findViewById(int)' on a null object reference
56
+
57
+
58
+
59
+ この点の回答としては、abs123様のものが適切だと考えています。(K-Tomoya様、これはOKですよね?)
60
+
61
+ で、次に、私が最初に回答させてもらった件
62
+
63
+ > 他のスレッドからTextViewの更新をしている為にエラーが起きています。
64
+
65
+ > TextViewは、この場合MainActivityが動作しているUIスレッドで更新する必要があります。
66
+
67
+
68
+
69
+ ですが、これはこれでその通りなのですが、今回はActivityとService間の通信の話になってくるので、ActivityのUIスレッドだけの話では終わらないです。この点、私の回答が拙速であったこと、お詫びします。
70
+
71
+
72
+
73
+ では結局、Activityが持っているTextViewをService側で発生したデータで更新して表示したいと言う要求はどうしたらいいのかと言うと、簡単には「Activityに`BroadcastReceiver`を持たせ、Serivice側からActivityへIntentで通知する。」との方法が適切かと思います。その為のサンプルを示します。Service内で1秒毎にActivityへIntentを送信し、ActivityではそのIntentから取り出した文字列をTextViewに表示するだけのものです。短いので全部載せます。
74
+
75
+
76
+
77
+ 尚、**本サンプルではActivityが停まってもServiceは停まりません**のでご注意ください。
78
+
79
+
80
+
81
+ Activityの、MainActivity.java です。
82
+
83
+ ```Java
84
+
85
+ package examples.products.test24;
86
+
87
+
88
+
89
+ import android.content.BroadcastReceiver;
90
+
91
+ import android.content.Context;
92
+
93
+ import android.content.Intent;
94
+
95
+ import android.content.IntentFilter;
96
+
97
+ import android.support.v7.app.AppCompatActivity;
98
+
99
+ import android.os.Bundle;
100
+
101
+ import android.util.Log;
102
+
103
+ import android.widget.TextView;
104
+
105
+
106
+
107
+ public class MainActivity extends AppCompatActivity {
108
+
109
+
110
+
111
+ private static final String TAG = "Test24.MainActivity";
112
+
113
+
114
+
115
+ private BroadcastReceiver mReceiver = null;
116
+
117
+ private IntentFilter mIntentFilter = null;
118
+
119
+ private TextView mTextView1 = null;
120
+
121
+
122
+
123
+ @Override
124
+
125
+ protected void onCreate(Bundle savedInstanceState) {
126
+
127
+ super.onCreate(savedInstanceState);
128
+
129
+ setContentView(R.layout.activity_main);
130
+
131
+ mTextView1 = (TextView) findViewById(R.id.textview1);
132
+
133
+
134
+
135
+ mReceiver = new BroadcastReceiver() {
136
+
137
+ @Override
138
+
139
+ public void onReceive(Context context, Intent intent) {
140
+
141
+ // このonReceiveでMainServiceからのIntentを受信する。
142
+
143
+ Bundle bundle = intent.getExtras();
144
+
145
+ String message = bundle.getString("message");
146
+
147
+ Log.d(TAG, "Message from MainService: " + message);
148
+
149
+ // TextViewへ文字列をセット
150
+
151
+ mTextView1.setText(message);
152
+
153
+ }
154
+
155
+ };
156
+
157
+
158
+
159
+ // "TEST24_ACTION" Intentフィルターをセット
160
+
161
+ mIntentFilter = new IntentFilter();
162
+
163
+ mIntentFilter.addAction("TEST24_ACTION");
164
+
165
+ registerReceiver(mReceiver, mIntentFilter);
166
+
167
+
168
+
169
+ Intent intent = new Intent(getApplication(), MainService.class);
170
+
171
+ startService(intent);
172
+
173
+
174
+
175
+ // !!!! サンプルの為、MainServiceサービスを停める処理が無いので、注意してください。
176
+
177
+ }
178
+
179
+ }
180
+
181
+ ```
182
+
183
+
184
+
185
+ Serviceの、MainService.javaです。
186
+
187
+ ```Java
188
+
189
+ package examples.products.test24;
190
+
191
+
192
+
193
+ import android.app.Service;
194
+
195
+ import android.content.Intent;
196
+
197
+ import android.os.IBinder;
198
+
199
+ import android.util.Log;
200
+
201
+
202
+
203
+ import java.util.Timer;
204
+
205
+ import java.util.TimerTask;
206
+
207
+
208
+
209
+ public class MainService extends Service {
210
+
211
+ private static final String TAG = "Test24.MainService";
212
+
213
+ private Timer mTimer = null;
214
+
215
+ private int mCount = 0;
216
+
217
+
218
+
219
+ @Override
220
+
221
+ public void onCreate() {
222
+
223
+ super.onCreate();
224
+
225
+ }
226
+
227
+
228
+
229
+ @Override
230
+
231
+ public int onStartCommand(Intent intent, int flags, int startId) {
232
+
233
+ Log.d(TAG, "onStartCommand():");
234
+
235
+ mTimer = new Timer();
236
+
237
+ mTimer.schedule(new TimerTask() {
238
+
239
+ @Override
240
+
241
+ public void run() {
242
+
243
+ mCount++;
244
+
245
+
246
+
247
+ // MainActivityへデータを送信
248
+
249
+ String message = String.format("count=%d", mCount);
250
+
251
+ sendBroadcast(message);
252
+
253
+ }
254
+
255
+ }, 0, 1000);
256
+
257
+
258
+
259
+ return super.onStartCommand(intent, flags, startId);
260
+
261
+ }
262
+
263
+
264
+
265
+ @Override
266
+
267
+ public void onDestroy() {
268
+
269
+ super.onDestroy();
270
+
271
+ Log.d(TAG, "onDestroy():");
272
+
273
+ // タイマーを停止
274
+
275
+ if (mTimer != null) {
276
+
277
+ mTimer.cancel();
278
+
279
+ mTimer = null;
280
+
281
+ }
282
+
283
+ }
284
+
285
+
286
+
287
+ @Override
288
+
289
+ public IBinder onBind(Intent intent) {
290
+
291
+ Log.d(TAG, "onBind():");
292
+
293
+ return null;
294
+
295
+ }
296
+
297
+
298
+
299
+ private void sendBroadcast(String message) {
300
+
301
+ Log.d(TAG, "sendBroadcast: " + message);
302
+
303
+
304
+
305
+ // IntentをブロードキャストすることでMainActivityへデータを送信
306
+
307
+ Intent intent = new Intent();
308
+
309
+ intent.setAction("TEST24_ACTION");
310
+
311
+ intent.putExtra("message", message);
312
+
313
+ getBaseContext().sendBroadcast(intent);
314
+
315
+ }
316
+
317
+ }
318
+
319
+ ```
320
+
321
+ AndroidManifest.xmlです
322
+
323
+ ```XML
324
+
325
+ <?xml version="1.0" encoding="utf-8"?>
326
+
327
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
328
+
329
+ package="examples.products.test24">
330
+
331
+
332
+
333
+ <application
334
+
335
+ android:allowBackup="true"
336
+
337
+ android:icon="@mipmap/ic_launcher"
338
+
339
+ android:label="@string/app_name"
340
+
341
+ android:roundIcon="@mipmap/ic_launcher_round"
342
+
343
+ android:supportsRtl="true"
344
+
345
+ android:theme="@style/AppTheme">
346
+
347
+ <activity android:name=".MainActivity">
348
+
349
+ <intent-filter>
350
+
351
+ <action android:name="android.intent.action.MAIN" />
352
+
353
+
354
+
355
+ <category android:name="android.intent.category.LAUNCHER" />
356
+
357
+ </intent-filter>
358
+
359
+ </activity>
360
+
361
+
362
+
363
+ <service android:name=".MainService"></service>
364
+
365
+ </application>
366
+
367
+ </manifest>
368
+
369
+ ```
370
+
371
+ レイアウトのlayout/activity_main.xmlです。
372
+
373
+ ```XML
374
+
375
+ <?xml version="1.0" encoding="utf-8"?>
376
+
377
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
378
+
379
+ xmlns:app="http://schemas.android.com/apk/res-auto"
380
+
381
+ xmlns:tools="http://schemas.android.com/tools"
382
+
383
+ android:layout_width="match_parent"
384
+
385
+ android:layout_height="match_parent"
386
+
387
+ android:orientation="vertical"
388
+
389
+ tools:context="examples.products.test24.MainActivity">
390
+
391
+
392
+
393
+ <TextView
394
+
395
+ android:id="@+id/textview1"
396
+
397
+ android:layout_width="wrap_content"
398
+
399
+ android:layout_height="wrap_content"
400
+
401
+ android:text="Text#1"
402
+
403
+ app:layout_constraintBottom_toBottomOf="parent"
404
+
405
+ app:layout_constraintLeft_toLeftOf="parent"
406
+
407
+ app:layout_constraintRight_toRightOf="parent"
408
+
409
+ app:layout_constraintTop_toTopOf="parent" />
410
+
411
+ </LinearLayout>
412
+
413
+ ```
414
+
415
+ UIスレッドではないスレッドからのTextView等のビューの更新についてですが、先の回答で提示させてもらった以下のクラスメソッドの利用
416
+
417
+ - `Handler#post(Runnnable)`
418
+
419
+ - `TextView#post(Runnable)`
420
+
421
+ - `Activity#runOnUiThread(Runnable)`
422
+
423
+ は、これらはActivityで SensorEventListener, LocationListener等を使っていて、イベントがActivityとは違うスレッドで通知される場合に必要になります。今回はServiceでイベントをハンドリングしているので、恐らく問題にはならないと思われます。混乱させてすみません。

1

注意事項を追記

2017/10/11 06:37

投稿

dodox86
dodox86

スコア9183

test CHANGED
@@ -17,3 +17,25 @@
17
17
  Activity#runOnUiThread(Runnable) 等の
18
18
 
19
19
  メソッドを利用して、その中でTextViewを更新することになると思います。
20
+
21
+
22
+
23
+ **※上記、外している可能性があるので追記させていただきます。**
24
+
25
+ ご提示のコードをよく見ると
26
+
27
+ public void onSensorChanged() 内で
28
+
29
+ new Thread(new Runnable() {
30
+
31
+ @Override
32
+
33
+ public void run() {
34
+
35
+ としているので、一見、大丈夫なようにも見えます。
36
+
37
+
38
+
39
+ 問題無いかどうかは、SensorEventListenerが違うスレッドで動作していて、
40
+
41
+ OnSensorChanged()メソッドがそのスレッドで呼ばれているかどうかによります。