[转]大话企业级Android应用开发实战 文件下载

                      25  Android文件下载 

25.1  Android文件单线程下载

25.1.1  J2SE文件单线程下载

1.J2SE从网络获取图片

3)源码再现

package com.sharpandroid.junitTest;

 

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import org.junit.Test;

 

public class InternetTest {

    @Test

public void getImage() throws Exception {

                      // 首先我们要得到请求的路径, 路径为我们想要得到的资源

String urlpath = "http://i1.itc.cn/20100326/3b8_921a1797_

8fb1_4551_b4a3_dad3746f53fb_0.jpg";

    URL url = new URL(urlpath);                // 建立URL类对象,抛异常

HttpURLConnection conn = (HttpURLConnection) url.openConnection();

//得到urlConnection对象

    conn.setRequestMethod("GET");                        // 声明请求方式

    conn.setConnectTimeout(6 * 1000);                   // 设置链接超时

    if(conn.getResponseCode() == 200) {

        InputStream inputStream = conn.getInputStream();   

// 得到服务端传回来数据,相对客户为输入流

        byte[] data = readInstream(inputStream);   // 得到数据

        File file = new File("sohu.jpg");             // 创建保存文件

        FileOutputStream outputStream = new FileOutputStream(file);

// 创建一个文件的输出流

            outputStream.write(data);

// 把所得的二进制数据全部写入到我们建好的文件中

            outputStream.close();                           // 关闭输出流

        }

    }

2.J2SE从网络获取文本

1)源码回现

在InternetTest类中添加getHtml()方法,具体代码为:

@Test

    public void getHtml() throws Exception {

                          // 首先我们要得到请求的路径 ,路径为我们想要得到的资源

        String urlpath = "http://www.sohu.com";

        URL url = new URL(urlpath);                       // 建立URL类对象,抛异常

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

// 得到urlConnection对象

        conn.setRequestMethod("GET");                     // 声明请求方式

        conn.setConnectTimeout(6 * 1000);                // 设置链接超时

        if (conn.getResponseCode() == 200) {

            InputStream inputStream = conn.getInputStream();             

//得到输入流

            byte[] data = readInstream(inputStream);    //得到数据

             System.out.println(new String(data));      //将字节转换为字符串打印

在控制台上

        }

    }

3.J2SE从网络获取可执行文件

从网络上获取可执行文件和获取图片很相似,在InternetTest类中添加getFile()方法,具体代码如下:

     @Test

    public void getFile() throws Exception {

                    // 首先我们要得到请求的路径 ,路径为我们想要得到的资源

        String urlpath = "http://ftpcnc-js.pconline.com.cn/pub/download/

201003/Fetion_3.6.1900.exe";

        URL url = new URL(urlpath);                // 建立URL类对象,抛异常

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        // 得到urlConnection对象

        conn.setRequestMethod("GET");                        // 声明请求方式

        conn.setConnectTimeout(6 * 1000);                   // 设置链接超时

        if (conn.getResponseCode() == 200) {

        InputStream inputStream = conn.getInputStream();   

        // 得到输入流

        byte[] data = readInstream(inputStream);          // 得到数据

        File file = new File("feixin.exe");               // 创建保存文件

        FileOutputStream outputStream = new FileOutputStream(file);

        // 创建一个文件的输出流

        outputStream.write(data);

        // 把我们所得的二进制数据全部写入到我们建好的文件中

        outputStream.close();                           // 关闭输出流

        }

    }

25.1.2  Android客户端单线程下载

1.Android客户端从网络获取文本

2)源码再现

第一步:编写res下values中的string.xml文件。

 <?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="hello">Hello World, DataActivity!</string>

    <string name="app_name">从internet中获取数据</string>

    <string name="path">图片路径</string>

<string name="button">获取图片</string>

</resources>

第二步:编写res下Layout中的main.xml文件。

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/path"

    />

  <EditText

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text=" http://i1.itc.cn/20100326/3b8_921a1797_8fb1_4551_

b4a3_dad3746f53fb_0.jpg "

    android:id="@+id/path"

  ></EditText>

  <Button

   android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:text="@string/button"

    android:id="@+id/button"

  ></Button>

  <ImageView

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:id="@+id/ImageView"

  ></ImageView>

</LinearLayout>

第三步:编写核心代码DataActivity.java。

package com.sharpandroid.activity;

 

import com.sharpandroid.net.utils.NetTool;

import android.app.Activity;

import android.content.Intent;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import
android.widget.ImageView;

import android.widget.Toast;

 

  public class DataActivity extends Activity {

    private static final String TAG ="DataActivity";

     private EditText imageEditText;

     private ImageView imageView;

    @Override

public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

imageEditText = (EditText) this.findViewById(R.id.path);

//根据id得到EditText

imageView = (ImageView) this.findViewById(R.id.ImageView);

//根据 id得到imageView

 Button button =  (Button) this.findViewById(R.id.button);

//根据id得到button

 button.setOnClickListener(new View.OnClickListener() {

//给button添加一个单击事件

           

@Override

public void onClick(View v) {

String path = imageEditText.getText().toString();//从imageEditText中取出

路径

    try {

        byte [] data =NetTool.getImage(path);             //得到图片

        Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);

         imageView.setImageBitmap(bm);

    } catch (Exception e) {

         Log.i(TAG, e.getMessage());//有异常打印在控制台上

        Toast.makeText(DataActivity.this, "获取图片失败", 1).show();

        }

       }

});

   }

}    

新建工具类NetTool.java。

package com.sharpandroid.net.utils;

 

import java.io.ByteArrayOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

public class NetTool {

public static byte[] getImage(String path) throws Exception {

                          // 首先我们要得到请求的路径 ,路径为我们想要得到的资源

        URL url = new URL(path);                         // 建立URL类对象,抛

异常

HttpURLConnection conn = (HttpURLConnection) url.openConnection();// 得到

urlConnection对象

        conn.setRequestMethod("GET");                          // 声明请求方式

        conn.setConnectTimeout(6 * 1000);                      // 设置链接超时

        if (conn.getResponseCode() == 200) {

            InputStream inputStream = conn.getInputStream();  // 得到输入流

              return readInstream(inputStream);              // 返回得到的数组

          }

        return null;//

    }

// 读取流文件的内容

    public static byte[] readInstream(InputStream inputStream) throws

Exception {

        ByteArrayOutputStream byteArrayOutputStream =

 new ByteArrayOutputStream();        // 创建ByteArrayOutputStream类

        byte[] buffer = new byte[1024];                         // 声明缓冲区

        int length = -1;// 定义读取默认的长度

         while ((length = inputStream.read(buffer)) != -1) {

            byteArrayOutputStream.write(buffer, 0, length);// 把缓存区中输

出到内存中

        }

       

        byteArrayOutputStream.close();                           // 关闭输出流

        inputStream.close();// 关闭输入流

        return byteArrayOutputStream.toByteArray();// 返回这个输出流的字节数组

    }

 

}

 

2.Android客户端从网络获取文本

1)实现流程

第一步,新添加两个布局文件:gettext.xml和text.xml。

gettext.xml中代码:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

  xmlns:android="http://schemas.android.com/apk/res/android"

  android:layout_width="fill_parent"

  android:layout_height="wrap_content"

  android:orientation="vertical">

  <EditText android:id="@+id/text"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="http://www.sohu.com"

  ></EditText>

  <Button android:id="@+id/textbutton"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:text="@string/textbutton"

  ></Button>

</LinearLayout>

text.xml中的代码:

 <?xml version="1.0" encoding="utf-8"?>

 <ScrollView

   xmlns:android="http://schemas.android.com/apk/res/android"

   android:layout_width=fill_parent"

   android:layout_height="fill_parent"

    android:orientation="vertical">

 

 <TextView android:layout_width="fill_parent"

  android:layout_height="wrap_content"

  android:id="@+id/sohu"/>

</ScrollView>

在main.xml文件中添加一个Button控件:

         <Button android:id="@+id/totextbutton"

           android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:text="@string/toTextButton"

  ></Button>

第二步:

(1)在NetTool.java类中添加方法getHtml()。

    public static String getHtml(String path,String encoding) throws

Exception {

             URL url = new URL(path);          // 建立URL类对象,抛出异常

            HttpURLConnection conn = (HttpURLConnection)

url.openConnection();                          // 得到urlConnection对象

            conn.setRequestMethod("GET");                 // 声明请求方式

            conn.setConnectTimeout(6 * 1000);            // 设置链接超时

            if (conn.getResponseCode() == 200) {

                InputStream inputStream = conn.getInputStream();   

// 得到输入流

                byte[] data = readInstream(inputStream);   // 得到数据

                return new String(data,encoding);

//将字节转换为字符串打印在控制台上

      }

            return null;

}

(2)在DataActivity.java中添加totextbutton的单击事件。

Button totextbutton = (Button) this.findViewById(R.id.totextbutton);

            totextbutton.setOnClickListener(new View.OnClickListener() {

                @Override

                public void onClick(View v) {

                    Intent intent = new Intent(DataActivity.this,

SohuActivity.class);

                    startActivity(intent);

                    }

            });    

(3)在com.sharpandroid.activity中,新建一个继承了android.app.Activity的SohuActivity.  java类。

package com.sharpandroid.activity;

 

import com.sharpandroid.net.utils.NetTool;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

import android.widget.Toast;

 

 public class SohuActivity extends Activity {

    private static final String TAG ="GetTextActivity";

    private EditText editText;

    private Button textButton;

    private TextView textView;

      @Override

    protected void onCreate(Bundle savedInstanceState) {

        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);

        setContentView(R.layout.gettext);

        editText = (EditText) this.findViewById(R.id.text);

        textButton = (Button) this.findViewById(R.id.textbutton);

       

        textButton.setOnClickListener(new View.OnClickListener() {

           

            @Override

            public void onClick(View v) {

               String path = editText.getText().toString();

               try {

                String html = NetTool.getHtml(path,"GBK");

                setContentView(R.layout.text);

                textView = (TextView)SohuActivity.this.findViewById

(R.id.sohu);

                textView.setText(html);

 

                Toast.makeText(SohuActivity.this, "获取文本成功", Toast.

LENGTH_LONG).show();

            } catch (Exception e) {

                 Toast.makeText(SohuActivity.this, "获取文本失败", Toast.

LENGTH_LONG).show();

                e.printStackTrace();

            }

               

           

            }

        });

       

    }

}

25.2  Android文件多线程下载

25.2.1  J2SE文件多线程下载

源码再现:

package junit.test;

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import org.junit.Test;

 

public class DownLoader {

 

    @Test

