0

さまざまな理由でアプリを正しく動作させることができません。

設計の概要: 私が目指しているのは、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();
        }
    }
}
4

1 に答える 1

-1

「startService(..)を使用してAndroidサービスを開始すると、stopService(..)を明示的に呼び出すまで、そのサービスは実行されたままになります。システムでサービスを実行できる理由は2つあります。誰かがContext.startService()を呼び出した場合次に、システムはサービスを取得し(サービスを作成し、必要に応じてonCreate()メソッドを呼び出します)、クライアントから提供された引数を使用してonStartCommand(Intent、int、int)メソッドを呼び出します。この時点で、サービスは次のように実行され続けます。 Context.stopService()またはstopSelf()が呼び出されます。Context.startService()への複数の呼び出しはネストされないことに注意してください(ただし、onStartCommand()への対応する呼び出しは複数発生します)。 Context.stopService()またはstopSelf()が呼び出されると、サービスは停止します。ただし、サービスはstopSelf(int)メソッドを使用して、開始されたインテントが処理されるまでサービスが停止されないようにすることができます。

クライアントは、Context.bindService()を使用して、サービスへの永続的な接続を取得することもできます。これは、サービスがまだ実行されていない場合(実行中にonCreate()を呼び出す)も同様に作成しますが、onStartCommand()は呼び出しません。クライアントは、サービスがonBind(Intent)メソッドから返すIBinderオブジェクトを受け取り、クライアントがサービスにコールバックできるようにします。接続が確立されている限り(クライアントがサービスのIBinderで参照を保持しているかどうかに関係なく)、サービスは実行され続けます。通常、返されるIBinderは、aidlで記述された複雑なインターフェイス用です。

サービスを開始することも、接続をバインドすることもできます。このような場合、システムは、サービスが開始されているか、Context.BIND_AUTO_CREATEフラグを使用してサービスに接続している限り、サービスを実行し続けます。これらの状況のいずれも成立しない場合、サービスのonDestroy()メソッドが呼び出され、サービスは効果的に終了します。すべてのクリーンアップ(スレッドの停止、レシーバーの登録解除)は、onDestroy()から戻ったときに完了する必要があります。」

これがあなたの仕事を成し遂げるのに役立つことを願っています。

ありがとう :)

于 2012-07-22T18:28:47.613 に答える