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服务代码:

 
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;//发送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的知识绝对不仅仅包含这些,剩下的就看小伙伴们是不是感兴趣了。


  对于List的上滑加载更多,网络上有很多开源控件,本篇接下来我将带领大家一起学习一下,如何实现List的上滑加载更多。

  首先是我们的主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);
        }        
    }
    
}
 
原文地址:https://www.cnblogs.com/android-blogs/p/4956575.html