    public void download() throws Throwable{

        String filename ="qqGame.exe";

        String path="http://dl_dir.qq.com/minigamefile/QQGame2010Beta1

Patch1_setup_web.EXE";

        URL url = new URL(path);

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();

        conn.setConnectTimeout(5*1000);

        conn.setRequestMethod("GET");

        int filelength = conn.getContentLength();  //获取下载文件的长度

        System.out.println(filelength);

       

        RandomAccessFile file = new RandomAccessFile(filename, "rw");

        file.setLength(filelength);                    //设置本地文件的长度

        file.close();

        conn.disconnect();

        int threadsize = 3;                             //线程数

        int threadlength=filelength % 3==0? filelength/3 : filelength/3+1;

//每条线程下载的长度

        for(int i=0; i<threadsize ; i++){

            int startposition = i * threadlength;

//计算每条线程应该从文件的什么位置开始下载

            RandomAccessFile threadfile = new RandomAccessFile(filename,"

rw");

            threadfile.seek(startposition);//从文件的什么位置开始写入数据

            //启动3条线程分别从startposition指定的位置下载文件

            new DownLoadThread(i, path, startposition, threadfile, threadl

ength).start();

        }

        int quit = System.in.read();

        while('q' != quit){        

            Thread.sleep(2*1000);

        }

    }

   

    private class DownLoadThread extends Thread{

        private int threadid;

        private int startposition;

        private RandomAccessFile threadfile;

        private int threadlength;

        private String path;

       

        public DownLoadThread(int threadid, String path, int startposition,

RandomAccessFile threadfile, int threadlength) {

            this.threadid = threadid;

            this.startposition = startposition;

            this.threadfile = threadfile;

            this.threadlength = threadlength;

            this.path = path;

        }

 

        @Override

        public void run() {

            try {

                URL url = new URL(path);

                HttpURLConnection conn = (HttpURLConnection)url.openCon

nection();

                conn.setConnectTimeout(5*1000);

                conn.setRequestMethod("GET");

                conn.setRequestProperty("Range", "bytes="+startposi

tion+ "-");

//指定从文件的什么位置开始下载

                InputStream inStream = conn.getInputStream();

                byte[] buffer = new byte[1024];

                int len = -1;

                int length = 0;

                while(length<threadlength && (len = inStream.read

(buffer))!=-1){

                    threadfile.write(buffer, 0, len);

                    length += len;                         //累计下载的长度

                }

                threadfile.close();

                inStream.close();

                System.out.println("线程"+ (threadid+1)+ "已经下载完

成");

            } catch (Exception e) {

                System.out.println("线程"+ (threadid+1)+ "下载出错:"+ e);

            }

        }

    }

}

 

25.2.2  Android客户端断点、多线程下载

1.准备阶段

String.xml中的代码:

 <?xml version="1.0" encoding="utf-8"?>

<resources>

  <string name="hello">Hello World, DownLoaderActivity!</string>

     <string name="app_name">多线程下载器</string>

     <string name="path">下载路径</string>

     <string name="button">下载</string>

     <string name="success">下载成功</string>

     <string name="fail">下载失败</string>

     <string name="sdcarderror">SDCard不存在或者写保护</string>

</resources>

Main.xml中的代码:

  <?xml version="1.0" encoding="utf-8" ?>

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/

android"

   android:orientation="vertical"

   android:layout_width="fill_parent"

   android:layout_height="fill_parent">

     <TextView android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/path" />

    <EditText android:layout_width="fill_parent"

       android:layout_height="wrap_content"

android:text="http://

bj.itxiazai.com/soft/media/music/ITxiazai_ttpsetup_552.exe"android:id=

"@+id/path" />

  <Button android:layout_width="wrap_content"

     android:layout_height="wrap_content"

     android:text="@string/button"

     android:id="@+id/button" />

  <ProgressBar android:layout_width="fill_parent"

     android:layout_height="18dip"

  style="?android:attr/progressBarStyleHorizontal"

     android:id="@+id/progressBar" />

  <TextView android:layout_width="fill_parent"

     android:layout_height="wrap_content"

     android:gravity="center"

     android:id="@+id/result" />

  </LinearLayout>

2.数据库阶段

1)完成activity中的代码,给button添加单击事件

首先我们把我们页面上需要的控件都找出来。

     public class DownLoaderActivity extends Activity {

   

    private EditText pathText;

    private TextView resultView;

    private ProgressBar progressBar;

    private Button button;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       resultView =  (TextView) this.findViewById(R.id.result);

                                                       //文件的进度的信息

       button = (Button) this.findViewById(R.id.button);

                                                //得到下载按钮

       progressBar =  (ProgressBar)this.findViewById(R.id.downloadbar);

                                                       //得到下载的进度条

       pathText = (EditText) this.findViewById(R.id.path);

                                                       //得到下载路径

      button.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View v) {

            // TODO Auto-generated method stub

           

        }

    });

    }

}

2)在单击事件的onClick()方法中,下载文件并保存到SD卡中

下面是在这个类中的代码:

package com.sharpandroid.service;

 

import android.content.Context;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

 

public class DBOpenHelper extends SQLiteOpenHelper {

    private static final String DBNAME = "sharpandroid.db";

    private static final int VERSION = 1;

   

    public DBOpenHelper(Context context) {

        super(context, DBNAME, null, VERSION);

    }

创建表:

    @Override

    public void onCreate(SQLiteDatabase db) {

        db.execSQL("CREATE TABLE IF NOT EXISTS filedown (id integer primary

key autoincrement, downpath varchar(100), threadid INTEGER, position

INTEGER)");

    }

对表的表本进行更新:

    @Override

    public void onUpgrade(SQLiteDatabase db, int oldVersion,int newVersion){

        db.execSQL("DROP TABLE IF EXISTS filedown");

        onCreate(db);

    }

}

大致:呵呵,还是不错的嘛!下面我来完成在工程中需要的对线程相关的业务操作。

3)对各个线程的下载记录进行操作

FileService.java

import java.util.HashMap;

import java.util.Map;

import android.content.Context;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

/**

 * 业务bean

 *

 */

public class FileService {

    private DBOpenHelper openHelper;

 

    public FileService(Context context) {

        openHelper = new DBOpenHelper(context);

    }

    /**

     * 获取线程最后下载位置

     * @param path

     * @return

     */

    public Map<Integer, Integer> getData(String path){

        SQLiteDatabase db = openHelper.getReadableDatabase();

        Cursor cursor = db.rawQuery("select threadid, position from

filedown where downpath=?", new String[]{path});

        Map<Integer, Integer> data = new HashMap<Integer, Integer>();

        while(cursor.moveToNext()){

            data.put(cursor.getInt(0), cursor.getInt(1));

        }

        cursor.close();

        db.close();

        return data;

    }

    /**

     * 保存下载线程初始位置

     * @param path

     * @param map

     */

    public void save(String path,  Map<Integer, Integer> map){//int

threadid, int position

        SQLiteDatabase db = openHelper.getWritableDatabase();

        db.beginTransaction();

        try{

            for(Map.Entry<Integer, Integer> entry : map.entrySet()){

                db.execSQL("insert into filedown(downpath, threadid,

position) values(?,?,?)",

                    new Object[]{path, entry.getKey(), entry.getValue()});

            }

            db.setTransactionSuccessful();

        }finally{

            db.endTransaction();

        }

        db.close();

    }

    /**

     * 实时更新线程的最后下载位置

     * @param path

     * @param map

     */

    public void update(String path, Map<Integer, Integer> map){

        SQLiteDatabase db = openHelper.getWritableDatabase();

        db.beginTransaction();

        try{

            for(Map.Entry<Integer, Integer> entry : map.entrySet()){

                db.execSQL("update filedown set position=? where downpath=?

and threadid=?",

                        new Object[]{entry.getValue(), path, entry.

getKey()});

            }

            db.setTransactionSuccessful();

        }finally{

            db.endTransaction();

        }

        db.close();

    }

    /**

     * 当文件下载完成后,清掉该文件对应的下载记录

     * @param path

     */

    public void delete(String path){

        SQLiteDatabase db = openHelper.getWritableDatabase();

        db.execSQL("delete from filedown where downpath=?", new Object

[]{path});

        db.close();

    }

   

}

3.实现文件下载阶段

新建com.sharpandroid.net.download包下FileDownloader.java类。

 

package com.sharpandroid.net.download;

 

import java.io.File;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.LinkedHashMap;

import java.util.Map;

import java.util.UUID;

import java.util.concurrent.ConcurrentHashMap;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

import com.sharpandroid.service.FileService;

import android.content.Context;

import android.util.Log;

/**

 * 文件下载器

 */

public class FileDownloader {

    private Context context;

    private FileService fileService;

   

    private static final String TAG = "FileDownloader";

    /* 已下载文件大小 */

    private int downloadSize = 0;

    /* 原始文件大小 */

    private int fileSize = 0;

    /* 线程数 */

    private DownloadThread[] threads;

    /* 下载路径  */

    private URL url;

    /* 本地保存文件 */

    private File saveFile;

    /* 下载记录文件 */

    private File logFile;

    /* 缓存各线程最后下载的位置*/

    private Map<Integer, Integer> data = new ConcurrentHashMap<Integer,

Integer>();

    /* 每条线程下载的大小 */

    private int block;

    private String downloadUrl;//下载路径

    /**

     * 获取线程数

     */

    public int getThreadSize() {

        return threads.length;

    }

    /**

     * 获取文件大小

     * @return

     */

    public int getFileSize() {

        return fileSize;

    }

    /**

     * 累计已下载大小

     * @param size

     */

    protected synchronized void append(int size) {

        downloadSize += size;

    }

    /**

     * 更新指定线程最后下载的位置

     * @param threadId 线程id

     * @param pos 最后下载的位置

     */

    protected void update(int threadId, int pos) {

        this.data.put(threadId, pos);

    }

    /**

     * 保存记录文件

     */

    protected synchronized void saveLogFile() {

        this.fileService.update(this.downloadUrl, this.data);

    }

第三步,构造下载器。

    /**

     * 构建文件下载器

     * @param downloadUrl 下载路径

     * @param fileSaveDir 文件保存目录

     * @param threadNum 下载线程数

     */

    public FileDownloader(Context context,String downloadUrl,File fileSa

veDir,int threadNum) {

        try {

            this.context = context;

            this.downloadUrl = downloadUrl;

            fileService = new FileService(context);

            this.url = new URL(downloadUrl);

            if(!fileSaveDir.exists()) fileSaveDir.mkdirs();

            this.threads = new DownloadThread[threadNum];              

            HttpURLConnection conn = (HttpURLConnection) url.openConn

ection();

            conn.setConnectTimeout(6*1000);

            conn.setRequestMethod("GET");

            conn.setRequestProperty("Accept", "image/gif, image/jpeg,

image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/

xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap,

application/x-ms-application,application/vnd.ms-excel,application/vnd.m

s-powerpoint,

application/msword, */*");

            conn.setRequestProperty("Accept-Language", "zh-CN");

            conn.setRequestProperty("Referer", downloadUrl);

            conn.setRequestProperty("Charset", "UTF-8");

            conn.setRequestProperty("User-Agent","Mozilla/4.0

(compatible;MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

3.5.30729)");

            conn.setRequestProperty("Connection", "Keep-Alive");

            conn.connect();

            printResponseHeader(conn);        //打印返回服务器的响应数据

            if (conn.getResponseCode()==200) {

                this.fileSize = conn.getContentLength();

//根据响应获取文件大小

                if (this.fileSize <= 0) throw new RuntimeException("无法

获知文件大小");

                       

                String filename = getFileName(conn);

                this.saveFile = new File(fileSaveDir, filename);

/* 保存文件 */

                Map<Integer,Integer> logdata = fileService.getData

(downloadUrl);

                if(logdata.size()>0){

                    data.putAll(logdata);

                }

                this.block = this.fileSize / this.threads.length + 1;

                if(this.data.size()==this.threads.length){

                    for (int i = 0; i < this.threads.length; i++) {

                        this.downloadSize += this.data.get(i+1)-(this.

block * i);

                    }

                    print("已经下载的长度"+ this.downloadSize);

                }              

            }else{

                throw new RuntimeException("服务器响应错误 ");

            }

        } catch (Exception e) {

            print(e.toString());

            throw new RuntimeException("连接不到下载路径 ");

        }

    }

    

        /**

     * 获取文件名

     */

    private String getFileName(HttpURLConnection conn) {

        String filename = this.url.toString().substring(this.url.toString

().lastIndexOf('/') + 1);

        if(filename==null || "".equals(filename.trim())){

//如果获取不到文件名称

            for (int i = 0;; i++) {

                String mine = conn.getHeaderField(i);

                if (mine == null) break;

                if("content-disposition".equals(conn.getHeaderFieldKey

(i).toLowerCase())){

                    Matcher m = Pattern.compile(".*filename=(.*)").

matcher(mine.toLowerCase());

                    if(m.find()) return m.group(1);

                }

            }

            filename = UUID.randomUUID()+ ".tmp";//默认取一个文件名

        }

        return filename;

    }

第四步,实现下载功能,并同时可以得到此时各个线程的下载数量。

    /**

     *  开始下载文件

     * @param listener 监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为

null

     * @return 已下载文件大小

     * @throws Exception

     */

    public int download(DownloadProgressListener listener) throws

Exception{

        try {          

            if(this.data.size() != this.threads.length){

                this.data.clear();

                for (int i = 0; i < this.threads.length; i++) {

                    this.data.put(i+1, this.block * i);

                }

            }

            for (int i = 0; i < this.threads.length; i++) {

                int downLength = this.data.get(i+1) - (this.block * i);

                if(downLength < this.block && this.data.get(i+1)<this.

fileSize){        //该线程未完成下载时,继续下载

                    RandomAccessFile randOut = new RandomAccessFile(this.

saveFile, "rw");

                    if(this.fileSize>0) randOut.setLength(this.fileSize);

                    randOut.seek(this.data.get(i+1));

                    this.threads[i] = new DownloadThread(this, this.url,

randOut, this.block, this.data.get(i+1), i+1);

                    this.threads[i].setPriority(7);

                    this.threads[i].start();

                }else{

                    this.threads[i] = null;

                }

            }

            this.fileService.save(this.downloadUrl, this.data);

            boolean notFinish = true;                    //下载未完成

            while (notFinish) {                 // 循环判断是否下载完毕

                Thread.sleep(900);

                notFinish = false;                       //假定下载完成

                for (int i = 0; i < this.threads.length; i++){

                    if (this.threads[i] != null && !this.threads[i].

isFinish()) {

                        notFinish = true;                 //下载没有完成

                        if(this.threads[i].getDownLength() == -1){

//如果下载失败,再重新下载

                            RandomAccessFile randOut = new RandomAcc

essFile(this.saveFile, "rw");

                            randOut.seek(this.data.get(i+1));

                            this.threads[i] = new DownloadThread(this,

this.url, randOut, this.block, this.data.get(i+1), i+1);

                            this.threads[i].setPriority(7);

                            this.threads[i].start();

                        }

                    }

                }              

            if(listener!=null) listener.onDownloadSize(this.downloadSize);

            }

            fileService.delete(this.downloadUrl);

        } catch (Exception e) {

            print(e.toString());

            throw new Exception("下载失败");

        }

        return this.downloadSize;

    }

