Android與服務器的通訊方式主要有兩種,一是Http通訊,一是Socket通訊。二者的最大差別在於,http鏈接使用的是「請求—響應方式」,即在請求時創建鏈接通道,當客戶端向服務器發送請求後,服務器端才能向客戶端返回數據。而Socket通訊則是在雙方創建起鏈接後就能夠直接進行數據的傳輸,在鏈接時可實現信息的主動推送,而不須要每次由客戶端想服務器發送請求。 那麼,什麼是socket?Socket又稱套接字,在程序內部提供了與外界通訊的端口,即端口通訊。經過創建socket鏈接,可爲通訊雙方的數據傳輸傳提供通道。socket的主要特色有數據丟失率低,使用簡單且易於移植。java
1.1什麼是Socket
是一種抽象層,應用程序經過它來發送和接收數據,使用Socket能夠將應用程序添加到網絡中,與處於同一網絡中的其餘應用程序進行通訊。簡單來講,Socket提供了程序內部與外界通訊的端口併爲通訊雙方的提供了數據傳輸通道。android
1.2Socket的分類
根據不一樣的的底層協議,Socket的實現是多樣化的。本指南中只介紹TCP/IP協議族的內容,在這個協議族當中主要的Socket類型爲流套接字(streamsocket)和數據報套接字(datagramsocket)。流套接字將TCP做爲其端對端協議,提供了一個可信賴的字節流服務。數據報套接字使用UDP協議,提供數據打包發送服務。 下面,咱們來認識一下這兩種Socket類型的基本實現模型。數組
1.3Socket簡單例子:服務器
服務器端Socket服務代碼:網絡
public class MyServer { public static void main(String[] args) throws Exception{ ServerSocket ss = new ServerSocket(555); Socket s = ss.accept(); DataInputStream dis = new DataInputStream(s.getInputStream()); DataOutputStream dos = new DataOutputStream(s.getOutputStream()); String str = dis.readUTF(); System.out.print("客戶端已鏈接"); dos.writeUTF("Server:"+str); dos.flush(); dis.close(); s.close(); ss.close(); } }
Android客戶端的代碼:app
public class MainActivity extends Activity { public static Button mybutton = null;//發送Socket請求 public static TextView mytext = null;//顯示服務器返回的值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mybutton = (Button)findViewById(R.id.button); mytext = (TextView)findViewById(R.id.text); mybutton.setOnClickListener(new mybuttonlistener()); } //按鈕的點擊事件 class mybuttonlistener implements OnClickListener{ PrintStream out = null; BufferedReader buf = null; Socket s = null; public void onClick(View v) { try { s = new Socket("10.20.90.3", 555);//建立一個IP地址爲:10.20.90.3,端口號爲:555的Socket對象 DataOutputStream dos = new DataOutputStream(s.getOutputStream());//得到一個輸出流 DataInputStream dis = new DataInputStream(s.getInputStream());//得到一個輸入流 dos.writeUTF("河南理工大學ACM協會");//發送到服務器的請求值 String str = dis.readUTF();//獲取服務器返回的參數 mytext.setText(str); dos.flush(); dos.close(); dis.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
最簡單的一個服務器<--->客戶端Socket事例就實現了,客戶端程序執行前,須要首先啓動服務器端程序,當服務器端啓動完成後,咱們就能夠經過Android客戶端發送Socket請求了。這個事例中,咱們向服務器端發送:「河南理工大學ACM協會」字段,服務器爲咱們返回:「Server:河南理工大學ACM協會」。代碼很簡單,固然關於Socket的知識絕對不單單包含這些,剩下的就看小夥伴們是否是感興趣了。socket
對於List的上滑加載更多,網絡上有不少開源控件,本篇接下來我將帶領你們一塊兒學習一下,如何實現List的上滑加載更多。ide
首先是咱們的主Activity的佈局文件,佈局文件沒有其它內容只有一個ListView控件:函數
<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" tools:context="${relativePackage}.${activityClass}" > <ListView android:id="@+id/listview" android:layout_width="fill_parent" android:layout_height="wrap_content" android:visibility="gone"> </ListView> </RelativeLayout>
咱們的主Activity代碼:佈局
public class MainActivity extends Activity { private ListView listview ;//list容器 private List<String> data = new ArrayList<String>();//暫存數據的容器 private ArrayAdapter<String> adapter; private final int number = 30;//每頁的數據量 private final int maxpage = 5;//數據的頁數 private int ItemCount;//顯示的記錄數 private int nextpage; private boolean flag = true; //表示加載數據是否完成 private View tipView;//頁腳view @SuppressLint("InflateParams") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listview_main); listview = (ListView)findViewById(R.id.listview); listview.setOnScrollListener(new scrollListener());//滑動事件監聽 listview.setOnItemClickListener(new onItemClickListener());//點擊事件監聽 tipView = getLayoutInflater().inflate(R.layout.listview_tip, null);//得到加載更多的頁腳 /* * 第一次加載 */ data.addAll(new DataScroll().getDate(0, 30));//得到第一頁須要顯示的數據 adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.listview_item, R.id.textview, data);//將數據與對應的數據顯示頁面配對 /* * 添加頁腳必須依據下面的格式 */ listview.addFooterView(tipView);//添加頁腳(在加載數據以前) listview.setAdapter(adapter);//必須在此句以前加載頁腳 listview.removeFooterView(tipView);//刪除頁腳顯示 } public final class scrollListener implements OnScrollListener{ @Override public void onScrollStateChanged(AbsListView view, int scrollState) { } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int lastItemId = listview.getLastVisiblePosition();//得到屏幕Item的最後一條記錄的ID if((lastItemId+1)==totalItemCount){//判斷是否已經拖動到頁未 if(totalItemCount > 0){//判斷是否加載的數據是最後一頁數據 int currentpage = totalItemCount%number==0 ? totalItemCount/number : totalItemCount/number+1; nextpage = currentpage + 1; if(nextpage<=maxpage && flag){ flag = false; ItemCount = totalItemCount; listview.addFooterView(tipView);//顯示加載更多頁腳 new Thread(new Runnable() { @Override public void run() { //模擬網絡加載數據 try { Thread.sleep(3000);//模擬網絡加載 } catch (InterruptedException e) { e.printStackTrace(); } DataScroll datascroll = new DataScroll(); List<String> result = datascroll.getDate(nextpage, number); Hand.sendMessage(Hand.obtainMessage(100, result)); } }).start(); } } } if(0==firstVisibleItem){ if(firstVisibleItem < 0){ Toast.makeText(MainActivity.this, "刷新", Toast.LENGTH_SHORT).show(); } } } } //返回到主線程執行 Handler Hand = new Handler(){ @SuppressWarnings("unchecked") @SuppressLint("HandlerLeak") public void handleMessage(Message msg) { data.addAll((List<String>) msg.obj); adapter.notifyDataSetChanged();//告訴ListView數據已經發生改變,要求更新ListView界面 if(listview.getFooterViewsCount()>0){ listview.removeFooterView(tipView); } flag = true; } }; //List中各Item的點擊事件 class onItemClickListener implements OnItemClickListener{ @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(getApplicationContext(), position+" "+id, Toast.LENGTH_SHORT).show(); } } }
接下來咱們須要補充一下咱們的Item的佈局(listview_item.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="wrap_content" android:background="#aa00ff" tools:context="${relativePackage}.${activityClass}" > <TextView android:id="@+id/textview" android:layout_width="fill_parent" android:layout_height="60dp" android:textSize="18sp" android:textColor="#aa0000" android:singleLine="true" /> </RelativeLayout>
固然既然是加載更多,咱們還須要一個提示用戶正在加載更多的一個頁腳(listview_tip.xml):
<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" tools:context="${relativePackage}.${activityClass}" > <ProgressBar android:id="@+id/progressBar1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_below="@+id/textview" /> <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:textSize="18sp" android:textColor="#000000" android:singleLine="true" android:text="數據加載中..." /> </LinearLayout>
固然最重要的加載數據,這裏咱們由於爲了簡單起見,就沒有經過網絡加載更多數據,而是經過一個模擬加載函數類實現的一個模擬加載(DataScroll.java):
/* * 模擬得到分頁數據 */ public class DataScroll { public List<String> getDate(int nextpage, int maxResult){ int offset = 0; if(nextpage!=0){ offset = (nextpage-2)*maxResult; } List<String > list = new ArrayList<String>(); for(int i=0; i<maxResult; i++){ list.add("List數據分批加載"+ ++offset); } return list; } }
好了,咱們的上滑加載更多的實現就爲你們分享完畢,關於下滑刷新,小夥伴們能夠經過監聽用戶滑動事件,來自行研究,很簡單相信你們都能實現,有疑問歡迎留言討論。
Spinner:Android提供的下拉列表控件,接下來我將經過5個小例子,爲你們介紹一下Spinner的系統自帶樣式與自定義樣式,固然系統自帶樣式相對簡單,咱們就從簡單開始入手,爲你們一一介紹Spinner的使用。
首先是佈局文件:
<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" tools:context="${relativePackage}.${activityClass}" > <LinearLayout android:id="@+id/linearone" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Spinner下拉列表" android:textSize="25dip" android:layout_gravity="center_horizontal" /> <Spinner android:id="@+id/spinner1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:entries="@array/arr" android:spinnerMode="dropdown" /> <Spinner android:id="@+id/spinner2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:entries="@array/brr" android:spinnerMode="dialog" /> <Spinner android:id="@+id/spinner3" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Spinner android:id="@+id/spinner4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnerMode="dialog" /> <Spinner android:id="@+id/spinner5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:spinnerMode="dialog" /> <Button android:id="@+id/buttonone" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下一頁" /> </LinearLayout> </RelativeLayout>
前兩個控件使用的是Android自帶Spinner下拉列表樣式,紅色部分是我在res->values->strings文件中設置的值:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">下拉列表</string> <string name="hello_world">Hello world!</string> <string-array name="arr"> <item>默認效果</item> <item>河南</item> <item>北京</item> <item>上海</item> </string-array> <string-array name="brr"> <item>彈出效果</item> <item>河南</item> <item>北京</item> <item>上海</item> </string-array> </resources>
主Activity代碼:
public class Activityone extends Activity { private Spinner spin1;//默認Spinner,在按鈕下方顯示 private Spinner spin2;//默認Spinner,經過Dialog的形式爲用戶展現 private Spinner spin3;//自定義Spinner,在按鈕下方顯示 private Spinner spin4;//自定義Spinner,經過Dialog的形式爲用戶展現 private Spinner spin5;//自定義Spinner,經過Dialog的形式爲用戶展現 private Button buttonone; private String [] array = new String [] { "數組引用", "表明", "組長", "小妹" }; private String [] arrayadapt = new String [] { "arrayadapt引用", "表明", "組長", "小妹" }; private List<String> list = new ArrayList<String>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_one); list.add("list引用"); list.add("表明"); list.add("組長"); list.add("小妹"); buttonone=(Button)findViewById(R.id.buttonone); spin1=(Spinner)findViewById(R.id.spinner1); spin2=(Spinner)findViewById(R.id.spinner2); spin3=(Spinner)findViewById(R.id.spinner3); spin4=(Spinner)findViewById(R.id.spinner4); spin5=(Spinner)findViewById(R.id.spinner5); ArrayAdapter<String> arrayadapter = new ArrayAdapter<String>(Activityone.this, android.R.layout.simple_spinner_item, arrayadapt); spin5.setAdapter(arrayadapter); BaseAdapter baseadapterone = new baseadapterone(); spin3.setAdapter(baseadapterone); BaseAdapter baseadaptertwo = new baseadaptertwo(); spin4.setAdapter(baseadaptertwo); //設置點擊結果選擇提示 spin4.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { Toast.makeText(Activityone.this, list.get(position), Toast.LENGTH_SHORT).show(); } @Override public void onNothingSelected(AdapterView<?> parent) { } }); buttonone.setOnClickListener(new mybuttonistener()); } private class baseadapterone extends BaseAdapter{ @Override public int getCount() { return array.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView textview = new TextView(Activityone.this); textview.setText(array[position]); return textview; } } private class baseadaptertwo extends BaseAdapter{ @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { TextView textview = new TextView(Activityone.this); textview.setText(list.get(position)); return textview; } } class mybuttonistener implements OnClickListener{ @Override public void onClick(View v) { Intent intent = new Intent(Activityone.this,Activitytwo.class); Activityone.this.startActivity(intent); } } }