Android网络编程

一、Socket编程

Android网络编程和Java网络编程一样,也可通过Scokcet进行网络通信。

二、HTTP请求

一般有两种方法,通过HttpURLConnection或HttpClient,但HttpClient现在官方不再支持,故选择HttpURLConnection方式。下面为HttpURLConnection方式:

首先编写一个网络处理的类,主要实现post访问和get访问方法,代码如下

public class NetUtils {
    public static String post(String url,String content){
        HttpURLConnection conn = null;
        try {
            // 创建一个URL对象
            URL mUrl = new URL(url);
            // 调用URL的openConnection()方法,获取HttpURLConnection对象
            conn = (HttpURLConnection) mUrl.openConnection();
            conn.setRequestMethod("POST");// 设置请求方法为post
            conn.setReadTimeout(5000);// 设置读取超时为5秒
            conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
            conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容
            // 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
            OutputStream out = conn.getOutputStream();
            out.write(content.getBytes());// 获得一个输出流,向服务器写数据
            out.flush();
            out.close();
            int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
            if(responseCode==200){
                InputStream is = conn.getInputStream();
                String response = getStringFromInputStream(is);
                return response;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (conn != null) {
                conn.disconnect();// 关闭连接
            }
        }
        return "no data";
    }

    public static String get(String url,String content) {
        HttpURLConnection conn = null;
        try {
            // 利用string url构建URL对象
            URL mURL = new URL(url);
            conn = (HttpURLConnection) mURL.openConnection();
            conn.setRequestMethod("GET");
            conn.setReadTimeout(5000);
            conn.setConnectTimeout(10000);
            conn.setDoOutput(true);

            OutputStream out = conn.getOutputStream();
            out.write(content.getBytes());
            out.flush();
            out.close();

            int responseCode = conn.getResponseCode();
            if (responseCode == 200) {

                InputStream is = conn.getInputStream();
                String response = getStringFromInputStream(is);
                return response;
            } else {
                throw new NetworkErrorException("response status is "+responseCode);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

    private static String getStringFromInputStream(InputStream is)
            throws IOException {
        ByteArrayOutputStream os = new ByteArrayOutputStream();

        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = is.read(buffer)) != -1) {
            os.write(buffer, 0, len);
        }
        is.close();
        String state = os.toString();// 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
        os.close();
        return state;
    }
}

Activity主线程里处理

网络请求的操作不要放在主线程里,否则会报错“NetworkOnMainThreadException”。

因为这样会阻塞UI线程,故Google不允许这样做。所以需要单独创建一个线程来处理。在onCreate里代码如下:

Button btnPost = (Button)findViewById(R.id.btn_post);
btnPost.setOnClickListener(new View.OnClickListener(){
    @Override
    public void onClick(View v) {
        new Thread(networkTask).start();
    }
});

同时在Activity里添加如下代码:

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        Bundle data = msg.getData();
        String val = data.getString("value");
        //Log.i("mylog", "请求结果为-->" + val);
        // TODO
        // UI界面的更新等相关操作
        Toast.makeText(MainActivity.this,val,Toast.LENGTH_LONG).show();
    }
};

/**
 * 网络操作相关的子线程
 */
Runnable networkTask = new Runnable() {

    @Override
    public void run() {
        // TODO
        // 在这里进行 http request.网络请求相关操作
        NetUtils netUtils = new NetUtils();
        String response = netUtils.get("http://10.0.2.2:80/kjl/Mobie/Index/index","");

        Message msg = new Message();
        Bundle data = new Bundle();
        data.putString("value", "GET请求结果"+response);
        msg.setData(data);
        handler.sendMessage(msg);
    }
};

此外还需注意:

1.在Manifest里添加权限,否则会报“ java.net.SocketException:Permission.denied”

<uses-permission android:name="android.permission.INTERNET" />

2.http服务器在本机时,url不能用localhost或127.0.0.1,因为这样Android会认为其调用的是手机的地址。对此,可用10.0.2.2来代替或者用电脑实际被分配的地址(如:192.168.0.X)

三、URLConnection和HttpURLConnection

URLConnection和HttpURLConnection使用的都是java.net中的类,属于标准的java接口。

HttpURLConnection继承自URLConnection,差别在与HttpURLConnection仅仅针对Http连接。

四、URL类

URL.openConnection()和URL.openStream

