0

以前の多くの人と同じように、私は asmack と Openfire を使用してチャット アプリケーションを作成しています。これはまだかなり基本的なものですが、Spark でログインしているユーザーとエミュレーターで別のユーザーとの間でメッセージを送受信することができました。

SO を読んだ後、すべてのアクティビティにバインドする XMPP 接続用のサービスを作成することにしました。現在3つの活動を行っています

  • MainActivity (ユーザーのログインと XMPPconnection への接続)。
  • RosterActivity (ユーザーの連絡先を含むリストビュー)
  • チャット活動

私の質問は2つあります:

  1. すべてのアクティビティを Service にバインドする必要がありますか、それとも MainActivity をそれにバインドして XMPPConnection を extra として渡すことは可能でしょうか? もしそうなら、どのように渡すことができますか?

  2. ログインして RosterActivity を開始したら、onCreate() メソッドでサービスをバインドします。onStart メソッドで、mBound 変数を確認すると、常に false です。SystemClock.sleep() が機能するかどうかを確認するために試してみましたが、機能しませんでした。本当に困惑しているのは、このアクティビティを最初に書いたとき、クリックするとリストにデータを入力する手順を開始するボタンを使用したことです。それは完璧に機能しました。

    それで、私が見逃しているのは何ですか?連絡先を表示するためだけにユーザーがボタンを押す必要がないことは明らかです。onStart() でリストにデータが入力されるようにします。onClickListener 内から Service にアクセスしようとすると Service がバインドされるのはなぜですか。また、onStart でサービスが機能しないのはなぜですか。

    バインディングが非同期であることと関係があると思いますが、正確に何を見つけようとしています。

主な活動 :

package com.example.smack_text;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity 
{
XMPPService mService;
boolean mBound = false;
Button logBtn;
Button disBtn;
EditText userTxt;
EditText passTxt;

@Override
protected void onCreate(Bundle savedInstanceState) 
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//      BIND SERVICE
Intent intent = new Intent(getApplicationContext(), XMPPService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}

@Override
protected void onStart() 
{
super.onStart();

userTxt = (EditText) findViewById(R.id.userTxt);
passTxt = (EditText) findViewById(R.id.passTxt);

logBtn = (Button) findViewById(R.id.logBtn);
disBtn = (Button) findViewById(R.id.disBtn);
logBtn.setOnClickListener(new OnClickListener() 
    {

    @Override
    public void onClick(View v) 
        {
        final String user = new String(userTxt.getText().toString()); 
        final String pass = new String(passTxt.getText().toString());

        if(user=="" || pass=="")
            {
            Toast.makeText(getApplicationContext(), "Enter name and pass",           
Toast.LENGTH_LONG).show();
            }
        if(mBound)
        {
                mService.connect(user,pass);
                Log.d("Alex","connected");
        }
        else
        {
            Log.d("Alex","error in connecting");
        }
        Intent roster = new Intent();
        roster.setClass(getApplicationContext(), RosterActivity.class);
        startActivity(roster);
    }
});

disBtn.setOnClickListener(new OnClickListener() 
{
@Override
public void onClick(View v) 
    {
    if(mBound)
        {
        mService.disconnect();
        Log.d("Alex","disconnected");
        }
    else
        {
        Log.d("Alex","error in disconnecting");
        }
    }
});


}

@Override
protected void onDestroy() 
{
// Unbind from the service
if (mBound) 
    {
    unbindService(mConnection);
    mBound = false;
    }
super.onDestroy();
}

private ServiceConnection mConnection = new ServiceConnection() 
{
@Override
public void onServiceConnected(ComponentName name, IBinder service) 
    {
    mService = ((XMPPService.LocalBinder)service).getService();
    mBound = true;
    }

@Override
public void onServiceDisconnected(ComponentName name) 
    {
     mBound = false;
    }
};
} 

RosterActivity :

package com.example.smack_text;

import java.util.Collection;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.packet.Presence;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

public class RosterActivity extends ListActivity{

boolean mBound = false;
XMPPService mService;
Button btn;


@Override
public void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.roster);

    Intent intent = new Intent(getApplicationContext(), XMPPService.class);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

@Override
public void onStart(){
    super.onStart();
//      btn = (Button) findViewById(R.id.button1);
//      btn.setOnClickListener(new OnClickListener() {

//          @Override
//          public void onClick(View v) {

            if(mBound){
                Log.d("Alex","roster connected");

                Roster roster = mService.connection.getRoster();
//                  XWRIS TO RELOAD DN DOULEYEI
                roster.reload();

                Integer length = roster.getEntryCount();
                String[] users = new String[length];
                String[] userPresence = new String[length];

                Integer i=0;

                Collection<RosterEntry> entries = roster.getEntries();

                for(RosterEntry entry:entries){
                    users[i] = entry.getName();


Presence tmpPres = roster.getPresence(entry.getUser());
                    userPresence[i] = tmpPres.toString();
                    Log.d("RosterActivity" , entry.getUser().toString());

                    i++;

                }


ArrayAdapter<String> adapter = new ArrayAdapter<String>    (RosterActivity.this,

android.R.layout.simple_expandable_list_item_1,     users);
                    setListAdapter(adapter);



            }
            else{

Toast.makeText(getApplicationContext(), "service not bound yet", Toast.LENGTH_LONG).show();
            }

        }
//      });
//  }

@Override
protected void onDestroy() {

    // Unbind from the service
    if (mBound) {
        unbindService(mConnection);
        mBound = false;
    }
    super.onDestroy();
}

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {


    // Creating the dialog
    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    Object o = l.getItemAtPosition(position);
    String str = o.toString();
    Log.d("Roster Activity",str);

    builder.setTitle("Start Chat?");
    builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {

        @Override
        public void onClick(DialogInterface dialog, int which) {
            Intent chat = new Intent();
            chat.setClass(getApplicationContext(), ChatActivity.class);
            startActivity(chat);
        }
    });


    AlertDialog alert = builder.create();
    alert.show();
}