    /**

     * 获取HTTP响应头字段

     * @param http

     * @return

     */

    public static Map<String, String> getHttpResponseHeader(HttpURLConne

ction http) {

        Map<String, String> header = new LinkedHashMap<String, String>();

        for (int i = 0;; i++) {

            String mine = http.getHeaderField(i);

                                           //得到响应头的各个属性

            if (mine == null) break;

            header.put(http.getHeaderFieldKey(i), mine);

                                              //得到各个属性值

        }

        return header;

    }

    /**

     * 打印HTTP头字段

     * @param http

     */

    public static void printResponseHeader(HttpURLConnection http){

        Map<String, String> header = getHttpResponseHeader(http);

        for(Map.Entry<String, String> entry : header.entrySet()){

            String key = entry.getKey()!=null ? entry.getKey()+":" : "";

            print(key+ entry.getValue());

        }

    }

 

    private static void print(String msg){

        Log.i(TAG, msg);

    }

}

编写DownloadThread.java:

package com.sharpandroid.net.download;

 

import java.io.InputStream;

import java.io.RandomAccessFile;

import java.net.HttpURLConnection;

import java.net.URL;

import android.util.Log;

 

public class DownloadThread extends Thread {

    private static final String TAG = "DownloadThread";

    private RandomAccessFile saveFile;

    private URL downUrl;

    private int block;

    /* 下载开始位置  */

    private int threadId = -1;

    private int startPos;

    private int downLength;

    private boolean finish = false;

    private FileDownloader downloader;

 

    public DownloadThread(FileDownloader downloader, URL downUrl,

RandomAccessFile saveFile, int block, int startPos, int threadId) {

        this.downUrl = downUrl;

        this.saveFile = saveFile;

        this.block = block;

        this.startPos = startPos;

        this.downloader = downloader;

        this.threadId = threadId;

        this.downLength = startPos - (block * (threadId - 1));

    }

   

    @Override

    public void run() {

        if(downLength < block){//未下载完成

            try {

                HttpURLConnection http = (HttpURLConnection) downUrl.

openConnection();

                http.setRequestMethod("GET");

                http.setRequestProperty("Accept", "image/gif,

image/jpeg,image/pjpeg, image/pjpeg, application/x-shockwave-flash,

application/xaml+xml, application/vnd.ms-xpsdocument, application/

x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,applica

tion/vnd.ms-powerpoint, application/msword, */*");

                http.setRequestProperty("Accept-Language", "zh-CN");

                http.setRequestProperty("Referer", downUrl.toString());

                http.setRequestProperty("Charset", "UTF-8");

                http.setRequestProperty("Range", "bytes=" + this.

startPos + "-");

                http.setRequestProperty("User-Agent", "Mozilla/4.0

(compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

3.5.30729)");

                http.setRequestProperty("Connection", "Keep-Alive");

               

                InputStream inStream = http.getInputStream();

                int max = block>1024 ? 1024 : (block>10 ? 10 : 1);

                byte[] buffer = new byte[max];

                int offset = 0;

                print("线程 " + this.threadId + "从位置"+ this.startPos+

"开始下载 ");

                while(downLength < block && (offset=inStream.read(buffer,0,

max)) != -1) {

                    saveFile.write(buffer, 0, offset);

                    downLength += offset;

                    downloader.update(this.threadId, block * (threadId –

1) + downLength);

                    downloader.saveLogFile();

                    downloader.append(offset);

                    int spare = block-downLength;//求剩下的字节数

                    if(spare < max) max = (int) spare;

                }

                saveFile.close();

                inStream.close();          

                print("线程 " + this.threadId + "完成下载 ");

                this.finish = true;

                this.interrupt();

            } catch (Exception e) {

                this.downLength = -1;

                print("线程"+ this.threadId+ ":"+ e);

            }

        }

    }

    private static void print(String msg){

        Log.i(TAG, msg);

    }

    /**

     * 下载是否完成

     * @return

     */

    public boolean isFinish() {

        return finish;

    }

    /**

     * 已经下载的内容大小

     * @return 如果返回值为-1,代表下载失败

     */

    public long getDownLength() {

        return downLength;

    }

}

编写DownloadProgressListener.java:

 package com.sharpandroid.net.download;

 

public interface DownloadProgressListener {

    public void onDownloadSize(int size);

}

完成Activity中的内容:

package com.sharpandroid.download.activity;

 

import java.io.File;

import com.sharpandroid.net.download.DownloadProgressListener;

import com.sharpandroid.net.download.FileDownloader;

import android.app.Activity;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ProgressBar;

import android.widget.TextView;

import android.widget.Toast;

 

public class DownLoaderActivity extends Activity {

    private static final String TAG = "DownLoaderActivity";

    private EditText pathText;

    private ProgressBar progressBar;

    private TextView resultView;

    private Handler handler = new Handler(){

        @Override

        public void handleMessage(Message msg) {

            if(!Thread.currentThread().isInterrupted()){

                switch (msg.what) {

                case 1:

                    int size = msg.getData().getInt("size");

                    progressBar.setProgress(size);//设置当前刻度

                    int result =(int)(((float)progressBar.getProgress()/

(float)progressBar.getMax()) * 100);

                    resultView.setText(result+ "%");

                    if(progressBar.getMax()==progressBar.getProgress()){

                        Toast.makeText(DownLoaderActivity.this, R.

string.success, 1).show();

                    }

                    break;

 

                case -1:

                    String error = msg.getData().getString("error");

                    Toast.makeText(DownLoaderActivity.this, error, 1).

show();

                    break;

                }

               

            }

            super.handleMessage(msg);

        }

    };//用于往线程绑定的消息队列中发送或者处理消息

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        pathText = (EditText)findViewById(R.id.path);

        progressBar = (ProgressBar)findViewById(R.id.progressBar);

        resultView = (TextView)findViewById(R.id.result);

        Button button = (Button)findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {          

            @Override

            public void onClick(View v) {

                //下载文件,并保存到SDCard

                if(Environment.getExternalStorageState().equals

(Environment.MEDIA_MOUNTED)){

                    try {

                        download(pathText.getText().toString(),

Environment.getExternalStorageDirectory());//1

                    } catch (Exception e) {

                        Toast.makeText(DownLoaderActivity.this,

R.string.fail, 1).show();

                        Log.e(TAG, e.toString());

                    }

                }else{

                    Toast.makeText(DownLoaderActivity.this,

R.string.sdcarderror, 1).show();

                }

            }

        });

    }

    //运行在主线程(UI线程负责显示控件的显示更新[重绘界面])

   private void download(final String path, final File saveDir) throws

Exception{

      new Thread(new Runnable() {      

        @Override

        public void run() {

             try {

                FileDownloader downloader = new FileDownloader

(DownLoaderActivity.this, path, saveDir, 3);

                progressBar.setMax(downloader.getFileSize());

//设置进度条的最大刻度

                downloader.download(new DownloadProgressListener() {   

                        @Override

                        public void onDownloadSize(int size) {

//得到文件实时的下载长度

                            Message msg = new Message();

                            msg.what = 1;

                            msg.getData().putInt("size", size);

                            handler.sendMessage(msg);

                        }

                   });

            } catch (Exception e) {

                Message msg = new Message();

                msg.what = -1;

                msg.getData().putString("error", "下载失败");

                handler.sendMessage(msg);

                Log.e(TAG, e.toString());

            }

        }

    }).start();

}

}    

在download方法中的代码:

try {loader.download(new DownloadProgressListener() {                  

                @Override

                public void onDownloadSize(int size) {//得到当前下载的数量                     ...

msg.setData(data);

                    handler.sendMessage(msg);

                }

 

在Handle的内部类的中的代码:

        public void handleMessage(Message msg) {

            if(!Thread.currentThread().isInterrupted()){

                ...

Toast.makeText(DownLoadActivity.this, error, 1).show();

                    break;

                }              

            }

            super.handleMessage(msg);

        }

    };

最后在AndroidManifest.xml加入相关的权限:

  <!--

 访问internet权限

  -->

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

- <!--

 在SDCard中创建与删除文件权限

 -->

  <uses-permission android:name="android.permission.

MOUNT_UNMOUNT_FILESYSTEMS" />

- <!--

 往SDCard写入数据权限

  -->

  <uses-permission android:name="android.permission.

WRITE_EXTERNAL_STORAGE" />

26  Android文件上传 

26.1  Android客户端上传初体验

26.1.1  知识回顾

3.第三步,核心代码实现

新建一个Contact.java类:

package com.sharpandroid.domain;

 

public class Contact {

    private Integer id;

    private String name;

    private short age;

 

    public Contact(){

         

     }

    public Contact(Integer id, String name, short age) {

        super();

        this.id = id;

        this.name = name;

        this.age = age;

    }

 

    public Integer getId() {

        return id;

    }

    public void setId(Integer id) {

        this.id = id;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public short getAge() {

        return age;

    }

    public void setAge(short age) {

        this.age = age;

    }

}

新建ContactAction类图解。

package com.sharpandroid.action;

 

import java.util.ArrayList;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.Action;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import com.sharpandroid.domain.Contact;

 

public class ContactAction extends Action {

 

    @Override

    public ActionForward execute(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

List<Contact> contacts = new ArrayList<Contact>();

           contacts.add(new Contact(01, "laoli", (short) 25));

           contacts.add(new Contact(02, "laozhang", (short) 28));

           contacts.add(new Contact(03,"laowen",(short) 30));

           contacts.add(new Contact(04,"laohou  ",(short) 29));

           request.setAttribute("contacts", contacts);

return mapping.findForward("contacts");

    }

}

26.1.2  Android客户端直通CRM系统

2.第二步,核心代码实现

2)新建一个Contact.java实体类

   package com.sharpandroid.domain;

public class Contact {

   

       private Integer id;

       private String name;

       private short age;

   

       public Contact(){

       

      }

   

    public Contact(Integer id, String name, short age) {

        super();

           this.id = id;

           this.name = name;

           this.age = age;

    }

       public Integer getId() {

           return id;

       }

       public void setId(Integer id) {

           this.id = id;

       }

       public String getName() {

          return name;

       }

       public void setName(String name) {

           this.name = name;

        }

       public short getAge() {

           return age;

        }

       public void setAge(short age) {

           this.age = age;

       }

 

     @Override

      public String toString() {

        return "Contact [age=" + age + ", id=" + id + ", name=" + name

 + "]";

    }

}

代码解析:

分别定义了联系人Contact对象的id、name、age属性,并生成有参数和无参数的构造方法以及相应的set和get方法,为了后面输出的需要,覆盖它的toString方法。

3)建立一个ContactService.java业务bean

 

package com.sharpandroid.service;

 

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.List;

import javax.xml.parsers.SAXParser;

import javax.xml.parsers.SAXParserFactory;

import com.sharpandroid.domain.Contact;

 

 public class ContactService{

      

      /**

     * 获取CRM返回的客户数据

     * @return

     */

private static InputStream requestContact() throws Exception{

      String path = "http://192.168.1.100:8080/CRM/contacts.do";

      URL url = new URL(path);

HttpURLConnection conn =(HttpURLConnection)url.openConnection();

    conn.setConnectTimeout(5 * 1000);

    conn.setRequestMethod("GET");

    return conn.getInputStream();

}

}

4)新建一个继承org.xml.sax.helpers.DefaultHandler的ContactDefaultHandler.java类

package com.sharpandroid.service;

import java.util.ArrayList;

import java.util.List;

import org.xml.sax.Attributes;

import org.xml.sax.SAXException;

import org.xml.sax.helpers.DefaultHandler;

import com.sharpandroid.domain.Contact;

 

public class ContactDefaultHandler extends DefaultHandler {

