詳解Android的Socket通信、List加載更多、Spinner下拉列表
Android與服務(wù)器的通信方式主要有兩種,一是Http通信,一是Socket通信。兩者的最大差異在于,http連接使用的是“請(qǐng)求—響應(yīng)方式”,即在請(qǐng)求時(shí)建立連接通道,當(dāng)客戶端向服務(wù)器發(fā)送請(qǐng)求后,服務(wù)器端才能向客戶端返回?cái)?shù)據(jù)。而Socket通信則是在雙方建立起連接后就可以直接進(jìn)行數(shù)據(jù)的傳輸,在連接時(shí)可實(shí)現(xiàn)信息的主動(dòng)推送,而不需要每次由客戶端想服務(wù)器發(fā)送請(qǐng)求。 那么,什么是socket?Socket又稱套接字,在程序內(nèi)部提供了與外界通信的端口,即端口通信。通過(guò)建立socket連接,可為通信雙方的數(shù)據(jù)傳輸傳提供通道。socket的主要特點(diǎn)有數(shù)據(jù)丟失率低,使用簡(jiǎn)單且易于移植。
1.1什么是Socket
是一種抽象層,應(yīng)用程序通過(guò)它來(lái)發(fā)送和接收數(shù)據(jù),使用Socket可以將應(yīng)用程序添加到網(wǎng)絡(luò)中,與處于同一網(wǎng)絡(luò)中的其他應(yīng)用程序進(jìn)行通信。簡(jiǎn)單來(lái)說(shuō),Socket提供了程序內(nèi)部與外界通信的端口并為通信雙方的提供了數(shù)據(jù)傳輸通道。
1.2Socket的分類(lèi)
根據(jù)不同的的底層協(xié)議,Socket的實(shí)現(xiàn)是多樣化的。本指南中只介紹TCP/IP協(xié)議族的內(nèi)容,在這個(gè)協(xié)議族當(dāng)中主要的Socket類(lèi)型為流套接字(streamsocket)和數(shù)據(jù)報(bào)套接字(datagramsocket)。流套接字將TCP作為其端對(duì)端協(xié)議,提供了一個(gè)可信賴的字節(jié)流服務(wù)。數(shù)據(jù)報(bào)套接字使用UDP協(xié)議,提供數(shù)據(jù)打包發(fā)送服務(wù)。 下面,我們來(lái)認(rèn)識(shí)一下這兩種Socket類(lèi)型的基本實(shí)現(xiàn)模型。
1.3Socket簡(jiǎn)單例子:
服務(wù)器端Socket服務(wù)代碼:
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客戶端的代碼:
public class MainActivity extends Activity { public static Button mybutton = null;//發(fā)送Socket請(qǐng)求 public static TextView mytext = null;//顯示服務(wù)器返回的值 @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()); } //按鈕的點(diǎn)擊事件 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);//創(chuàng)建一個(gè)IP地址為:10.20.90.3,端口號(hào)為:555的Socket對(duì)象 DataOutputStream dos = new DataOutputStream(s.getOutputStream());//獲得一個(gè)輸出流 DataInputStream dis = new DataInputStream(s.getInputStream());//獲得一個(gè)輸入流 dos.writeUTF("河南理工大學(xué)ACM協(xié)會(huì)");//發(fā)送到服務(wù)器的請(qǐng)求值 String str = dis.readUTF();//獲取服務(wù)器返回的參數(shù) mytext.setText(str); dos.flush(); dos.close(); dis.close(); s.close(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }
最簡(jiǎn)單的一個(gè)服務(wù)器<--->客戶端Socket事例就實(shí)現(xiàn)了,客戶端程序執(zhí)行前,需要首先啟動(dòng)服務(wù)器端程序,當(dāng)服務(wù)器端啟動(dòng)完成后,我們就可以通過(guò)Android客戶端發(fā)送Socket請(qǐng)求了。這個(gè)事例中,我們向服務(wù)器端發(fā)送:“河南理工大學(xué)ACM協(xié)會(huì)”字段,服務(wù)器為我們返回:“Server:河南理工大學(xué)ACM協(xié)會(huì)”。代碼很簡(jiǎn)單,當(dāng)然關(guān)于Socket的知識(shí)絕對(duì)不僅僅包含這些,剩下的就看小伙伴們是不是感興趣了。
對(duì)于List的上滑加載更多,網(wǎng)絡(luò)上有很多開(kāi)源控件,本篇接下來(lái)我將帶領(lǐng)大家一起學(xué)習(xí)一下,如何實(shí)現(xiàn)List的上滑加載更多。
首先是我們的主Activity的布局文件,布局文件沒(méi)有其它內(nèi)容只有一個(gè)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>();//暫存數(shù)據(jù)的容器 private ArrayAdapter<String> adapter; private final int number = 30;//每頁(yè)的數(shù)據(jù)量 private final int maxpage = 5;//數(shù)據(jù)的頁(yè)數(shù) private int ItemCount;//顯示的記錄數(shù) private int nextpage; private boolean flag = true; //表示加載數(shù)據(jù)是否完成 private View tipView;//頁(yè)腳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());//滑動(dòng)事件監(jiān)聽(tīng) listview.setOnItemClickListener(new onItemClickListener());//點(diǎn)擊事件監(jiān)聽(tīng) tipView = getLayoutInflater().inflate(R.layout.listview_tip, null);//獲得加載更多的頁(yè)腳 /* * 第一次加載 */ data.addAll(new DataScroll().getDate(0, 30));//獲得第一頁(yè)需要顯示的數(shù)據(jù) adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.listview_item, R.id.textview, data);//將數(shù)據(jù)與對(duì)應(yīng)的數(shù)據(jù)顯示頁(yè)面配對(duì) /* * 添加頁(yè)腳必須依據(jù)下面的格式 */ listview.addFooterView(tipView);//添加頁(yè)腳(在加載數(shù)據(jù)之前) listview.setAdapter(adapter);//必須在此句之前加載頁(yè)腳 listview.removeFooterView(tipView);//刪除頁(yè)腳顯示 } 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){//判斷是否已經(jīng)拖動(dòng)到頁(yè)未 if(totalItemCount > 0){//判斷是否加載的數(shù)據(jù)是最后一頁(yè)數(shù)據(jù) int currentpage = totalItemCount%number==0 ? totalItemCount/number : totalItemCount/number+1; nextpage = currentpage + 1; if(nextpage<=maxpage && flag){ flag = false; ItemCount = totalItemCount; listview.addFooterView(tipView);//顯示加載更多頁(yè)腳 new Thread(new Runnable() { @Override public void run() { //模擬網(wǎng)絡(luò)加載數(shù)據(jù) try { Thread.sleep(3000);//模擬網(wǎng)絡(luò)加載 } 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(); } } } } //返回到主線程執(zhí)行 Handler Hand = new Handler(){ @SuppressWarnings("unchecked") @SuppressLint("HandlerLeak") public void handleMessage(Message msg) { data.addAll((List<String>) msg.obj); adapter.notifyDataSetChanged();//告訴ListView數(shù)據(jù)已經(jīng)發(fā)生改變,要求更新ListView界面 if(listview.getFooterViewsCount()>0){ listview.removeFooterView(tipView); } flag = true; } }; //List中各Item的點(diǎn)擊事件 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(); } } }
接下來(lái)我們需要補(bǔ)充一下我們的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>
當(dāng)然既然是加載更多,我們還需要一個(gè)提示用戶正在加載更多的一個(gè)頁(yè)腳(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="數(shù)據(jù)加載中..." /> </LinearLayout>
當(dāng)然最重要的加載數(shù)據(jù),這里我們因?yàn)闉榱撕?jiǎn)單起見(jiàn),就沒(méi)有通過(guò)網(wǎng)絡(luò)加載更多數(shù)據(jù),而是通過(guò)一個(gè)模擬加載函數(shù)類(lèi)實(shí)現(xiàn)的一個(gè)模擬加載(DataScroll.java):
/* * 模擬獲得分頁(yè)數(shù)據(jù) */ 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數(shù)據(jù)分批加載"+ ++offset); } return list; } }
好了,我們的上滑加載更多的實(shí)現(xiàn)就為大家分享完畢,關(guān)于下滑刷新,小伙伴們可以通過(guò)監(jiān)聽(tīng)用戶滑動(dòng)事件,來(lái)自行研究,很簡(jiǎn)單相信大家都能實(shí)現(xiàn),有疑問(wèn)歡迎留言討論。
Spinner:Android提供的下拉列表控件,接下來(lái)我將通過(guò)5個(gè)小例子,為大家介紹一下Spinner的系統(tǒng)自帶樣式與自定義樣式,當(dāng)然系統(tǒng)自帶樣式相對(duì)簡(jiǎn)單,我們就從簡(jiǎn)單開(kāi)始入手,為大家一一介紹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="下一頁(yè)" /> </LinearLayout> </RelativeLayout>
前兩個(gè)控件使用的是Android自帶Spinner下拉列表樣式,紅色部分是我在res->values->strings文件中設(shè)置的值:
<?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>默認(rèn)效果</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;//默認(rèn)Spinner,在按鈕下方顯示 private Spinner spin2;//默認(rèn)Spinner,通過(guò)Dialog的形式為用戶展示 private Spinner spin3;//自定義Spinner,在按鈕下方顯示 private Spinner spin4;//自定義Spinner,通過(guò)Dialog的形式為用戶展示 private Spinner spin5;//自定義Spinner,通過(guò)Dialog的形式為用戶展示 private Button buttonone; private String [] array = new String [] { "數(shù)組引用", "代表", "組長(zhǎng)", "小妹" }; private String [] arrayadapt = new String [] { "arrayadapt引用", "代表", "組長(zhǎng)", "小妹" }; 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("組長(zhǎng)"); 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); //設(shè)置點(diǎn)擊結(jié)果選擇提示 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); } } }
ok關(guān)于今天的內(nèi)容介紹到此介紹,內(nèi)容很簡(jiǎn)單,大家感興趣的話可以實(shí)現(xiàn)一下。新手學(xué)習(xí),高手交流。
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
- Android使用Spinner控件實(shí)現(xiàn)下拉列表的案例
- Android控件Spinner實(shí)現(xiàn)下拉列表及監(jiān)聽(tīng)功能
- Android UI控件之Spinner下拉列表效果
- Android自定義單選多選下拉列表的實(shí)例代碼
- Android下拉列表選項(xiàng)框及指示箭頭動(dòng)畫(huà)
- Android中PopuWindow實(shí)現(xiàn)下拉列表實(shí)例
- Android編程實(shí)現(xiàn)多列顯示的下拉列表框Spinner功能示例
- Android中使用Spinner實(shí)現(xiàn)下拉列表功能
- Android仿美團(tuán)淘寶實(shí)現(xiàn)多級(jí)下拉列表菜單功能
- Android下拉列表框Spinner使用方法詳解
相關(guān)文章
Android自定義短信倒計(jì)時(shí)view流程分析
倒計(jì)時(shí)實(shí)現(xiàn)有三種方式 而這個(gè)自定義view是通過(guò)handler實(shí)現(xiàn)的。本文通過(guò)實(shí)例代碼給大家介紹Android自定義短信倒計(jì)時(shí)view流程,,需要的朋友可以參考下2020-03-03Win8下Android SDK安裝與環(huán)境變量配置教程
這篇文章主要為大家詳細(xì)介紹了Win8下Android SDK安裝與環(huán)境變量配置教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07Android Studio 下自動(dòng)注釋(自定義作者,類(lèi)作用等)圖文詳解
android studio 下自動(dòng)注釋功能居然被隱藏了,很多功能都不見(jiàn)了,下面小編通過(guò)本文給大家分享Android Studio 下自動(dòng)注釋(自定義作者,類(lèi)作用等)圖文詳解,需要的朋友參考下吧2017-11-11Android 坐標(biāo)系與視圖坐標(biāo)系圖解分析
下面小編就為大家?guī)?lái)一篇Android 坐標(biāo)系與視圖坐標(biāo)系圖解分析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03音量控制鍵控制的音頻流(setVolumeControlStream)描述
當(dāng)開(kāi)發(fā)多媒體應(yīng)用或者游戲應(yīng)用的時(shí)候,需要使用音量控制鍵來(lái)設(shè)置程序的音量大小,在Android系統(tǒng)中有多種音頻流,感興趣的朋友可以了解下2013-01-01解決Android V7后自定義Toolbar、ActionBar左側(cè)有空白問(wèn)題
這篇文章主要介紹的Android V7后自定義Toolbar、ActionBar左側(cè)有空白問(wèn)題的解決方法,需要的朋友可以參考下2017-04-04Android用文件存儲(chǔ)數(shù)據(jù)的方法
這篇文章主要為大家詳細(xì)介紹了Android用文件存儲(chǔ)數(shù)據(jù)的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android Studio導(dǎo)入Eclipse項(xiàng)目的兩種方法
本文主要介紹了Android Studio導(dǎo)入Eclipse項(xiàng)目的兩種方法。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01Android webview和js互相調(diào)用實(shí)現(xiàn)方法
這篇文章主要介紹了 Android webview和js互相調(diào)用實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下2016-10-10