private ServiceConnection mConnection = new ServiceConnection() {


    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mService = ((XMPPService.LocalBinder)service).getService();

        mBound = true;

    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
         mBound = false;

    }
    };

}

XMPP サービス:

package com.example.smack_text;

import java.io.File;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class XMPPService extends Service{

XMPPConnection connection;
private final IBinder mBinder = new LocalBinder();


    @Override
    public void onCreate(){
        super.onCreate();
    }

    /**
     * Class used for the client Binder.  Because we know this service always
     * runs in the same process as its clients, we don't need to deal with IPC.
     */
    public class LocalBinder extends Binder {
        XMPPService getService() {
            return XMPPService.this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    public void connect(final String user, final String pass) {


        Log.d("Xmpp Alex","in service");


        ConnectionConfiguration config = new ConnectionConfiguration("10.0.2.2",5222);

//          KEYSTORE SETTINGS
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            config.setTruststoreType("AndroidCAStore");
            config.setTruststorePassword(null);
            config.setTruststorePath(null);
        } else {
            config.setTruststoreType("BKS");
            String path = System.getProperty("javax.net.ssl.trustStore");
            if (path == null)
                path = System.getProperty("java.home") + File.separator + "etc"
                    + File.separator + "security" + File.separator
                    + "cacerts.bks";
            config.setTruststorePath(path);
        }

//          Create XMPP Connection

        connection = new XMPPConnection(config);

//          THELEI TO RUNNABLE ALLIWS DN TREXEI

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    connection.connect();
                    connection.login(user, pass);
                    if(connection.isConnected()){
                        Log.d("Alex", "connected biatch!");
//                          try {
//                              Thread.sleep(5000);
//                          } catch (InterruptedException e) {
//                              e.printStackTrace();
//                          }
                    }
                    else{
                        Log.d("Alex","not connected");
                    }


                } catch (XMPPException e) {
                    e.printStackTrace();
                }
            }
        }).start();


    }

    public void disconnect(){
        if(connection.isConnected()){
            connection.disconnect();
        }

else{Toast.makeText(getApplicationContext(), "not     connected",Toast.LENGTH_LONG).show();
        }
    }

}

そしてレイアウト:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context=".MainActivity" >

<EditText
    android:id="@+id/userTxt"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_below="@+id/textView1"
    android:layout_marginLeft="30dp"
    android:layout_marginTop="27dp"
    android:background="#FFFFFF"
    android:ems="10"
    android:inputType="textPersonName" >

    <requestFocus />
</EditText>

<TextView
    android:id="@+id/textView1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/userTxt"
    android:layout_alignParentTop="true"
    android:layout_marginLeft="14dp"
    android:layout_marginTop="52dp"
    android:background="#FFFFFF"
    android:text="User Name :" />

<TextView
    android:id="@+id/textView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/textView1"
    android:layout_below="@+id/userTxt"
    android:layout_marginTop="62dp"
    android:background="#FFFFFF"
    android:text="Password :" />

<EditText
    android:id="@+id/passTxt"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignLeft="@+id/userTxt"
    android:layout_below="@+id/textView2"
    android:layout_marginTop="58dp"
    android:background="#FFFFFF"
    android:ems="10"
    android:inputType="textPassword" />

<Button
    android:id="@+id/logBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignRight="@+id/textView2"
    android:layout_below="@+id/passTxt"
    android:layout_marginTop="66dp"
    android:background="#FFFFFF"
    android:text="Log In" />

<Button
    android:id="@+id/disBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBottom="@+id/logBtn"
    android:layout_alignRight="@+id/userTxt"
    android:background="#FFFFFF"
    android:text="disconnect" />

</RelativeLayout>

名簿.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Button" />

<ListView
    android:id="@android:id/list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
</ListView>

</LinearLayout>
4

1 に答える 1

0

このようなことは少し混乱する可能性があるといつも思っているので、アプリ開発を容易にするために設計されたAndroidフレームワークであるVaporAPIにこれを簡単にするためのサポートを作成しました。

すべてのバインディングを暗黙的に管理し、サービスのクラスによって純粋にバインディングを取得することもできます(コード内で接続オブジェクトを維持する必要はありません。これは自動的に行われます)。

試してみたい場合は、次のように実行できます(VaporActivityVaporServiceBindableを使用)。

public class RosterActivity extends VaporActivity{

   public void create(VaporBundle bundle){

      $.srv(XMPPService.class); // optionally, first start the service

      // set up the callback for when the service is bound
      $.hook(SERVICE_BIND).hookIn(new $$hookee(){

          public void call(String hookName, VaporBundle args){

             // put your code here that depends on the binding...

          }

      });

      // bind to the service
      $.bind(XMPPService.class);


    }

}

これは明らかに、バインディングが非同期であるという事実に基づいて、あなたが説明する種類の問題の単純化されたスケルトンです。

さらに、アクティビティ内でサービスのメソッドを使用する場合は、どこからでも簡単に実行できます。

this.service(XMPPService.class).foo(); // some method in the service

内部的には、これは自動的に作成された以前のものを取得し、サービスServiceConnectionへのアクセスを提供しますIBinder

興味があれば、VaporServiceもチェックしてください。独自のスレッド内でサービスを実行し、任意に一時停止、スリープ、再起動できるため、面倒な詳細を気にすることなくサービスを完全に制御できます。

お役に立てば幸いです。

于 2013-03-07T15:48:20.877 に答える