    private List<Contact> contacts;

    private Contact contact;//记录当前person

    private String preTag;//记录前一个标签的名称

 

    public List<Contact> getContacts() {

        return contacts;

    }

/**

     * 第一个参数为:整个xml字符串

     */

    @Override

    public void characters(char[] ch, int start, int length) throws

 SAXException {

        if(preTag!=null){

            String data = new String(ch, start, length);

            if("name".equals(preTag)){             

                contact.setName(data);

            }else if("age".equals(preTag)){

                contact.setAge(new Short(data));

            }

        }

    }

    //适合在此方法完成初始化行为

    @Override

    public void startDocument() throws SAXException {

        contacts = new ArrayList<Contact>();

    }

@Override

    public void startElement(String uri, String localName, String qName,

Attributes attributes) throws SAXException {

        if("contact".equals(localName)){

            Integer id = new Integer(attributes.getValue(0));

            contact = new Contact();

            contact.setId(id);

        }

        preTag = localName;

    }

 

    @Override

    public void endElement(String uri, String localName, String qName)

 throws SAXException {

        if("contact".equals(localName)){

            contacts.add(contact);

            contact = null;

        }

        preTag = null;

    }

 

}

5)在ContactService类中创建getContacts()方法

        public static List<Contact> getContacts() throws Exception{

          

           InputStream inputStream = requestContact();

           SAXParserFactory factory = SAXParserFactory.newInstance();

           SAXParser saxParser = factory.newSAXParser();

ContactDefaultHandler handler = new ContactDefaultHandler();

           saxParser.parse(inputStream, handler);

           inputStream.close();

           return handler.getContacts();

       }

6)在com.sharpandroid.com.activity中建立单元测试类ContactTest.java

 

public class ContactTest extends AndroidTestCase {

     private static final String TAG = "ContactTest";

 

     public void testContacts() throws Throwable{

        List<Contact> contacts = ContactService.getContacts();

        for(Contact contact : contacts){

            Log.i(TAG, contact.toString());

        }

    }

}

26.2  Android客户端实现请求参数数据上传

26.2.1  知识回顾

2.第二步,核心代码实现

1)新建一个客户信息实体

继承了org.apache.struts.action.ActionForm的ContactForm。

package com.sharpandroid.formbean;

 

import org.apache.struts.action.ActionForm;

 

public class ContactForm extends ActionForm {

   

    private String name;

    private short age;

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public short getAge() {

        return age;

    }

    public void setAge(short age) {

        this.age = age;

    }

}

2)新建一个处理业务操作ContactManageAction.java类

package com.sharpandroid.action;

 

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;

import org.apache.struts.action.ActionForward;

import org.apache.struts.action.ActionMapping;

import org.apache.struts.actions.DispatchAction;

import com.sharpandroid.formbean.ContactForm;

 

   public class ContactManageAction extends DispatchAction {

    //保存数据

    public ActionForward save(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

       

        ContactForm formbean = (ContactForm)form;

        System.out.println("name="+ formbean.getName());//姓名

        System.out.println("age="+ formbean.getAge());//年龄

       

        return mapping.findForward("result");

    }

}

26会那么高呢,原来里面有这么多的学问啊!

第一步,业务分析

新建一个单元测试类。

package com.sharpandroid.test;

 

import java.io.DataOutputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import org.junit.Test;

 

 public class SendDataToCRMTest {

    private String name;

        private Short age;

      @Test

    public void testSave() throws Exception{

       

        save(name,age);

        }

}

新建testSave()单元测试方法:

   private  void save(String name, Short age) throws Exception{

       

            String path ="http://192.168.1.100:8080/CRM/contact/

manage.do";

            String params ="method=save&name=li&age=36";

            byte[] data = params.getBytes();

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.

openConnection();

            conn.setDoOutput(true);            //允许对外发送请求参数

            conn.setUseCaches(false);          //不进行缓存

            conn.setConnectTimeout(5 * 1000);

            conn.setRequestMethod("POST");

                                                   //下面设置http请求头

conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg,

image/pjpeg, application/x-shockwave-flash, application/xaml+xml,

application/vnd.ms-xpsdocument, application/x-ms-xbap, application/vnd.

application/x-ms-application, application/vnd.ms-excel, ms-powerpoint,

 application/msword, */*");

            conn.setRequestProperty("Accept-Language", "zh-CN");

            conn.setRequestProperty("User-Agent", "Mozilla/4.0

(compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

3.5.30729)");

            conn.setRequestProperty("Content-Type", "application/

x-www-form-urlencoded");

    conn.setRequestProperty("Content-Length", String.valueOf

(data.length));

            conn.setRequestProperty("Connection", "Keep-Alive");

                                                                //发送参数

        DataOutputStream outStream = new DataOutputStream

(conn.getOutputStream());

            outStream.write(data);                      //把参数发送出去

            outStream.flush();

            outStream.close();

            if(conn.getResponseCode()==200){

         byte[] returndata =  StreamTool.readInputStream(conn.

getInputStream());

                System.out.print(new String(returndata));

            }

           

        }

}

编写StreamTool.java:

public class StreamTool {

   

    public static byte[] readInputStream(InputStream inputStream) throws

Exception {

        byte[] buffer = new byte[1024];

        int len = -1;

        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();

        while( (len = inputStream.read(buffer)) != -1 ){

            outSteam.write(buffer, 0, len);

        }

        outSteam.close();

        inputStream.close();

        return outSteam.toByteArray();

    }

}

26.2.3  Android客户端之请求参数优化

1.解决Android客户端的中文乱码问题

1)第一种情况,J2EE中表单的post提交上传数据中文乱码问题

用这种方式建立Filter可以自动在web.xml文件中进行配置:

<filter>

        <display-name>EncodingFilter</display-name>

        <filter-name>EncodingFilter</filter-name>

<filter-class>com.sharpandroid.filter.EncodingFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>EncodingFilter</filter-name>

        <url-pattern>*.do</url-pattern>

    </filter-mapping>

程序代码:

   package com.sharpandroid.filter;

   import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

 

public class EncodingFilte implements Filter {

 

public void doFilter(ServletRequest request, ServletResponse response,

FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        req.setCharacterEncoding("UTF-8");

        chain.doFilter(request, response);

    }

 

    public void init(FilterConfig fConfig) throws ServletException {

       

    }

     public void destroy() {

           

    }

3)第三种,解决客户端应用中get方式发送请求参数中文乱码问题

实现代码如下:

   @Test

        public void testGetSendData() throws Throwable{

            //以get方式发送请求参数

            String path = "http://192.168.1.100:8080/CRM/contact/

manage.do?method=save&name="+ URLEncoder.encode("世界","UTF-8") + "

&age=30";

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.

openConnection();

            conn.setConnectTimeout(5 * 1000);

            conn.setRequestMethod("GET");

            if(conn.getResponseCode()==200){

                byte[] data = StreamTool.readInputStream(conn.

getInputStream());

                System.out.println(new String(data));;

            }

}

2.Android客户端post方式发送请求参数优化

post()方法具体代码如下:

public static byte[] post(String path,Map<String, String> params,String

encode) throws Exception{

        StringBuilder paramBuilder = new StringBuilder();

        if(params!=null && !params.isEmpty()){

        for(Map.Entry<String, String> entry : params.entrySet()){

            paramBuilder.append(entry.getKey()).append("=").append

(URLEncoder.encode(entry.getValue(), encode))

             .append("&");

            }

        paramBuilder.deleteCharAt(paramBuilder.length()-1);

        }

        byte[] data = paramBuilder.toString().getBytes();

        URL url = new URL(path);

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();

        conn.setDoOutput(true);//允许对外发送请求参数

        conn.setUseCaches(false);//不进行缓存

        conn.setConnectTimeout(5 * 1000);

        conn.setRequestMethod("POST");

        //下面设置http请求头

        conn.setRequestProperty("Accept", "image/gif, image/jpeg,

image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/

xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, appl

ication/x-ms-application, application/vnd.ms-excel, application/vnd.

ms-powerpoint, application/msword, */*");

        conn.setRequestProperty("Accept-Language", "zh-CN");

        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible;

MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR

2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

3.5.30729)");

        conn.setRequestProperty("Content-Type", "application/x-www-

form-urlencoded");

        conn.setRequestProperty("Content-Length", String.valueOf(data.

length));

        conn.setRequestProperty("Connection", "Keep-Alive");

       

                                                             //发送参数

        DataOutputStream outStream = new DataOutputStream(conn.

getOutputStream());

        outStream.write(data);//把参数发送出去

        outStream.flush();

        outStream.close();

        if(conn.getResponseCode()==200){

            return  StreamTool.readInputStream(conn.getInputStream());

        }

        return null;

    }

}

26.2.4  Android客户端之发送内容实体

1.自定义HTTP协议发送内容实体

