さまざまな理由でアプリを正しく動作させることができません。
設計の概要: 私が目指しているのは、2 つのボタン (接続、切断) と、接続から受信したデータを表示するテキストビューを持つアクティビティです。私は WebSocket 接続を処理する "MySocket" サービス (Gottox の Java 実装) を作成しました。このサービスは、tit がサーバーから何かを受け取るたびにアクティビティにメッセージを投稿し、アクティビティはこのデータをテキストビューに追加します。サービスは、アクティビティから接続/切断プロンプトを受信し、アクティビティにメッセージを渡すことができる必要があります。MySocket もフォアグラウンド サービスとして実行する必要があるため、接続が無期限に維持され、ユーザーにはスティッキー通知が提供されます。
私はさまざまな場所でこれに大きな問題を抱えています。最初に、元のアクティビティがまだ更新されている間に、アクティビティの別のインスタンスを開始できることに気付きました。android:launchMode="singleInstance">
マニフェストで指定することでこれを修正しました。私が抱えていた問題は、アクティビティが破棄されて新しいアクティビティが作成されたとき、サービスは更新を投稿し続けましたが、フォーカスされたアクティビティはそれらを受信していませんでした。元のアクティビティが破棄され、サービス ハンドラーが更新されていない場合、アクティビティが破棄されると null ポインター例外がスローされますが、アプリケーションは実行され続けます。unbindService(mConnection)
次に、onDestroy メソッドで実行しようとしましたが、 java.lang.IllegalArgumentException: Service not registered:
The service is messages somethingがスローされました。これは焦点を絞った活動であるべきですが、それを受け取っていないようです。フォアグラウンド サービスの実装が不十分であることが原因だと思われますが、まったく手がかりがありません。
問題の 2 つのクラスは LONG であるため、Logcat 行、グローバル、および無関係であると確信しているいくつかのメソッドを削除しました。アーキテクチャが恐ろしいことはわかっていますが、これは私が機能するのと同じくらい近いです。コードが恐ろしすぎて読むことができない場合は、望ましい結果が得られれば、誰かが別の構造を提案してくれることを嬉しく思います。
活動クラス:
@Override
public void onCreate(Bundle savedInstanceState)
{
...
mMessenger = new Messenger(mHandler);
connect.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
messageSocket("ACTION", "CONNECT");
}
});
@Override
protected void onDestroy()
{
super.onDestroy();
doUnbindService();
}
private ServiceConnection conn = new ServiceConnection()
{
public void onServiceConnected(ComponentName className, IBinder binder)
{
Log.d(debug, "Service Connected");
messenger = new Messenger(binder);
boundToService = true;
}
public void onServiceDisconnected(ComponentName className)
{
Log.d(debug, "Service Disconnected");
messenger = null;
boundToService = false;
}
};
void doBindService()
{
final Intent intent = new Intent(this, MySocket.class);
intent.putExtra("MESSENGER", messenger);
Thread t = new Thread()
{
public void run()
{
boundToService =
getApplicationContext().bindService(
intent,
conn,
Context.BIND_AUTO_CREATE
);
}
};
t.start();
}
そして MySocket クラス:
class IncomingHandler extends Handler
{
@Override
public void onCreate()
{...}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground( id, showNotification() );
connect();
return START_STICKY;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground( id, showNotification() );
connect();
return START_STICKY;
}
private Notification showNotification()
{
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
CharSequence text = "WebSocket currently active";
Notification notification = new Notification(R.drawable.ic_launcher,
text, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, SocketTester.class), 0);
notification.setLatestEventInfo(this, "WebSocket Test", text,
contentIntent);
notification.flags = Notification.FLAG_FOREGROUND_SERVICE;
return notification;
}
@Override
public IBinder onBind(Intent intent)
{
Bundle extras = intent.getExtras();
Log.d(debug, "onBind called");
if (intent.getExtras() != null)
{
Log.d(debug, "Setting messenger");
outMessenger = (Messenger) extras.get("MESSENGER");
}
return inMessenger.getBinder();
}
@Override
public void handleMessage(Message msg)
{
Bundle data = msg.getData();
Message backMsg = Message.obtain();
Bundle bundle = new Bundle();
backMsg.setData(bundle);
if ("CONNECT".equals(data.getString(ACTION)))
{
Log.d(debug, "Connecting");
startService(new Intent(MySocket.this, MySocket.class));
/*startService now calls connect();*/
}
else if ("DISCONNECT".equals(data.getString(ACTION)))
{
if (socket != null)
{
socket.disconnect();
}
stopForeground( true );
stopSelf();
}
}
}