以前の多くの人と同じように、私は asmack と Openfire を使用してチャット アプリケーションを作成しています。これはまだかなり基本的なものですが、Spark でログインしているユーザーとエミュレーターで別のユーザーとの間でメッセージを送受信することができました。
SO を読んだ後、すべてのアクティビティにバインドする XMPP 接続用のサービスを作成することにしました。現在3つの活動を行っています
- MainActivity (ユーザーのログインと XMPPconnection への接続)。
- RosterActivity (ユーザーの連絡先を含むリストビュー)
- チャット活動
私の質問は2つあります:
すべてのアクティビティを Service にバインドする必要がありますか、それとも MainActivity をそれにバインドして XMPPConnection を extra として渡すことは可能でしょうか? もしそうなら、どのように渡すことができますか?
ログインして 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>