核心代码sendXML方法实现:

   /**

     * 发送内容

     * @param path //请求路径

     * @param xml //XML数据

     */

    public static byte[] sendXML(String path, String xml) throws Exception{

        byte[] data = xml.getBytes();              //要发送的实体数据

        URL url = new URL(path);

        HttpURLConnection conn = (HttpURLConnection)url.openConnection();

        conn.setDoOutput(true);                   //允许对外发送请求参数

        conn.setUseCaches(false);                 //不进行缓存

        conn.setConnectTimeout(5 * 1000);

        conn.setRequestMethod("POST");

        //下面设置http请求头

        conn.setRequestProperty("Accept", "image/gif, image/jpeg,

image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/

xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,applicati

on/x-ms-application, application/vnd.ms-excel, application/vnd.ms-

powerpoint, application/msword, */*");

        conn.setRequestProperty("Accept-Language", "zh-CN");

        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible;

MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR

2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

3.5.30729)");

        conn.setRequestProperty("Content-Type", "text/xml; charset=

UTF-8");

        conn.setRequestProperty("Content-Length", String.valueOf(data.

length));

        conn.setRequestProperty("Connection", "Keep-Alive");

       

                                                          //发送参数

        DataOutputStream outStream = new DataOutputStream(conn.

getOutputStream());

        outStream.write(data);                    //把XML数据发送出去

        outStream.flush();

        outStream.close();

        if(conn.getResponseCode()==200){

            return StreamTool.readInputStream(conn.getInputStream());

        }

        return null;

    }

}

2.写一个单元测试方法准备实体并调用sendXML方法

testsendXML()方法源码:

@Test

public void testsendXML()throws Throwable{

        String path = "http://192.168.1.100:8080/CRM/contact/manage.do?

method=getXML";

        String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>

<persons><person id=\"23\"><name>李明</name><age>30</age></person>

</persons>";

        sendXML(path, xml);

    }

3.在CRM客户关系管理系统接受实体

getXML方法源码:

 public ActionForward getXML(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

        InputStream inStream = request.getInputStream();

        byte[] data = StreamTool.readInputStream(inStream);

        String xml = new String(data);

        System.out.println(xml);

        return mapping.findForward("result");

    }

26.2.5  Android客户端发送数据参数到服务器

1.第一种,Android客户端实现post方式发送数据到服务器

1)完成View层

String.xml的代码:

 <?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="hello">Hello World, ContactActivity!</string>

    <string name="app_name">CRM客户端</string>

    <string name="name">姓名</string>

    <string name="age">年龄</string>

    <string name="button">保存</string>

</resources>

Main.xml的代码:

 <?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<TextView 

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/name"

    />

    <EditText android:id="@+id/name"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    ></EditText>

    <TextView 

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    android:text="@string/age"

    />

    <EditText android:id="@+id/age"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    ></EditText>

    <Button android:id="@+id/button"

    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:text="@string/button"

    ></Button>

</LinearLayout>

2)核心代码实现——Controll层

package com.sharpandroid.crm.activity;

 

import com.sharpandroid.service.ContactService;

import android.app.Activity;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

 

public class ContactActivity extends Activity {

    private static final String TAG = "ContactActivity";

    private EditText nameText;

    private EditText ageText;

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        nameText = (EditText) this.findViewById(R.id.name);

        ageText = (EditText) this.findViewById(R.id.age);

        Button button = (Button) this.findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {          

            @Override

            public void onClick(View v) {

                String name = nameText.getText().toString();

                String age = ageText.getText().toString();

                try {

                    ContactService.save(name, new Short(age));

                    Toast.makeText(ContactActivity.this, R.string.

success, 1).show();

                } catch (Exception e) {

                    Toast.makeText(ContactActivity.this, R.string.fail,

1).show();

                    Log.e(TAG, e.toString());

                }

            }

        });

       

    }

}

3)业务模型实现——Model层

在ContactService业务bean中实现数据上传的功能,具体代码如下:

  public static  void save(String name,Short age) throws Exception{

            String path = "http://192.168.1.100:8080/CRM/contact/

manage.do";

            Map<String, String> params = new HashMap<String, String>();

            params.put("method", "save");

            params.put("name", name);

            params.put("age", String.valueOf(age));

       post(path, params, "UTF-8");

       }

(2)params.put("age", String.valueOf(age))

要将age进行类型转换成需要的String类型。

       public static byte[] post(String path,Map<String, String>

params,String encode) throws Exception{

            StringBuilder paramBuilder = new StringBuilder();

            if(params!=null && !params.isEmpty()){

            for(Map.Entry<String, String> entry : params.entrySet()){

                paramBuilder.append(entry.getKey()).append("=").append

(URLEncoder.encode(entry.getValue(), encode))

                 .append("&");

                }

            paramBuilder.deleteCharAt(paramBuilder.length()-1);

            }

            byte[] data = paramBuilder.toString().getBytes();

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.

openConnection();

            conn.setDoOutput(true);//允许对外发送请求参数

            conn.setUseCaches(false);//不进行缓存

            conn.setConnectTimeout(5 * 1000);

            conn.setRequestMethod("POST");

//下面设置http请求头

            conn.setRequestProperty("Accept", "image/gif, image/jpeg,

image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/

xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap,

application/x-ms-application, application/vnd.ms-excel, application/

vnd.ms-powerpoint, application/msword, */*");

            conn.setRequestProperty("Accept-Language", "zh-CN");

            conn.setRequestProperty("User-Agent", "Mozilla/4.0

(compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET

CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR

3.5.30729)");

            conn.setRequestProperty("Content-Type", "application/x-

www-form-urlencoded");

            conn.setRequestProperty("Content-Length", String.valueOf

(data.length));

            conn.setRequestProperty("Connection", "Keep-Alive");

           

                                                     //发送参数

            DataOutputStream outStream = new DataOutputStream(conn.

getOutputStream());

            outStream.write(data);                //把参数发送出去

            outStream.flush();

            outStream.close();

            if(conn.getResponseCode()==200){

              return  StreamTool.readInputStream(conn.getInputStream());

            }

            return null;

        }

2.第二种,Android客户端实现get方式发送数据到服务器

在ContactService业务bean中添加GetSendData()方法:

  public static void GetSendData(String name,Short age) throws Exception{

            //以get方式发送请求参数

            String path = "http://192.168.1.100:8080/CRM/contact/manage.

do?method=save&name="+

                URLEncoder.encode(name,"UTF-8") + "&age="+age;

            URL url = new URL(path);

            HttpURLConnection conn = (HttpURLConnection)url.

openConnection();

            conn.setConnectTimeout(5 * 1000);

            conn.setRequestMethod("GET");

            if(conn.getResponseCode()==200){

                byte[] data = StreamTool.readInputStream(conn.

getInputStream());

                System.out.println(new String(data));;

            }

        }

3.用开源框架实现Android客户端发送实体

在ContactService业务bean添加postFromHttpClient()方法:

   public static byte[] postFromHttpClient(String path, Map<String, String>

 params, String encode) throws Exception{

    List<NameValuePair> formparams = new ArrayList<NameValuePair>();    for(Map.Entry<String, String> entry : params.entrySet()){

         formparams.add(new BasicNameValuePair(entry.getKey(), entry.

getValue()));

            }      

            UrlEncodedFormEntity entity = new UrlEncodedFormEntity

(formparams, "UTF-8");

            HttpPost httppost = new HttpPost(path);

            httppost.setEntity(entity);

            HttpClient httpclient = new DefaultHttpClient();

//看做是浏览器

            HttpResponse response = httpclient.execute(httppost);

//发送post请求     

            return StreamTool.readInputStream(response.getEntity().

getContent());

        }

 

26.3  Android客户端实现文件上传

26.3.1  知识回顾

1)业务模型实现——Model层

在ContactForm中定义上传的参数类型:

Com.sharpandroid.formbean.ContactForm.java

 

public class ContactForm extends ActionForm {

       private String name;

       private Short age;

       private FormFile image;

   

    public FormFile getImage() {

        return image;

    }

    public void setImage(FormFile image) {

        this.image = image;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public Short getAge() {

        return age;

    }

    public void setAge(Short age) {

        this.age = age;

    }

   

}

2)核心代码实现——Controll层

save()方法源码:

public ActionForward save(ActionMapping mapping, ActionForm form,

            HttpServletRequest request, HttpServletResponse response)

            throws Exception {

       ContactForm formbean = (ContactForm)form;

        //System.out.println("get : name="+ new String(request.

getParameter("name").getBytes("ISO-8859-1"),"UTF-8"));

        System.out.println("name="+ formbean.getName());

        System.out.println("age="+ formbean.getAge());

        if(formbean.getImage()!=null && formbean.getImage().

getFileSize()>0){

        String dirRealPath = request.getSession().getServletContext().

getRealPath("/images");

            System.out.println(dirRealPath);

            File dir = new File(dirRealPath);

            if(!dir.exists()) dir.mkdirs();

            File saveFile = new File(dir, formbean.getImage().

getFileName());

            FileOutputStream outStream = new FileOutputStream(saveFile);

            outStream.write(formbean.getImage().getFileData());

            outStream.close();

        }

        return mapping.findForward("result");

    }

3)页面美化——View层

index.jsp页面中的代码:

  <body>

    <form action="${pageContext.request.contextPath}/contact/manage.

do" method="post" enctype="multipart/form-data">

        <input type="hidden" name="method" value="save"/>

        姓名:<input type="text" name="name"/><br/>

        年龄:<input type="text" name="age"/><br/>

        图片:<input type="file" name="image"/><br/>

        <input type="submit" value="保存"/>

    </form>

</body>

26.3.2  Android客户端之文件上传

1)模型实现——Model层

FormFile.java 源代码:

  import java.io.InputStream;

 

/**

 * 上传文件

 */

public class FormFile {

    private byte[] data;

    private InputStream inStream;

    private String filname;

    private String formname;

    private String contentType = "application/octet-stream";

   

    public FormFile(String filname, byte[] data, String formname, String

contentType) {

        this.data = data;

        this.filname = filname;

        this.formname = formname;

        if(contentType!=null) this.contentType = contentType;

    }

   

    public FormFile(String filname, InputStream inStream, String formname,

String contentType) {

        this.filname = filname;

        this.formname = formname;

        this.inStream = inStream;

        if(contentType!=null) this.contentType = contentType;

    }

   

    public InputStream getInStream() {

        return inStream;

    }

 

    public byte[] getData() {

        return data;

    }

 

    public String getFilname() {

        return filname;

    }

 

    public void setFilname(String filname) {

        this.filname = filname;

    }

 

    public String getFormname() {

        return formname;

    }

 

    public void setFormname(String formname) {

        this.formname = formname;

    }

 

    public String getContentType() {

        return contentType;

    }

 

    public void setContentType(String contentType) {

        this.contentType = contentType;

    }

   

}

通过面向HTTP协议,实现如下面表单提交功能,具体的代码如下:

package com.sharpandroid.utils;

 

import java.io.DataOutputStream;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.Map;

   

public class HttpRequester {

    public static String post(String actionUrl, Map<String, String> params,

 FormFile[] files) {

        try {           

            String BOUNDARY = "---------7d4a6d158c9";      //数据分隔线

            String MULTIPART_FORM_DATA = "multipart/form-data";

           

            URL url = new URL(actionUrl);

            HttpURLConnection conn = (HttpURLConnection)

url.openConnection();

            conn.setConnectTimeout(5* 1000);

            conn.setDoInput(true);                      //允许输入

            conn.setDoOutput(true);                    //允许输出

            conn.setUseCaches(false);                  //不使用Cache

            conn.setRequestMethod("POST");          

            conn.setRequestProperty("Connection", "Keep-Alive");

            conn.setRequestProperty("Charset", "UTF-8");

            conn.setRequestProperty("Content-Type", MULTIPART_FORM_DATA

+ "; boundary=" + BOUNDARY);

 

            StringBuilder sb = new StringBuilder();

            for (Map.Entry<String, String> entry : params.entrySet()) {

//构建表单字段内容

                sb.append("--");

                sb.append(BOUNDARY);

                sb.append("\r\n");

                sb.append("Content-Disposition: form-data; name=\""+

entry.getKey() + "\"\r\n\r\n");

                sb.append(entry.getValue());

                sb.append("\r\n");

            }

            DataOutputStream outStream = new DataOutputStream

(conn.getOutputStream());

            outStream.write(sb.toString().getBytes());   //发送表单字段数据

            for(FormFile file : files){                    //发送文件数据

            StringBuilder split = new StringBuilder();

                split.append("--");

                split.append(BOUNDARY);

                split.append("\r\n");

                split.append("Content-Disposition: form-data;name=\""+

file.getFormname()+"\";filename=\""+ file.getFilname() + "\"\r\n");

                split.append("Content-Type: "+ file.getContentType()+"

\r\n\r\n");

                outStream.write(split.toString().getBytes());

                if(file.getInStream()!=null){

                byte[] buffer = new byte[1024];

                int len = 0;

                while((len = file.getInStream().read(buffer))!=-1){

                     outStream.write(buffer, 0, len);

                }

                file.getInStream().close();

                }else{

                outStream.write(file.getData(), 0, file.getData().length);

                }

                outStream.write("\r\n".getBytes());

            }

            byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();

//数据结束标志          

            outStream.write(end_data);

            outStream.flush();

            int cah = conn.getResponseCode();

            if (cah != 200) throw new RuntimeException("请求url失败");

            InputStream is = conn.getInputStream();

            int ch;

            StringBuilder b = new StringBuilder();

            while( (ch = is.read()) != -1 ){

            b.append((char)ch);

            }           

            outStream.close();

            conn.disconnect();

            return b.toString();

        } catch (Exception e) {

        throw new RuntimeException(e);

        }

    }

   

    public static String post(String actionUrl, Map<String, String> params,

FormFile file) {

       return post(actionUrl, params, new FormFile[]{file});

    }

}

HttpRequester.java上传数据模型如下:

     * 直接通过HTTP协议提交数据到服务器,实现如下面表单提交功能

     *   <FORM METHOD=POST ACTION="http://192.168.0.200:8080/ssi/

fileload/test.do" enctype="multipart/form-data">

            <INPUT TYPE="text" NAME="name">

            <INPUT TYPE="text" NAME="id">

            <input type="file" name="imagefile"/>

            <input type="file" name="zip"/>

         </FORM>

     * @param actionUrl 上传路径(注:避免使用localhost或127.0.0.1这样的路径

测试,因为它会指向手机模拟器,你可以使用像http://192.168.1.10:8080这样的路径测试)

     * @param params 请求参数 key为参数名,value为参数值

     * @param file 上传文件

构造一个数据的内容:

{

sb.append("--");

          sb.append(BOUNDARY);

          sb.append("\r\n");

     sb.append("Content-Disposition: form-data; name=\""+ entry.getKey()

 + "\"\r\n\r\n");

          sb.append(entry.getValue());

          sb.append("\r\n");

}

 

sb.append("--");

sb.append(BOUNDARY);

文件可能有很多,我们构造一个,然后去迭代。

split.append("--");

          split.append(BOUNDARY);

          split.append("\r\n");

split.append("Content-Disposition: form-data;name=\""+ file.

getFormname()+"\";filename=\""+ file.getFilname() + "\"\r\n");

          split.append("Content-Type: "+ file.getContentType()+

"\r\n\r\n");

          outStream.write(split.toString().getBytes());

          if(file.getInStream()!=null){

                byte[] buffer = new byte[1024];

                int len = 0;

                while((len = file.getInStream().read(buffer))!=-1){

                     outStream.write(buffer, 0, len);

                }

                file.getInStream().close();

                }else{

                outStream.write(file.getData(), 0, file.getData().length);

                }

outStream.write("\r\n".getBytes());

            }

            byte[] end_data = ("--" + BOUNDARY + "--\r\n").getBytes();//

数据结束标志        

sb.append("--");

sb.append(BOUNDARY);

2)核心代码实现——Controll层

编写ContactActivity.java:

