編輯:關於Android編程
Socket是基於Tcp的鏈接,適用於長鏈接
Socke通訊需要客戶端和服務器,客戶端我們在android上編寫,而服務器則選擇在eclipse上編寫
上效果圖;
eclipse:
我們一共需要4個類,分別是
Server類,繼承自Thread,用於建立服務器,並監聽Socket的鏈接
MySocket類,繼承自Thread,用於對Socket進行讀寫操作
SocketManager類,單態模式,管理Socket,不過主要的用途其實還是可以將信息發送給所有人
Start類,開啟Server類
Start:
package wkk.server.socket;
public class Start {
public static void main(String[] args) {
new Server().start();
}
}
Server:
package wkk.server.socket;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends Thread {
private SocketManager manager;
@Override
public void run() {
try {
// 1-65535
ServerSocket ss = new ServerSocket(1234);
manager=SocketManager.getInstance();
while (true) {
// 此方法會阻塞線程 直至有人鏈接
Socket socket = ss.accept();
System.out.println("有客戶端連接上服務器了");
MySocket socket1=new MySocket(socket);
socket1.start();
manager.add(socket1);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
new ServerSocket(1234);
這個方法的參數為int型端口號數值在1-65535之間,一般選擇較大值避免沖突
accept(),這個方法會阻塞線程,所以適合在主線程中進行操作,我們循環監聽Socket的鏈接,為每一個Socket開啟一個獨立的線程,並將Socket添加到SocketManager的list集合中
MySocket :
package wkk.server.socket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class MySocket extends Thread {
private Socket socket;
private SocketManager manager;
public MySocket(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
manager=SocketManager.getInstance();
try {
//讀取並發送
BufferedReader reader = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
String messageString = null;
while ((messageString = reader.readLine()) != null) {
System.out.println(messageString);
manager.sendAll(this, messageString);
}
reader.close();
manager.remove(this);
} catch (Exception e) {
}
}
//寫
public void out(String out) {
try {
socket.getOutputStream().write((out + "\r\n").getBytes("utf-8"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
在構造方法中傳入所需的Socket,繼承自Thread,在run方法中監聽客戶端發送來的消息,並將消息發送給所有人
SocketManager:
package wkk.server.socket;
import java.util.ArrayList;
public class SocketManager {
private static SocketManager manager;
private ArrayList list;
private SocketManager() {
list = new ArrayList();
}
public static SocketManager getInstance() {
if (manager == null) {
manager = new SocketManager();
}
return manager;
}
public void add(MySocket soc){
list.add(soc);
}
public void remove(MySocket soc){
list.remove(soc);
}
//發送給所有人
public void sendAll(MySocket soc,String out){
for (MySocket soc1 : list) {
if(!soc.equals(soc1)){
soc1.out(out);
}
}
}
}
這個類就很簡單了,只有一個list並提過對外部的方法,增加,刪除,以及發送給除自己之外的所有人
好eclipse上就這些東西
接下來開始編寫Android的代碼:
<code class=" hljs xml"><!--?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" tools:context="wkk.app4.MainActivity"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content"> <edittext android:id="@+id/ip" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="輸入ip地址" android:text="192.168.1.110"> <edittext android:id="@+id/code" android:layout_width="100dp" android:layout_height="wrap_content" android:hint="輸入端口號" android:text="1234"> <button android:id="@+id/link" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="鏈接"> <listview android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"></listview> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content"> <edittext android:id="@+id/message" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:hint="輸入聊天信息"> </edittext></linearlayout></button></edittext></edittext></linearlayout></linearlayout></code><button android:id="@+id/send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="發送"><code class=" hljs xml"> </code></button>
整個布局很簡單,在上面已經看過效果圖了
listview的item也很簡單,之後一個TextView我就不貼了
適配器什麼的無關緊要,就不占用篇幅了,實體類就一個String和一個boolean,一個是用於顯示內容,一個是用於判斷是自己發出去的信息,還是其他人發出去的信息,來設置TextView的Gravity,實在不懂的等下可以下源碼
MainActivity:
package wkk.app4;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener,Handler.Callback {
private EditText ip, code, message;
private Button link, send;
private ListView listview;
private Socket socket;
private InputStream inputStream;
private OutputStream outputStream;
private MyAdapter adapter;
private List list;
private String[] ipandcode;//裡面的內容分別是ip地址和端口號
private Handler handler;
private BufferedWriter writer;//對outputStream包裝用於發送信息
private static final int MESSAGE=0;
private static final int SUCCEED=1;
private static final int FAILURE=2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化相應數據
findview();
adapter = new MyAdapter(this);
listview.setAdapter(adapter);
list = adapter.getList();
handler=new Handler(this);
}
private void findview() {
ip = (EditText) findViewById(R.id.ip);
code = (EditText) findViewById(R.id.code);
message = (EditText) findViewById(R.id.message);
link = (Button) findViewById(R.id.link);
send = (Button) findViewById(R.id.send);
listview = (ListView) findViewById(R.id.listview);
link.setOnClickListener(this);
send.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.link:
String ipt = ip.getText().toString().trim();
String codet = code.getText().toString().trim();
if (TextUtils.isEmpty(ipt) || TextUtils.isEmpty(codet)) {
return;
}
if (socket != null) {
Toast.makeText(this,"已連接",Toast.LENGTH_SHORT).show();
return;
}
ipandcode = new String[2];
ipandcode[0] = ipt;
ipandcode[1] = codet;
//使用異步任務來進行網絡操作
new MyAsyncTask().execute();
break;
case R.id.send:
if(writer==null){
Toast.makeText(this,"請先鏈接",Toast.LENGTH_SHORT).show();
return;
}
try {
//發送數據
writer.write(message.getText().toString().trim() + "\n");
writer.flush();
Bean bean=new Bean();
bean.setMessage( message.getText().toString().trim());
bean.setIsmy(true);
list.add(bean);
message.setText("");
adapter.notifyDataSetChanged();
} catch (IOException e) {
Log.d("測試",e.toString());
}
break;
}
}
@Override
public boolean handleMessage(Message msg) {
switch(msg.what){
case MESSAGE:
//獲取信息刷新界面
String message= (String) msg.obj;
Bean bean=new Bean();
bean.setMessage(message);
bean.setIsmy(false);
list.add(bean);
adapter.notifyDataSetChanged();
break;
case SUCCEED:
Toast.makeText(this,"鏈接成功",Toast.LENGTH_SHORT).show();
break;
case FAILURE:
Toast.makeText(this,"鏈接失敗",Toast.LENGTH_SHORT).show();
break;
}
return true;
}
private class MyAsyncTask extends AsyncTask {
@Override
protected String doInBackground(Void... params) {
try {
//參數 ip地址 端口號
socket=new Socket(ipandcode[0],Integer.parseInt(ipandcode[1]));
Message msg= handler.obtainMessage();
msg.what=SUCCEED;
handler.sendMessage(msg);
} catch (IOException e) {
Message msg= handler.obtainMessage();
msg.what=FAILURE;
handler.sendMessage(msg);
return null;
}
try {
outputStream = socket.getOutputStream();
inputStream = socket.getInputStream();
writer=new BufferedWriter(new OutputStreamWriter(outputStream));
//監聽服務器傳遞過來的信息
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String message = null;
while ((message = reader.readLine()) != null) {
Message msg= handler.obtainMessage();
msg.what=MESSAGE;
msg.obj=message;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
}
整個Activity代碼看起來有點復雜,但是邏輯並不多,無非就是連接服務器,向服務器發送數據,監聽服務器傳遞過來的數據並且刷新界面這些而已,核心代碼就那麼多,和服務器上的代碼幾乎一樣,無非就是接收和發送數據罷了:
//發送數據
writer.write(message.getText().toString().trim() + "\n");
writer.flush();
接收:
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String message = null;
while ((message = reader.readLine()) != null) {
Message msg= handler.obtainMessage();
msg.what=MESSAGE;
msg.obj=message;
handler.sendMessage(msg);
}
好了,接下來,你只要將eclipse的服務開啟,然後就可以聊天了,當然界面很簡介,有興趣可以給它拓展下…
整個代碼就這麼多,看清楚了真的不難,但是這個demo只能在局域網下進行通訊,如果想放到外網上這些代碼肯定不行,會很麻煩,如果有興趣可以自己去嘗試下,
額…………
本文實例講述了Android實現獲取SD卡總容量,可用大小,機身內存總容量及可用大小的方法。分享給大家供大家參考,具體如下:可能有的同學不知道系統已經提供了獲取獲取SD卡
近期在做圖片上傳的功能,從相機拍攝或從相冊選區。就研究了這方面的東西一.圖片的基本知識1.文件形式(即以二進制形式存在於硬盤上)獲取大小(Byte):File.lengt
In recent years,mobile platform become more and more popular!At present,the flourishi
程序員很多,遍地都是,高手也很多,但是懂設計的程序員並不多,我覺得我們不僅要成為一個coder還要成為一個designer。我是一個比較注重ued的人,如果對一個app來