像我之前的许多人一样,我正在使用 asmack 和 Openfire 编写一个聊天应用程序。它仍然很基本,但我已经成功地与一个用 Spark 登录的用户和另一个在模拟器上登录的用户发送和接收消息。
在阅读了一些 SO 之后,我决定为我绑定到每个 Activity 的 XMPP 连接创建一个服务。我目前有三个活动
- MainActivity(用户登录并连接到 XMPPconnection)。
- RosterActivity(包含用户联系人的列表视图)
- 聊天活动
我的问题是双重的:
是否有必要将每个活动绑定到服务,或者是否可以将 MainActivity 绑定到它并将 XMPPConnection 作为额外的传递?如果是这样,如何通过?
登录并启动 RosterActivity 后,我在 onCreate() 方法中绑定服务。在 onStart 方法中,如果我检查 mBound 变量,它总是错误的。我已经尝试过 SystemClock.sleep() 只是为了看看它是否可以工作,但它没有。真正让我困惑的是,当我第一次编写这个 Activity 时,我使用了一个按钮,单击该按钮将启动填充列表的过程。那工作得很好。
那么我错过了什么?我显然不希望用户必须按下按钮才能查看联系人,我希望在 onStart() 处填充列表。为什么当我尝试从 onClickListener 内部访问它时服务绑定,为什么它在 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;
}
};
}
名册活动:
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>