详解Android的Socket通信、List加载更多、Spinner下拉列表
Android与服务器的通信方式主要有两种,一是Http通信,一是Socket通信。两者的最大差异在于,http连接使用的是“请求—响应方式”,即在请求时建立连接通道,当客户端向服务器发送请求后,服务器端才能向客户端返回数据。而Socket通信则是在双方建立起连接后就可以直接进行数据的传输,在连接时可实现信息的主动推送,而不需要每次由客户端想服务器发送请求。那么,什么是socket?Socket又称套接字,在程序内部提供了与外界通信的端口,即端口通信。通过建立socket连接,可为通信双方的数据传输传提供通道。socket的主要特点有数据丢失率低,使用简单且易于移植。
1.1什么是Socket
是一种抽象层,应用程序通过它来发送和接收数据,使用Socket可以将应用程序添加到网络中,与处于同一网络中的其他应用程序进行通信。简单来说,Socket提供了程序内部与外界通信的端口并为通信双方的提供了数据传输通道。
1.2Socket的分类
根据不同的的底层协议,Socket的实现是多样化的。本指南中只介绍TCP/IP协议族的内容,在这个协议族当中主要的Socket类型为流套接字(streamsocket)和数据报套接字(datagramsocket)。流套接字将TCP作为其端对端协议,提供了一个可信赖的字节流服务。数据报套接字使用UDP协议,提供数据打包发送服务。下面,我们来认识一下这两种Socket类型的基本实现模型。
1.3Socket简单例子:
服务器端Socket服务代码:
publicclassMyServer{
publicstaticvoidmain(String[]args)throwsException{
ServerSocketss=newServerSocket(555);
Sockets=ss.accept();
DataInputStreamdis=newDataInputStream(s.getInputStream());
DataOutputStreamdos=newDataOutputStream(s.getOutputStream());
Stringstr=dis.readUTF();
System.out.print("客户端已连接");
dos.writeUTF("Server:"+str);
dos.flush();
dis.close();
s.close();
ss.close();
}
}
Android客户端的代码:
publicclassMainActivityextendsActivity{
publicstaticButtonmybutton=null;//发送Socket请求
publicstaticTextViewmytext=null;//显示服务器返回的值
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mybutton=(Button)findViewById(R.id.button);
mytext=(TextView)findViewById(R.id.text);
mybutton.setOnClickListener(newmybuttonlistener());
}
//按钮的点击事件
classmybuttonlistenerimplementsOnClickListener{
PrintStreamout=null;
BufferedReaderbuf=null;
Sockets=null;
publicvoidonClick(Viewv){
try{
s=newSocket("10.20.90.3",555);//创建一个IP地址为:10.20.90.3,端口号为:555的Socket对象
DataOutputStreamdos=newDataOutputStream(s.getOutputStream());//获得一个输出流
DataInputStreamdis=newDataInputStream(s.getInputStream());//获得一个输入流
dos.writeUTF("河南理工大学ACM协会");//发送到服务器的请求值
Stringstr=dis.readUTF();//获取服务器返回的参数
mytext.setText(str);
dos.flush();
dos.close();
dis.close();
s.close();
}catch(UnknownHostExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
}
}
}
最简单的一个服务器<--->客户端Socket事例就实现了,客户端程序执行前,需要首先启动服务器端程序,当服务器端启动完成后,我们就可以通过Android客户端发送Socket请求了。这个事例中,我们向服务器端发送:“河南理工大学ACM协会”字段,服务器为我们返回:“Server:河南理工大学ACM协会”。代码很简单,当然关于Socket的知识绝对不仅仅包含这些,剩下的就看小伙伴们是不是感兴趣了。
对于List的上滑加载更多,网络上有很多开源控件,本篇接下来我将带领大家一起学习一下,如何实现List的上滑加载更多。
首先是我们的主Activity的布局文件,布局文件没有其它内容只有一个ListView控件:
<RelativeLayoutxmlns: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代码:
publicclassMainActivityextendsActivity{
privateListViewlistview;//list容器
privateList<String>data=newArrayList<String>();//暂存数据的容器
privateArrayAdapter<String>adapter;
privatefinalintnumber=30;//每页的数据量
privatefinalintmaxpage=5;//数据的页数
privateintItemCount;//显示的记录数
privateintnextpage;
privatebooleanflag=true;//表示加载数据是否完成
privateViewtipView;//页脚view
@SuppressLint("InflateParams")
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.listview_main);
listview=(ListView)findViewById(R.id.listview);
listview.setOnScrollListener(newscrollListener());//滑动事件监听
listview.setOnItemClickListener(newonItemClickListener());//点击事件监听
tipView=getLayoutInflater().inflate(R.layout.listview_tip,null);//获得加载更多的页脚
/*
*第一次加载
*/
data.addAll(newDataScroll().getDate(0,30));//获得第一页需要显示的数据
adapter=newArrayAdapter<String>(getApplicationContext(),R.layout.listview_item,R.id.textview,data);//将数据与对应的数据显示页面配对
/*
*添加页脚必须依据下面的格式
*/
listview.addFooterView(tipView);//添加页脚(在加载数据之前)
listview.setAdapter(adapter);//必须在此句之前加载页脚
listview.removeFooterView(tipView);//删除页脚显示
}
publicfinalclassscrollListenerimplementsOnScrollListener{
@Override
publicvoidonScrollStateChanged(AbsListViewview,intscrollState){
}
@Override
publicvoidonScroll(AbsListViewview,intfirstVisibleItem,
intvisibleItemCount,inttotalItemCount){
intlastItemId=listview.getLastVisiblePosition();//获得屏幕Item的最后一条记录的ID
if((lastItemId+1)==totalItemCount){//判断是否已经拖动到页未
if(totalItemCount>0){//判断是否加载的数据是最后一页数据
intcurrentpage=totalItemCount%number==0?totalItemCount/number:totalItemCount/number+1;
nextpage=currentpage+1;
if(nextpage<=maxpage&&flag){
flag=false;
ItemCount=totalItemCount;
listview.addFooterView(tipView);//显示加载更多页脚
newThread(newRunnable(){
@Override
publicvoidrun(){
//模拟网络加载数据
try{
Thread.sleep(3000);//模拟网络加载
}catch(InterruptedExceptione){
e.printStackTrace();
}
DataScrolldatascroll=newDataScroll();
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();
}
}
}
}
//返回到主线程执行
HandlerHand=newHandler(){
@SuppressWarnings("unchecked")
@SuppressLint("HandlerLeak")
publicvoidhandleMessage(Messagemsg){
data.addAll((List<String>)msg.obj);
adapter.notifyDataSetChanged();//告诉ListView数据已经发生改变,要求更新ListView界面
if(listview.getFooterViewsCount()>0){
listview.removeFooterView(tipView);
}
flag=true;
}
};
//List中各Item的点击事件
classonItemClickListenerimplementsOnItemClickListener{
@Override
publicvoidonItemClick(AdapterView<?>parent,Viewview,intposition,
longid){
Toast.makeText(getApplicationContext(),position+""+id,Toast.LENGTH_SHORT).show();
}
}
}
接下来我们需要补充一下我们的Item的布局(listview_item.xml):
<RelativeLayoutxmlns: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):
<LinearLayoutxmlns: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):
/*
*模拟获得分页数据
*/
publicclassDataScroll{
publicList<String>getDate(intnextpage,intmaxResult){
intoffset=0;
if(nextpage!=0){
offset=(nextpage-2)*maxResult;
}
List<String>list=newArrayList<String>();
for(inti=0;i<maxResult;i++){
list.add("List数据分批加载"+++offset);
}
returnlist;
}
}
好了,我们的上滑加载更多的实现就为大家分享完毕,关于下滑刷新,小伙伴们可以通过监听用户滑动事件,来自行研究,很简单相信大家都能实现,有疑问欢迎留言讨论。
Spinner:Android提供的下拉列表控件,接下来我将通过5个小例子,为大家介绍一下Spinner的系统自带样式与自定义样式,当然系统自带样式相对简单,我们就从简单开始入手,为大家一一介绍Spinner的使用。
首先是布局文件:
<RelativeLayoutxmlns: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文件中设置的值:
<?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="app_name">下拉列表</string> <stringname="hello_world">Helloworld!</string> <string-arrayname="arr"> <item>默认效果</item> <item>河南</item> <item>北京</item> <item>上海</item> </string-array> <string-arrayname="brr"> <item>弹出效果</item> <item>河南</item> <item>北京</item> <item>上海</item> </string-array> </resources>
主Activity代码:
publicclassActivityoneextendsActivity{
privateSpinnerspin1;//默认Spinner,在按钮下方显示
privateSpinnerspin2;//默认Spinner,通过Dialog的形式为用户展示
privateSpinnerspin3;//自定义Spinner,在按钮下方显示
privateSpinnerspin4;//自定义Spinner,通过Dialog的形式为用户展示
privateSpinnerspin5;//自定义Spinner,通过Dialog的形式为用户展示
privateButtonbuttonone;
privateString[]array=newString[]{
"数组引用",
"代表",
"组长",
"小妹"
};
privateString[]arrayadapt=newString[]{
"arrayadapt引用",
"代表",
"组长",
"小妹"
};
privateList<String>list=newArrayList<String>();
@Override
protectedvoidonCreate(BundlesavedInstanceState){
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=
newArrayAdapter<String>(Activityone.this,android.R.layout.simple_spinner_item,arrayadapt);
spin5.setAdapter(arrayadapter);
BaseAdapterbaseadapterone=newbaseadapterone();
spin3.setAdapter(baseadapterone);
BaseAdapterbaseadaptertwo=newbaseadaptertwo();
spin4.setAdapter(baseadaptertwo);
//设置点击结果选择提示
spin4.setOnItemSelectedListener(newOnItemSelectedListener(){
@Override
publicvoidonItemSelected(AdapterView<?>parent,Viewview,
intposition,longid){
Toast.makeText(Activityone.this,list.get(position),Toast.LENGTH_SHORT).show();
}
@Override
publicvoidonNothingSelected(AdapterView<?>parent){
}
});
buttonone.setOnClickListener(newmybuttonistener());
}
privateclassbaseadapteroneextendsBaseAdapter{
@Override
publicintgetCount(){
returnarray.length;
}
@Override
publicObjectgetItem(intposition){
returnnull;
}
@Override
publiclonggetItemId(intposition){
return0;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
TextViewtextview=newTextView(Activityone.this);
textview.setText(array[position]);
returntextview;
}
}
privateclassbaseadaptertwoextendsBaseAdapter{
@Override
publicintgetCount(){
returnlist.size();
}
@Override
publicObjectgetItem(intposition){
returnnull;
}
@Override
publiclonggetItemId(intposition){
return0;
}
@Override
publicViewgetView(intposition,ViewconvertView,ViewGroupparent){
TextViewtextview=newTextView(Activityone.this);
textview.setText(list.get(position));
returntextview;
}
}
classmybuttonistenerimplementsOnClickListener{
@Override
publicvoidonClick(Viewv){
Intentintent=newIntent(Activityone.this,Activitytwo.class);
Activityone.this.startActivity(intent);
}
}
}
ok关于今天的内容介绍到此介绍,内容很简单,大家感兴趣的话可以实现一下。新手学习,高手交流。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持毛票票!