package com.sharpandroid.crm.activity;

 

import java.io.File;

import java.io.FileInputStream;

import com.sharpandroid.service.ContactService;

import com.sharpandroid.utils.FormFile;

import android.app.Activity;

import android.os.Bundle;

import android.os.Environment;

import android.util.Log;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

public class ContactActivity extends Activity {

    private static final String TAG = "ContactActivity";

    private EditText nameText;

    private EditText ageText;

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        nameText = (EditText) this.findViewById(R.id.name);

        ageText = (EditText) this.findViewById(R.id.age);

        Button button = (Button) this.findViewById(R.id.button);

        button.setOnClickListener(new View.OnClickListener() {          

            @Override

            public void onClick(View v) {

                String name = nameText.getText().toString();

                String age = ageText.getText().toString();

                try {

                    String filename = " android.jpg";

                    FileInputStream inStream = new FileInputStream(new

File(Environment.getExternalStorageDirectory(), filename));

                    FormFile file = new FormFile(filename, inStream, "

image", "image/pjpeg");

                    ContactService.save(name, new Short(age), file);

                    Toast.makeText(ContactActivity.this, R.string.

success, 1).show();

                } catch (Exception e) {

                    Toast.makeText(ContactActivity.this, R.string.fail,

1).show();

                    Log.e(TAG, e.toString());

                }

            }

        });

       

    }

}

在ContactActivity.java中构建FormFile ContactActivity.java 关键代码:

String filename = " android.jpg";

FileInputStream inStream = new FileInputStream(new File(Environment.

getExternalStorageDirectory(), filename));

FormFile file = new FormFile(filename, inStream, "image", "image/

pjpeg");

ContactService.save(name, new Short(age), file);

在ContactService.java中完成带文件的save()方法:

public static void save(String name, Short age, FormFile file) throws

Exception{

        String path = "http://192.168.1.100:8080/CRM/contact/manage.do";

        Map<String, String> params = new HashMap<String, String>();

params.put("method", "save");

        params.put("name", name);

        params.put("age", String.valueOf(age));

        HttpRequester.post(path, params, file);

    }

(2)调用HttpRequester中的上传单个文件的post()方法:HttpRequester.post(path, params, file)。

加入访问网络和对SD卡读写的相关的权限:

- <!--

 在SD Card中创建与删除文件权限

  -->

  <uses-permission android:name="android.permission.MOUNT_UNMOUNT_

FILESYSTEMS" />

- <!--

 在SD Card中写入数据权限

 --> 

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_

STORAGE" />

27  Socket编程 

27.3  Socket编程实战——Android聊天室实例

27.3.1  编写PC端工程代码

2.编写服务器端程序代码

1)编写Server.java

import java.awt.BorderLayout;

import javax.swing.*;

import java.awt.event.*;

public class Sever extends JFrame implements ActionListener

{   //服务器端主程序负责界面,以及服务段主线程ServerThread的启动     

    //服务端主线程ServerThread又产生BroadCast及ClientThread线程

    //建立服务器端主界面中所用到的布局方式

    BorderLayout borderLayout1 = new BorderLayout();

    BorderLayout borderLayout2 = new BorderLayout();

   

    JPanel jPanel1 = new JPanel();    //创建面板

    JPanel jPanel2 = new JPanel();

    JButton jButton1 = new JButton(); //创建按钮

    JButton jButton2 = new JButton();

    JScrollPane jScrollPane1 = new JScrollPane();

   

    //创建服务器端接收信息文本框

    static JTextArea jTextArea1 = new JTextArea();

    boolean bool = false, start = false;

   

    //声明ServerThread线程类对象

    ServerThread serverThread;

    Thread thread;

   

    //构造函数,用于初始化

    public Sever()  

    { 

    super("Server");

    //设置内容面板布局方式

        getContentPane().setLayout(borderLayout1);

       

        //初始化按钮组件

        jButton1.setText("启动服务器");

        jButton1.addActionListener(this);

        jButton2.setText("关闭服务器");

        jButton2.addActionListener(this);

       

        //初始化jPanel1面板对象,并向其中加入组件

        this.getContentPane().add(jPanel1, java.awt.BorderLayout.NORTH);

        jPanel1.add(jButton1);

        jPanel1.add(jButton2);

 

        //初始化jPanel2面板对象,并向其中加入组件

        jTextArea1.setText("");

        jPanel2.setLayout(borderLayout2);

        jPanel2.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        jScrollPane1.getViewport().add(jTextArea1);

        this.getContentPane().add(jPanel2, java.awt.BorderLayout.CENTER);

       

        this.setSize(400, 400);  

        this.setVisible(true);

    }

 

    public static void main(String[] args)

    {

        Sever sever = new Sever();

        sever.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

 

    //服务器界面中按钮事件处理

    public void actionPerformed(ActionEvent e)

    {

        if(e.getSource() == jButton1)

       {

            serverThread = new ServerThread();

             serverThread.start();

       }else if(e.getSource() == jButton2){

            bool = false;

            start = false;

            serverThread.finalize();

            this.setVisible(false);

     }

    }

}

2)编写ServerThread.java

import java.net.*;

import java.util.*;

import java.io.*;

public class ServerThread extends Thread        

    //服务器监听端口线程

{

    //声明ServerSocket类对象

    ServerSocket serverSocket; 

    //指定服务器监听端口常量

    public static final int PORT = 8521;

 

    //创建一个Vector对象,用于存储客户端连接的ClientThread对象

    //ClientThread类维持服务器与单个客户端的连接线程

    //负责接收客户端发来的信息

    Vector<ClientThread> clients;

    //创建一个Vector对象,用于存储客户端发送过来的信息

    Vector<Object> messages;

    //声明BroadCast类对象

    //BroadCast类负责服务器向客户端广播消息

    BroadCast broadcast; 

   

    String ip;

    InetAddress myIPaddress=null;

 

    public ServerThread()

    {

    //创建两个Vector数组非常重要

    //clients负责存储所有与服务器建立连接的客户端

    //messages负责存储服务器接收到的未发送出去的全部客户端的信息

        clients=new Vector<ClientThread>();    

        messages=new Vector<Object>();

       

        try

        {

        //创建ServerSocket类对象

            serverSocket = new ServerSocket(PORT);

        }

        catch(IOException E){}

        //获取本地服务器地址信息

        try {

        myIPaddress=InetAddress.getLocalHost();

        }catch (UnknownHostException e){System.out.println(e.

toString());}

        ip = myIPaddress.getHostAddress();

        Sever.jTextArea1.append("服务器地址:"+ ip +

             "端口号:"+String.valueOf(serverSocket.getLocalPort())+"

\n");

       

        //创建广播信息线程并启动

        broadcast = new BroadCast(this);

        broadcast.start();

    }

 

    //注意:一旦监听到有新的客户端创建即new Socket(ip, PORT)被执行,

    //就创建一个ClientThread来维持服务器与这个客户端的连接

     public void run()

     {

         while(true)

         {

             try

             {

               //获取客户端连接,并返回一个新的Socket对象

                 Socket socket = serverSocket.accept();

                

System.out.println(socket.getInetAddress().getHostAddress());

                 //创建ClientThread线程并启动

                 //启动ClientTread之后,可以监听该连接对应的客户端是否发送来消息,

                 //并获取消息

                 ClientThread clientThread=new ClientThread(socket,this);

                 clientThread.start();

                 if(socket!=null)

                 {

                     synchronized (clients)

                     {

                        //将客户端连接加入到Vector数组中保存

                         clients.addElement(clientThread);

                     }

                 }

             }

             catch(IOException E)

             {

                 System.out.println("发生异常:"+E);

                 System.out.println("建立客户端联机失败!");

                 System.exit(2);

             }

         }

     }

 

     public void finalize()   

     {

         try

         {   //关闭serverSocket方法

             serverSocket.close();

         }

         catch(IOException E){}

         serverSocket=null;

     }

}

3)编写ClientThread.java

import java.net.*;

import java.io.*;

public class ClientThread extends Thread          

{  

    //维持服务器与单个客户端的连接线程,负责接收客户端发来的信息

   

    //声明一个新的Socket对象,

    //用于保存服务器端用accept方法得到的客户端的连接

    Socket clientSocket;

   

    //声明服务器端中存储的Socket对象的数据输入/输出流

    DataInputStream in = null;

    DataOutputStream out = null;

   

    //声明ServerThread对象

    ServerThread serverThread;

//    String str;

   

//    public static int ConnectNumber=0;

 

    public ClientThread(Socket socket,ServerThread serverThread)

    {

    clientSocket=socket;  

        this.serverThread=serverThread;

        try

        {

         //创建服务器端数据输入/输出流

            in = new DataInputStream(clientSocket.getInputStream());

            out = new DataOutputStream(clientSocket.getOutputStream());

        }

        catch (IOException e2)

        {

            System.out.println("发生异常"+e2);

            System.out.println("建立I/O通道失败!");

            System.exit(3);

        }

    }

    //该方法监听该连接对应得客户端是否有消息发送

    public void run()

    {

        while(true)

        {

            try

            {

              //读入客户端发送来的信息

                String message=in.readUTF();

                synchronized(serverThread.messages)

                {

                    if(message!=null)

                    {

                       //将客户端发送来得信息存于serverThread的messages数组中

                        serverThread.messages.addElement(message);

                        //在服务器端的文本框中显示新消息

                        Sever.jTextArea1.append(message+'\n');

                    }

                }

            }

            catch(IOException E){break;}

        }

    }

}

4)编写BroadCast.java

import java.io.*;

public class BroadCast extends Thread                 

{   //服务器向客户端广播线程

    //声明ClientThread对象

    ClientThread clientThread;

    //声明ServerThread对象

    ServerThread serverThread;

    String str;

 

    public BroadCast(ServerThread serverThread)

    {

        this.serverThread = serverThread;

    }

   //该方法的作用是不停地向所有客户端发送新消息

    public void run()

    {

        while(true)

        {

            try  

            {

              //线程休眠200 ms

                Thread.sleep(200);

            }

            catch(InterruptedException E){}

         

            //同步化serverThread.messages

            synchronized(serverThread.messages)

            {

              //判断是否有未发的消息

                if(serverThread.messages.isEmpty()){

                  continue;

                }

                //获取服务器端存储的需要发送的第一条数据信息

                str = (String)this.serverThread.messages.firstElement();

            }

            //同步化serverThread.clients

            synchronized(serverThread.clients)

            {

              //利用循环获取服务器中存储的所有建立的与客户端的连接

                for(int i=0;i<serverThread.clients.size();i++)

                {

                    clientThread=(ClientThread)serverThread.clients.

elementAt(i);

                    try

                    {

                       //向记录的每一个客户端发送数据信息

                        clientThread.out.writeUTF(str);

                    }

                    catch(IOException E){}

                }

                //从Vector数组中删除已经发送过的那条数据信息

                this.serverThread.messages.removeElement(str);

            }

        }

    }

}

3.编写PC客户端程序代码

PC客户端包括一个类,Client.java。Client.java的代码如下:

import javax.swing.*;

import java.awt.*;

import java.net.*;

import java.sql.Date;

import java.text.SimpleDateFormat;

import java.io.*;

import java.awt.event.*;

public class Client extends JFrame implements Runnable,ActionListener           

{   //客户端程序

    private static final long serialVersionUID = 1L;

 

    //创建Socket通信端口号常量

    public static final int PORT = 8521;

   

    …

Swing代码生成界面省略

    //声明套接字对象

    Socket socket;

    //声明线程对象

    Thread thread; 

   

    //声明客户器端数据输入/输出流

    DataInputStream in;

    DataOutputStream out;

    //是否登录的标记

    boolean flag=false;

   

    //声明字符串,name存储用户名,chat_txt存储发言信息,chat_in存储从服务器接收到

的信息

    String name,chat_txt,chat_in;

    String ip=null;

   

    //构造方法,生成客户端界面

    public Client()

    {

    …

Swing代码生成界面省略

    }

 

    public static void main(String[] args)

