這篇要來介紹的是,如何在Android使用SignalR完成簡易聊天室,我們要完成上圖畫面,Server 端的實作可以參考我的這篇文章
MVC - 使用SignalR完成簡易聊天室
別懷疑!微軟沒有上傳SignalR的Maven位置
原始碼請至github下載(有點雷.趕時間別去踩)
或是你可以跟我一樣來這裡直接下載jar檔引用
除了要引用signalr-client-sdk還有Gson也要
Manifest記得要加上網路權限
<uses-permission android:name="android.permission.INTERNET"/>
兩個檔案,主畫面與listview的item
先看activity_main的layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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:orientation="vertical"> <ListView tools:listitem="@layout/item" android:id="@+id/chatLv" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:divider="#ddd" android:dividerHeight="1dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginBottom="2dp" android:layout_marginTop="2dp" android:background="#000" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:orientation="horizontal" android:padding="5dp"> <EditText android:id="@+id/messageEt" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:padding="5dp" /> <Button android:id="@+id/sendBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="5dp" android:text="SEND" /> </LinearLayout> </LinearLayout>
item的layout
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:padding="5dp" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/nameTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="3dp" android:text="Name" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=":" /> <TextView android:id="@+id/messageTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="3dp" android:text="Message" /> </LinearLayout>
這邊有三個檔案,稍微解釋一下:
MainActivity(主畫面)
ChatAdapter(ListView Adapter)
ChatData(資料容器)
先說MainActivity,裡面的四個常數的意義
HUB_URL:就是你signalR的DomainName+/signalr
HUB_NAME:Hub檔案名稱
HUB_EVENT_NAME:Hub觸發的事件名稱
HUB_METHOD_NAME:Call的method名稱
下面這張圖可以清楚對照,如果不知道藍框裡面是什麼東西
請先看這篇
public class MainActivity extends Activity { private static final String HUB_URL = "[你的url]/signalr"; private static final String HUB_NAME = "你的Hub name"; private static final String HUB_EVENT_NAME = "你的事件名稱"; private static final String HUB_METHOD_NAME = "你的Call method name"; private SignalRFuture<Void> mSignalRFuture; private HubProxy mHub; private String mName; private ChatAdapter mChatAdapter; private ListView mChatLv; private EditText mMessageEt; private Button mSendBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mChatLv = (ListView)findViewById(R.id.chatLv); mMessageEt = (EditText)findViewById(R.id.messageEt); mSendBtn = (Button)findViewById(R.id.sendBtn); mName = "Android-"+System.currentTimeMillis(); mChatAdapter = new ChatAdapter(this,0,new ArrayList<ChatData>(),mName); mChatLv.setAdapter(mChatAdapter); mSendBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { try { String message = mMessageEt.getText().toString(); mHub.invoke(HUB_METHOD_NAME, mName, message).get(); mMessageEt.setText(""); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } }); HubConnection connection = new HubConnection(HUB_URL); mHub = connection.createHubProxy(HUB_NAME); mSignalRFuture = connection.start(new ServerSentEventsTransport(connection.getLogger())); //可以理解為訊息or事件監聽器 mHub.on(HUB_EVENT_NAME, new SubscriptionHandler2<String, String>() { @Override public void run(String name,String message) { //使用AsyncTask來更新畫面 new AsyncTask<String,Void,ChatData>(){ @Override protected ChatData doInBackground(String... param) { ChatData chatData = new ChatData(param[0],param[1]); return chatData; } @Override protected void onPostExecute(ChatData chatData) { mChatAdapter.add(chatData); mChatLv.smoothScrollToPosition(mChatAdapter.getCount()-1); super.onPostExecute(chatData); } }.execute(name,message); } }, String.class,String.class); //開啟連線 try { mSignalRFuture.get(); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } @Override protected void onDestroy() { //關閉連線 mSignalRFuture.cancel(); super.onDestroy(); } }
ChatData資料容器
public class ChatData { private String name; private String message; public ChatData(String name, String message) { this.name = name; this.message = message; } public String getName() { return name; } public String getMessage() { return message; } }
ChatAdapter,這邊比較需要講一下的只有
我將自己的聊天內容標註為紅色而已
public class ChatAdapter extends ArrayAdapter<ChatData>{ private String mName; public ChatAdapter(Context context, int resource, List<ChatData> objects,String mName) { super(context, resource, objects); this.mName = mName; } private class ViewHolder { TextView nameTv; TextView messageTv; } @Override public View getView(int position, View convertView, ViewGroup parent) { ChatData chatData = getItem(position); ViewHolder holder; if(convertView==null){ holder = new ViewHolder(); convertView = LayoutInflater.from(getContext()).inflate(R.layout.item, null); holder.nameTv = (TextView) convertView.findViewById(R.id.nameTv); holder.messageTv = (TextView) convertView.findViewById(R.id.messageTv); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.nameTv.setText(chatData.getName()); holder.messageTv.setText(chatData.getMessage()); if(chatData.getName().equals(mName)){ holder.nameTv.setTextColor(Color.RED); } return convertView; } }
Android與brower對話..