String urltext = "";
        try {
//        方法一:  
            URL url = new URL(urltext);
            URLConnection conn = url.openConnection();//取得一个新的链接对指定的URL  
            conn.connect();//本方法不会自动重连  
            InputStream is = conn.getInputStream();
            is.close();//关闭InputStream  
//        方法二:  
            URL url2 = new URL(urltext);
            InputStream is2 = url2.openStream();
            is2.close();//关闭InputStream  
            //URL对象也提供取得InputStream的方法。URL.openStream()会打开自动链接,所以不需要运行openConnection  

            //方法三:本方法同一,但是openConnection返回值直接转为HttpsURLConnection,  
            //这样可以使用一些Http连接特有的方法,如setRequestMethod  
            URL url3 = new URL(urltext);
            HttpsURLConnection conn3 =(HttpsURLConnection)url.openConnection();
            conn3.setRequestMethod("POST");
            //允许Input、Output,不使用Cache  
            conn3.setDoInput(true);
            conn3.setDoOutput(true);
            conn3.setUseCaches(false);  
          /* 
           * setRequestProperty 
           */
            conn3.setRequestProperty("Connection", "Keep-Alive");
            conn3.setRequestProperty("Charset", "UTF-8");
            conn3.setRequestProperty("Content-type", "multipart/form-data;boundary=*****");
            //在与服务器连接之前,设置一些网络参数  
            conn3.setConnectTimeout(10000);

            conn3.connect();
            // 与服务器交互:向服务器端写数据,这里可以上传文件等多个操作  
            OutputStream outStream = conn3.getOutputStream();
            ObjectOutputStream objOutput = new ObjectOutputStream(outStream);
            objOutput.writeObject(new String("this is a string…"));
            objOutput.flush();

            // 处理数据, 取得响应内容  
            InputStream is3 = conn.getInputStream();
            is3.close();//关闭InputStream  
        } catch (IOException e) {
            // TODO Auto-generated catch block  
            e.printStackTrace();
        }

五、使用URL访问网络资源

通过URL.openStream来获取服务器端的图片

在主Activity的layout里添加ImageView控件,在主Activity里通过线程来获取

ImageView show;
Bitmap bitmap;
Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        if(msg.what==0x123){
            show.setImageBitmap(bitmap);
        }
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    fab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
        }
    });

    show = (ImageView)findViewById(R.id.show);
    new Thread(){
        @Override
        public void run() {
            try{
                URL url = new URL("https://www.baidu.com/img/baidu_jgylogo3.gif");
                InputStream is = url.openStream();
                bitmap = BitmapFactory.decodeStream(is);
                handler.sendEmptyMessage(0x123);
                is.close();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }.start();
}

Im

六、通过HttpURLConnection上传文件,同时带参数

public static String form(String serverUrl,List<Map<String,String>> generalField
,List<Map<String,String>> fileField){
    // 每个post参数之间的分隔。随意设定,只要不会和其他的字符串重复即可。
    String BOUNDARY = "----------HV2ymHFg03ehbqgZCaKO6jyH";
    // 向服务器发送post请求
    String strResponse = "";
    try {
        URL url = null;
        url = new URL(serverUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        // 发送POST请求必须设置如下两行
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setUseCaches(false);
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setRequestProperty("Charset", "UTF-8");
        connection.setRequestProperty("Content-Type",
                "multipart/form-data; boundary=" + BOUNDARY);
        // 头
        String boundary = BOUNDARY;
        // 传输内容
        StringBuffer contentBody = new StringBuffer("--" + BOUNDARY);
        // 尾
        String endBoundary = "\r\n--" + boundary + "--\r\n";
        OutputStream out = connection.getOutputStream();
        // 1. 处理文字形式的POST请求
        for (Map<String,String> map : generalField){
            contentBody.append("\r\n")
                    .append("Content-Disposition: form-data; name=\"")
                    .append(map.get("name") + "\"")
                    .append("\r\n")
                    .append("\r\n")
                    .append(map.get("value"))
                    .append("\r\n")
                    .append("--")
                    .append(boundary);
        }
        String boundaryMessage1 = contentBody.toString();
        out.write(boundaryMessage1.getBytes("utf-8"));
        // 2. 处理文件上传
        for (Map<String,String> map : fileField){
            contentBody = new StringBuffer();
            contentBody.append("\r\n")
                    .append("Content-Disposition:form-data; name=\"")
                    .append(map.get("name") + "\"; ") // form中field的名称
                    .append("filename=\"")
                    .append(map.get("value") + "\"") // 上传文件的文件名,包括目录
                    .append("\r\n")
                    .append("Content-Type:application/octet-stream")
                    .append("\r\n\r\n");
            String boundaryMessage2 = contentBody.toString();
            out.write(boundaryMessage2.getBytes("utf-8"));
            // 开始真正向服务器写文件
            File file = new File(map.get("value"));
            DataInputStream dis = new DataInputStream(new FileInputStream(file));
            int bytes = 0;
            byte[] bufferOut = new byte[(int) file.length()];
            bytes = dis.read(bufferOut);
            out.write(bufferOut, 0, bytes);
            dis.close();
            contentBody.append(BOUNDARY);
            String boundaryMessage = contentBody.toString();
            out.write(boundaryMessage.getBytes("utf-8"));
            // System.out.println(boundaryMessage);
        }
        out.write("------------HV2ymHFg03ehbqgZCaKO6jyH--\r\n"
                .getBytes("UTF-8"));
        // 3. 写结尾
        out.write(endBoundary.getBytes("utf-8"));
        out.flush();
        out.close();
        // 4. 从服务器获得回答的内容
        String strLine = "";
        InputStream in = connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        while ((strLine = reader.readLine()) != null){
            strResponse += strLine + "\n";
        }
         System.out.print(strResponse);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return strResponse;
}

publi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值