    {

        Client client = new Client();

        client.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

 

    //客户端线程启动后的动作

    public void run()  

    {

     //循环执行,作用是一直监听服务器端是否有消息

        while(true)  

        {

            try

            {

              //读取服务器发送来的数据信息

               chat_in = in.readUTF();

               //将消息并显示在客户端的对话窗口中

               jTextArea1.append(chat_in+"\n\n");

            }

            catch(IOException e){}

        }

    }

   

    //界面按钮的事件处理机制

    public void actionPerformed(ActionEvent e)

    {

    //"进入聊天室"按钮的处理

    if(e.getSource() == loginJButton)

    {

        //获取用户名

        name=jTextField1.getText();

        //获取服务器ip

        ip=jTextField3.getText();

        //判断用户名是否有效及ip是否为空

        if(name!="用户名输入"&&ip!=null)

        {

            try

            {

                //创建Socket对象

                socket = new Socket(ip, PORT);

                //创建客户端数据输入/输出流,用于对服务器端发送或接收数据

                in = new DataInputStream(socket.getInputStream());

                out = new DataOutputStream(socket.getOutputStream());

                Date now = new Date(System.currentTimeMillis());

                  SimpleDateFormat format = new SimpleDateFormat("hh:mm:

ss");

                  String nowStr = format.format(now);

               

                  out.writeUTF("$$"+name +"  "+ nowStr + " 上线了!");

            } catch (IOException e1) {System.out.println("can not

connect");}

            thread = new Thread(this);

            //开启线程,监听服务器端是否有消息

            thread.start();

            //说明已经登录成功

            flag = true;

        }

    }

    //"发送"按钮的处理

    else if(e.getSource() == sendMessageJButton)

    {

       

        //获取客户端输入的发言内容

            chat_txt=jTextField2.getText();

            if(chat_txt!=null)

            {

              Date now = new Date(System.currentTimeMillis());

              SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");

              String nowStr = format.format(now);

              //发言,向服务器发送发言的信息

                try{out.writeUTF("^_^" +jTextField1.getText()+ "  " +

nowStr + " 说\n"+chat_txt);}

                catch(IOException e2){}

            }

            else

            {

                try{out.writeUTF("请说话");}

                catch(IOException e3){}

            }        

    }

    //"退出聊天室"按钮事件的处理

    else if(e.getSource() == leaveJButton)

    {

            if(flag==true)

            {

             

                try

                {

                  out.writeUTF("##"+ name +"下线了!");

                  //关闭socket

                  out.close();

                  in.close();

                  socket.close();

                } catch (IOException e4) {}

            }

            flag=false;

            this.setVisible(false);          

    }

    }

}

27.3.2  编写手机客户端工程代码

2.编写strings.xml

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="hello">Hello World, ChatClientActivity!</string>

    <string name="app_name">聊天室Android客户端</string>

    <string name="username">用户名:</string>

    <string name="ip">服务器IP:</string>

    <string name="login">进入</string>

    <string name="leave">退出</string>

    <string name="send">发送</string>

</resources>

3.编写main.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/

android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

     <TextView

        android:text="@string/username"

        android:layout_width="70px"

        android:layout_height="40px"

        android:id="@+id/usernameText"/>

     <EditText

        android:text=" "

        android:layout_width="180px"

        android:layout_height="40px"

        android:maxLength="10"

        android:layout_toRightOf="@id/usernameText"

        android:id="@+id/username" >

    </EditText>

   

    <Button

    android:layout_width="wrap_content"

    android:layout_height="40px"

    android:text="@string/login"

        android:layout_toRightOf="@id/username"

        android:id="@+id/LoginButton"/>

     

     <TextView

        android:text="@string/ip"

        android:layout_width="70px"

        android:layout_height="40px"

        android:layout_below="@id/username"

        android:layout_alignParentLeft="true"

        android:id="@+id/ipText"/>

     <EditText

        android:text="192.168.1.188"

        android:layout_width="180px"

        android:layout_height="40px"

        android:layout_toRightOf="@id/ipText"

        android:layout_alignTop="@id/ipText"

        android:digits=".1234567890"

        android:id="@+id/ip" >

    </EditText>

    <Button

    android:layout_width="wrap_content"

    android:layout_height="40px"

    android:text="@string/leave"

        android:layout_toRightOf="@id/ip"

        android:layout_alignTop="@id/ip"

        android:id="@+id/LeaveButton"/> 

 

    <EditText

        android:layout_width="fill_parent"

        android:layout_height="280px"

        android:layout_below="@id/ipText"

        android:editable="false"

        android:gravity="top"

        android:id="@+id/history" >

    </EditText>

    <EditText

        android:layout_width="280px"

        android:layout_height="240px"

        android:layout_below="@id/history"

        android:gravity="top"

        android:id="@+id/message" >

    </EditText>

    <Button

    android:layout_width="wrap_content"

    android:layout_height="240px"

    android:text="@string/send"

    android:layout_toRightOf="@id/message"

    android:layout_alignTop="@id/message"

        android:id="@+id/SendButton"/>

</RelativeLayout>

4.编写功能清单文件,添加网络访问权限

编写AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.sharpandroid.chatclient"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/

app_name">

        <activity android:name=".ChatClientActivity"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"

/>

            </intent-filter>

        </activity>

 

    </application>

    <uses-sdk android:minSdkVersion="7" />

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

permission>

</manifest>

5.编写ChatClientActivity.java

package com.sharpandroid.chatclient;

 

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.net.InetAddress;

import java.net.Socket;

import java.sql.Date;

import java.text.SimpleDateFormat;

 

import android.app.Activity;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.Toast;

 

public class ChatClientActivity extends Activity implements Runnable{

    private EditText usernameEdit;

    private EditText ipEdit;

    private EditText historyEdit;

    private EditText messageEdit;

   

    private Button loginButton;

    private Button sendButton;

    private Button leaveButton;

  

    //声明字符串,name存储用户名

    //chat_txt存储发言信息

    //chat_in存储从服务器接收到的信息

    private String username,ip,chat_txt,chat_in;

    //创建Socket通信端口号常量

    public static final int PORT = 8521;

   

     //声明套接字对象

    Socket socket;

   

    //声明线程对象

    Thread thread; 

   

    //声明客户器端数据输入输出流

    DataInputStream in;

    DataOutputStream out;

    //是否登录的标记

    boolean flag=false;

   

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        //获取main.xml文件中定义的一系列组件

        usernameEdit = (EditText) findViewById(R.id.username);

        ipEdit = (EditText) findViewById(R.id.ip);

        historyEdit = (EditText) findViewById(R.id.history);

        messageEdit = (EditText) findViewById(R.id.message);

   

        loginButton = (Button) findViewById(R.id.LoginButton);

        sendButton = (Button) findViewById(R.id.SendButton);

        leaveButton = (Button) findViewById(R.id.LeaveButton);

       

        //为三个按钮注册监听器

        loginButton.setOnClickListener(listener);

        sendButton.setOnClickListener(listener);

        leaveButton.setOnClickListener(listener);

     }

   

    View.OnClickListener listener = new View.OnClickListener() {

       

        @Override

        public void onClick(View v) {

            switch (v.getId()) {

            //"进入聊天室"按钮的处理

            case R.id.LoginButton:

                if(flag == true){

                    Toast.makeText(ChatClientActivity.this,"已经登陆过

了!", Toast.LENGTH_SHORT).show();

                    return;

                }

             //获取用户名

             username = usernameEdit.getText().toString();

             //获取服务器ip

             ip = ipEdit.getText().toString();

             //判断用户名是否有效及ip是否为空

             if(username != "" && username!=null

                     && username!="用户名输入" && ip!=null){

                 try

                 {

                     //创建Socket对象

                     socket = new Socket(ip, PORT);

                     //创建客户端数据输入/输出流,用于对服务器端发送或接收数据

                     in = new DataInputStream(socket.getInputStream());

                     out = new DataOutputStream(socket.getOutputStream());

                    

                     Date now = new Date(System.currentTimeMillis());

                      SimpleDateFormat format = new SimpleDateFormat("

hh:mm:ss");

                      String nowStr = format.format(now);

                    

                      out.writeUTF("$$" + username +"  "+ nowStr + " 上

线了!");

                 } catch (IOException e1) {System.out.println("can not

connect");}

                 thread = new Thread(ChatClientActivity.this);

                 //开启线程,监听服务器段是否有消息

                 thread.start();

                 //说明已经登录成功

                 flag = true;

             }

                break;

            //"发送"按钮的处理

            case R.id.SendButton:

                if(flag ==false){

                       Toast.makeText(ChatClientActivity.this, "没有登录,

请登录!",Toast.LENGTH_SHORT).show();

                       return;

                }

                //获取客户端输入的发言内容

                chat_txt = messageEdit.getText().toString();

                if(chat_txt != null)

                {

                  Date now = new Date(System.currentTimeMillis());

                  SimpleDateFormat format = new SimpleDateFormat("hh:mm:

ss");

                  String nowStr = format.format(now);

                 

                  //发言,向服务器发送发言的信息

                    try{out.writeUTF("^_^" + username+ "  " + nowStr + "

说\n" + chat_txt);}

                    catch(IOException e2){}

                }

                else

                {

                    try{out.writeUTF("请说话");}

                    catch(IOException e3){}

                }        

                break;

            //"退出聊天室"按钮事件的处理

            case R.id.LeaveButton:

                 if(flag==true)

                    {

                     if(flag ==false){

                           Toast.makeText(ChatClientActivity.this, "没有

登录,请登录!",Toast.LENGTH_SHORT).show();

                           return;

                    }

                     try {

                          out.writeUTF("=="+username+"下线了!");

                          //关闭socket

                          out.close();

                          in.close();

                          socket.close();

                        } catch (IOException e4) {}

                    }

                    flag=false;

                    Toast.makeText(ChatClientActivity.this, "已退出!",

Toast.LENGTH_SHORT).show();

                break;

            }

        }

    };

     //客户端线程启动后的动作

    @Override

    public void run() {

         //循环执行,作用是一直监听服务器端是否有消息

        while(true)  

        {

            try

            {

              //读取服务器发送来的数据信息

               chat_in = in.readUTF();

               chat_in = chat_in + "\n";

               //发送一个消息,要求刷新界面

               mHandler.sendMessage(mHandler.obtainMessage());

            }

            catch(IOException e){}

        }

    }

    Handler mHandler = new Handler()

    {                                      

          public void handleMessage(Message msg)

          {    

              //将消息并显示在客户端的对话窗口中

              historyEdit.append(chat_in);

              // 刷新   

              super.handleMessage(msg);    

           

          }

     };

}

28  WebView的介绍及应用  

28.2  WebView浏览网页简单示例

编写strings.xml:

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="hello">请输入网址:</string>

    <string name="app_name">WebView简单示例</string>

    <string name="button">LoadUrl</string>

    <string name="button1">LoadData</string>

</resources>

编写main.xml文件:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

    <TextView 

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/hello"/>

       

        <EditText

            android:id="@+id/path"

            android:layout_width="fill_parent"

            android:layout_height="wrap_content"

            android:text="http://www.baidu.com"/>

     <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/button"

        android:id="@+id/button"/> 

     <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/button1"

        android:id="@+id/button1"/> 

    <WebView

        android:layout_height="fill_parent"

        android:layout_width="fill_parent"

        android:id="@+id/webview"/>

</LinearLayout>

编写WebViewActivity1.java:

package com.sharpandroid.webviewdemo1;

 

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.webkit.WebView;

import android.widget.Button;

import android.widget.EditText;

 

public class WebViewActivity1 extends Activity {

   

    private WebView webView;

    private EditText pathEdit;

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       webView = (WebView) findViewById(R.id.webview);

      

       Button Button = (Button) findViewById(R.id.button);

       //为第一个button添加单击事件

       button.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View v) {

            //获取文本框里的内容

            pathEdit = (EditText) findViewById(R.id.path);

            String path = pathEdit.getText().toString();

            //在WebView中加载指定的路径,路径以“http://”开头

            webView.loadUrl(path); 

        }

    });

      

       Button button1 = (Button) findViewById(R.id.button1);

       //为第二个Button添加单击事件

       button1.setOnClickListener(new View.OnClickListener() {

       @Override

       public void onClick(View v) {

           pathEdit = (EditText) findViewById(R.id.path);

           //定义一个字符串,内容包含一个超链接,指向百度

           String data = "<a href='http://www.baidu.com'>baidu</a>" ;

           //在WebView中加载该数据,数据类型是“text/html”,编码格式是“utf-8”

         webView.loadData(data,"text/html" ,"utf -8");

       }

       });

      

    }

}

为程序添加网络访问权限。编写功能清单文件,内容如下:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.sharpandroid.webviewdemo1"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/

app_name">

        <activity android:name=".WebViewActivity1"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"

/>

            </intent-filter>

        </activity>

    </application>

    <uses-sdk android:minSdkVersion="7" />

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

</manifest>

28.3  WebView浏览网页复杂示例

准备一个名为index.html的HTML文件,放置到工程的“/assets”目录下。文件中包含三种不同的弹出对话框,供WebChromeClient测试使用,内容如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "

http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

    <head>

        <meta http-equiv="Content-Type" content="text/html; charset=

gb2312" />

        <title>测试JavaScript的三种不同对话框</title>

        <script language="JavaScript">

            function alertFun()

            {

                alert("Alert警告对话框!-你好吗?");

            }

            function confirmFun()

            {

                if(confirm("访问搜狐?"))

                {

                    location.href="http://www.sohu.com";

                }

                else

                {

                    alert("取消访问!");

                }

            }

            function promptFun()

            {

                var word =prompt("Prompt对话框","请输入你最想说的一句话:");

                if(word)

                {

                    alert("你说:"+ word)

                }else{

                alert("呵呵,你沉默了!");

                }

            }

        </script>

    </head>

    <body>

        <p>三种对话框示例</p>

        <p>Alert对话框-你好啊!</p>

        <p>

          <input type="submit" name="Submit" value="按钮1" onclick="

alertFun()" />

        </p>

        <p>Confirm对话框-是否访问搜狐!</p>

        <p>

          <input type="submit" name="Submit2" value="按钮2" onclick=

"confirmFun()" />

        </p>

        <p>Prompt对话框-告诉我你想说的话!</p>

        <p>

          <input type="submit" name="Submit3" value="按钮3" onclick=

"promptFun()" />

        </p>

    </body>

</html>

编写strings.xml文件:

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <string name="app_name">WebView示例2</string>

    <string name="hello">请输入网址:</string>

    <string name="button">LoadUrl</string>

</resources>

编写main.xml文件:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

    <TextView 

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="@string/hello"/>

       

    <EditText

        android:id="@+id/path"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:text="file:///android_asset/index.html"/>

   <Button

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="@string/button"

        android:id="@+id/button"/> 

    <WebView

        android:layout_height="fill_parent"

        android:layout_width="fill_parent"

        android:id="@+id/webview"/>

</LinearLayout>

编写prompt_view.xml文件:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:gravity="center_horizontal"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="wrap_content"

    >

    <TextView

        android:id="@+id/text"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"/>

    <EditText

        android:id="@+id/edit"

        android:layout_width="fill_parent"

        android:layout_height="wrap_content"

        android:selectAllOnFocus="true"

        android:scrollHorizontally="true"/>

</LinearLayout>

编写WebViewActivity2.java:

package com.sharpandroid.webviewdemo2;

 

import android.app.Activity;

import android.app.AlertDialog;

import android.app.AlertDialog.Builder;

import android.content.DialogInterface;

import android.os.Bundle;

import android.view.LayoutInflater;

import android.view.View;

import android.view.View.OnClickListener;

import android.webkit.JsPromptResult;

import android.webkit.JsResult;

import android.webkit.WebChromeClient;

import android.webkit.WebSettings;

import android.webkit.WebView;

import android.widget.Button;

import android.widget.EditText;

import android.widget.TextView;

 

public class WebViewActivity2 extends Activity {

    private Button mButton;

    private EditText mEditText;

    private WebView mWebView;

 

    @Override

    public void onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        mButton = (Button) findViewById(R.id.button);

        mEditText = (EditText) findViewById(R.id.path);

        mWebView = (WebView) findViewById(R.id.webview);

       

        //获取WebSettings对象

        WebSettings webSettings = mWebView.getSettings(); 

        //设置支持JavaScript脚本

        webSettings.setJavaScriptEnabled(true);

        //设置可以访问文件

        webSettings.setAllowFileAccess(true);

        //设置支持缩放

        webSettings.setBuiltInZoomControls(true);

       

        //设置WebChromeClient,对网页中 JavaScript代码的各种事件进行处理

        mWebView.setWebChromeClient(new MyWebChromeClient());

       

        //按钮单击事件监听

        mButton.setOnClickListener(new OnClickListener()

        {

            public void onClick(View v)

            {

                //取得编辑框中我们输入的内容

            String url = mEditText.getText().toString();

            mWebView.loadUrl(url);

            }

        });

    }

 

    class MyWebChromeClient extends WebChromeClient {

        @Override

        // 处理javascript中的alert

        public boolean onJsAlert(WebView view, String url, String message,

                final JsResult result) {

            // 构建一个Builder来显示网页中的对话框

            new Builder(WebViewActivity2.this).setTitle("Alert对话框")

            .setMessage(message)

            // android.R.string.ok来自系统自带的文本,内容为“确定”

            .setPositiveButton(android.R.string.ok,

                new AlertDialog.OnClickListener() {

                    public void onClick(DialogInterface dialog,int which) {

                        // 单击确定按钮之后,继续执行网页中的操作

                        result.confirm();

                    }

                })

            .setCancelable(false).show();

            return true;

        };

 

        @Override

        // 处理javascript中的confirm

        public boolean onJsConfirm(WebView view, String url, String

message,

                final JsResult result) {

            new Builder(WebViewActivity2.this)

            .setTitle("Confirm对话框")

            .setMessage(message)

            .setPositiveButton(android.R.string.ok,

                new AlertDialog.OnClickListener() {

                    public void onClick(DialogInterface dialog,int which) {

                        result.confirm();

                    }

                })

                // android.R.string.ok来自系统自带的文本,内容为“取消”

                .setNegativeButton(android.R.string.cancel,

                    new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int

which) {

                            result.cancel();

                        }

                    })

            .setCancelable(false)

            .show();

            return true;

        };

 

        @Override

        // 处理javascript中的prompt

        // message为网页中对话框的提示内容

        // defaultValue在没有输入时,默认显示的内容

        public boolean onJsPrompt(WebView view, String url, String message,

                String defaultValue, final JsPromptResult result) {

            //获得一个LayoutInflater对象factory,该对象可以将指定的xml布局文

件生成相应的对象

            final LayoutInflater factory = LayoutInflater.from

(WebViewActivity2.this);

            // 获取自定义的带输入框的对话框由TextView和EditText构成

            final View dialogView = factory.inflate(R.layout.prompt_view,

null);

            // 设置TextView对应网页中的提示信息

            ((TextView) dialogView.findViewById(R.id.text))

                    .setText(message);

            //为dialogView上的edit输入框 设置来自网页的默认文字

            ((EditText) dialogView.findViewById(R.id.edit))

                    .setText(defaultValue);

 

            new Builder(WebViewActivity2.this)

            .setTitle("Prompt对话框")

            //将前面获取的diaoView这个视图文件添加到对话框上面

            .setView(dialogView)

            .setPositiveButton(android.R.string.ok,

                new AlertDialog.OnClickListener() {

                    public void onClick(DialogInterface dialog,int which){

                        // 单击确定之后,取得输入的值,传给网页处理

                        String value = ((EditText) dialogView.findViewById

(R.id.edit)).getText().toString();

                        result.confirm(value);

                    }

                })

            .setNegativeButton(android.R.string.cancel,

                new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog,intwhich){

                        result.cancel();

                    }

                })

            .show();

            return true;

        };

    }

}

由于在工程中需要访问Internet,因此,添加访问网络权限,编写功能清单文件:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.sharpandroid.webviewdemo2"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/

app_name">

        <activity android:name=".WebViewActivity2"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"

/>

            </intent-filter>

        </activity>

    </application>

    <uses-sdk android:minSdkVersion="7" />

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

permission>

</manifest>

 

28.4  WebView使用HTML替代Layout做界面

2.编写网页文件

在assets目录下新建一个HTML文件phoneui.html,内容如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "

http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>Insert title here</title>

<script type="text/javascript">

    //该部分用到了JavaScript的一些知识,不熟练的读者可以查阅相关书籍

    //或者可由美工做出来之后,进行必要的修改

   

    function show(jsondata){

    //将传递过来的json数据转换为对象

        var jsonobjs = eval(jsondata);

        //获取下面定义的的表格

        var table = document.getElementById("personTable");

        //遍历上面创建的json对象,将每个对象添加为表格中的一行,其每个属性为一列

        for(var i=0; i<jsonobjs.length; i++){

            //添加一行

            var tr = table.insertRow(table.rows.length);

            //添加三个单元格

            var td1 = tr.insertCell(0);

            var td2 = tr.insertCell(1);

            td2.align = "center";

            var td3 = tr.insertCell(2);

            //设置单元格的内容和属性,

            //其中innerHTML为设置或获取位于对象起始和结束标签内的 HTML

            //jsonobjs[i]为对象数组中的第i个对象

            td1.innerHTML = jsonobjs[i].id;

            td2.innerHTML = jsonobjs[i].name

            //为显示的内容添加超链接。

            //超链接会调用Java代码中的call()方法并且把内容作为参数传递过去

            td3.innerHTML = "<a href='javascript:sharp.call(\""+

jsonobjs[i].phone +"\")'>"+jsonobjs[i].phone+ "</a>"; ;

        }

    }

</script>

 

</head>

<!--onload指定了当该页面被加载时调用的方法,本例调用了Java代码中的contactlist方

法--><body bgcolor="#000000" text="#FFFFFF" style="margin:0000"

onload="javascript:sharp.contactlist()">

    <!-- 定义一个表格,显示数据-->

    <table border="0" width="100%" id="personTable" cellspacing="0"

        <tr>

            <td width="15%">编号</td><td align="center">姓名</td><td

width="15%">电话</td>

        </tr>

    </table>

</body>

</html>

3.编写main.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

<WebView

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:id="@+id/webView"

    />

</LinearLayout>

4.编写Contact.java

其代码如下:

package com.sharpandroid.domain;

 

public class Contact {

    private Integer id;

    private String name;

    private String phone;

    public Integer getId() {

        return id;

    }

    public void setId(Integer id) {

        this.id = id;

    }

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public String getPhone() {

        return phone;

    }

    public void setPhone(String phone) {

        this.phone = phone;

    }

    public Contact(Integer id, String name, String phone) {

        this.id = id;

        this.name = name;

        this.phone = phone;

    }

    public Contact(){}

}

5.编写HtmlActivity.Java

HtmlActivity.java

package com.sharpandroid.html;

 

import java.util.ArrayList;

import java.util.List;

 

import org.json.JSONArray;

import org.json.JSONObject;

 

import android.app.Activity;

import android.content.Intent;

import android.net.Uri;

import android.os.Bundle;

import android.webkit.WebView;

 

import com.sharpandroid.domain.Contact;

 

public class HtmlActivity extends Activity {

     private WebView webView;

    /** Called when the activity is first created. */

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        webView = (WebView)this.findViewById(R.id.webView);//浏览器

        webView.getSettings().setJavaScriptEnabled(true);//支持js

        webView.getSettings().setSaveFormData(false);//不保存表单

        webView.getSettings().setSavePassword(false);//不保存密码

        webView.getSettings().setSupportZoom(false);//不支持放大功能

        webView.addJavascriptInterface(new SharpJavaScript(), "sharp");

//addJavascriptInterface方法中要绑定的Java对象

 

        webView.loadUrl("file:///android_asset/index.html");

    }

    public class SharpJavaScript{

    public void contactlist(){

        try {

                String json = buildJson(getContacts());

                webView.loadUrl("javascript:show('"+ json + "')");//调

用js的show()方法

            } catch (Exception e) {

                e.printStackTrace();

            }

    }

   

    public void call(String phone){

    Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+

phone));

        HtmlActivity.this.startActivity(intent);

    }

    }

   

    //模拟从数据库或者从网络获取数据

    public List<Contact> getContacts(){

    List<Contact> contacts = new ArrayList<Contact>();

    contacts.add(new Contact(1, "张三", "5554"));

    contacts.add(new Contact(2, "李四", "5556"));

    contacts.add(new Contact(3, "王五", "5557"));

    return contacts;

    }

    public String buildJson(List<Contact> contacts) throws Exception{

    JSONArray array = new JSONArray();

    for(Contact contact : contacts){

        JSONObject jsonObject = new JSONObject();

        jsonObject.put("id", contact.getId());

        jsonObject.put("name", contact.getName());

        jsonObject.put("phone", contact.getPhone());

        array.put(jsonObject);

    }

    return array.toString();

    }

}

6.添加拨号权限

功能清单文件如下:

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.sharpandroid.phoneuibyhtml"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/

app_name">

        <activity android:name=".PhoneActivity"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

 

    </application>

    <uses-sdk android:minSdkVersion="7" />

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

</manifest>

原文地址:https://www.cnblogs.com/fx2008/p/3132165.html