和我之前的很多人一樣,我正在使用asmack和Openfire寫一個聊天應用程序。 這仍然是非常基本的,但我已經設法發送和接收消息與用戶在模擬器與火花和其他人一起。確保綁定服務
經過一些SO閱讀後,我決定爲我的XMPP連接創建一個服務,並將其綁定到每個活動。我目前有三項活動
- MainActivity(用戶登錄和連接到XMPPconnection)。
- RosterActivity(包含一個ListView用戶的聯繫人)
- ChatActivity
我的問題是雙重的:
是否有必要每一次活動的服務綁定,或有可能只需將MainActivity綁定到它並將XMPPConnection作爲額外的參數傳遞給它?如果是這樣,那麼傳球怎麼辦呢?
我登錄並啓動RosterActivity後,我在onCreate()方法中綁定了服務。在onStart方法中,如果我檢查mBound變量,它總是爲false。我試過SystemClock.sleep()只是爲了看它是否會起作用,而不是。令我感到困惑的是,當我第一次寫這個Activity的時候,我使用了一個按鈕,當點擊這個按鈕時,會啓動該過程來填充列表。這工作完美。
那麼我錯過了什麼?我顯然不希望用戶不得不按下按鈕來查看聯繫人,我想要在onStart()中填充列表。爲什麼當我試圖通過onClickListener訪問服務時會綁定服務,爲什麼它在onStart中不起作用?
我猜它具有一切與綁定是異步的,但我試圖找出究竟是什麼。
MainActivity:
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;
}
};
}
XMPPService:
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>
roster.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>
非常感謝您的回覆,它看起來非常有用,但由於這是我的最終項目,我需要明確地做所有事情。 – countzero 2013-03-21 15:07:53