android学习(二十) 执行网络操作(一) 连接到网络

为了在你的应用进行网络操作,你需要以下权限

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

设计安全网络通信

在你增加网络功能之前,你需要确保数据和信息在你的应用里是安全的,通过网络传输。要做到以下几点:
· 您通过网络传输尽可能减少敏感或个人的的用户数据。
· 根据SSL发送所有的网络数据。


选择HTTP客户端

大部分的网络连接,android应用使用HTTP进行发送和接收数据。android平台包含的HttpsURLConnection端支持TLS,流上传和下载,超时时间配置,IPv6,连接池。


在子线程进行网络操作

为了避免创建一个反应迟钝的UI,不要在UI线程上进行网络操作。默认android3.0(API level 11)和更高版本,在其他线程进行网络操作;如果你不想,会有一个NetworkOnMainThreadException异常。

下面的例子是通过一个不显示的fragment封装异步网络操作。
首先创建一个DownloadCallback接口

public interface DownloadCallback<T> {
    interface Progress{
        //错误
        int ERROR = -1;
        //连接成功
        int CONNECT_SUCCESS = 0;
        //获取inputstream成功
        int GET_INPUT_STREAM_SUCCESS = 1;
        //处理inputstream的进度
        int PROCESS_INPUT_STREAM_IN_PROGRESS = 2;
        //处理inputstream成功
        int PROCESS_INPUT_STREAM_SUCCESS = 3;
    }

    //指示回调处理需要根据任务的结果更新其外观或信息。
    // 预计将从主线程调用。
    void updateFormDownload(T result);

    //从NetworkInfo类获取设备网络状况
    NetworkInfo getActiveNetWorkInfo();

    //指示回调处理一些程序上的更新。
    void onProgressUpdate(int progressCode,int percentComplete);

    //指示下载操作完成。即使这个下载未完成也会调用该方法
    void finishDownloading();
}

然后创建一个NetworkFragment

//实现一个无显示的Fragment,为了从网络上获取数据执行一个异步任务
public class NetworkFragment extends Fragment {
    public static final String TAG = "NetworkFragment";

    private static final String URL_KEY = "UrlKey";

    private DownloadCallback mCallback;
    private DownloadTask mDownloadTask;
    private String mUrlString;

    //静态初始化NetworkFragment,设置将要下载的URL
    public static NetworkFragment getInstance(FragmentManager fragmentManager,String url){
        NetworkFragment networkFragment = (NetworkFragment) fragmentManager
                .findFragmentByTag(NetworkFragment.TAG);
        if(networkFragment == null){
            networkFragment = new NetworkFragment();
            Bundle args = new Bundle();
            args.putString(URL_KEY,url);
            networkFragment.setArguments(args);
            fragmentManager.beginTransaction().add(networkFragment,TAG).commit();
        }
        Log.d("networkFragment","networkFragment创建成功"+networkFragment);
        return networkFragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //在主活动的配置更改中保留此片段
        setRetainInstance(true);
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        //主activity发送一个callback
        //从DownloadTask开始非阻塞执行
        mUrlString = getArguments().getString(URL_KEY);
        cancelDownload();
        mCallback = (DownloadCallback) context;
        mDownloadTask = new DownloadTask(mCallback);
        mDownloadTask.execute(mUrlString);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        //清除引用的主activity,避免存储泄露
        mCallback = null;
    }

    @Override
    public void onDestroy() {
        //当fragment销毁时,取消工作
        cancelDownload();
        super.onDestroy();
    }
    //取消一些正在执行的DownloadTask
    public void cancelDownload() {
        if(mDownloadTask!=null){
            mDownloadTask.cancel(true);
        }
    }
}

创建异步进程类DownloadTask,并且使用HttpsUrlConnection获取数据。

public class DownloadTask extends AsyncTask<String,Void,DownloadTask.Result>{
    private DownloadCallback mCallback;

    DownloadTask(DownloadCallback callback){
        setCallback(callback);
    }

    private void setCallback(DownloadCallback callback){
        mCallback = callback;
    }
    //封装类作为结果和异常的连接。当下载工作完成了,
    //完成或异常任选其一保证非空值。
    //这允许你传递一个异常给UI线程
    static class Result {
        public String mResultValue;
        public Exception mException;
        public Result(String resultValue){
            mResultValue = resultValue;
        }
        public Result(Exception mException){
            this.mException = mException;
        }
    }
    //取消后台网络运行如果我们没有网络连接
    @Override
    protected void onPreExecute() {
        if(mCallback!=null){
            NetworkInfo networkInfo = mCallback.getActiveNetWorkInfo();
            if(networkInfo==null || !networkInfo.isConnected() || (networkInfo.getType()!= ConnectivityManager.TYPE_WIFI
                    &&networkInfo.getType()!=ConnectivityManager.TYPE_MOBILE)){
                //如果没有连接,取消工作和下载作为空值回调
                mCallback.updateFormDownload(null);
                cancel(true);
            }
        }
    }

    //规定在后台执行网络工作
    @Override
    protected DownloadTask.Result doInBackground(String... urls) {
        Result result = null;
        if(!isCancelled() && urls!=null && urls.length>0){
            String urlString = urls[0];
            try {
                URL url = new URL(urlString);
                String resultString = downloadUrl(url);

                if(resultString!=null){
                    result = new Result(resultString);
                } else {
                    throw new IOException("没有接收响应");
                }
            } catch (Exception e) {
                //传递给result一个异常
                result = new Result(e);
            }
        }
        return result;
    }

    //更新DownloadCallback结果
    @Override
    protected void onPostExecute(Result result) {
        if(result!=null&&mCallback!=null){
            if(result.mException!=null){
                mCallback.updateFormDownload(result.mException.getMessage());
            } else if(result.mResultValue!=null){
                mCallback.updateFormDownload(result.mResultValue);
            }
            mCallback.finishDownloading();
        }
    }

    //覆写一个特别的行为取消了后台线程
    @Override
    protected void onCancelled(Result result) {

    }

    private String downloadUrl(URL url) throws IOException {
        InputStream stream = null;
        HttpURLConnection connection = null;
        String result = null;
        try {
            connection = (HttpURLConnection) url.openConnection();
            //读取InputStream设置3000ms超时
            connection.setReadTimeout(3000);
            //连接设置3000ms超时
            connection.setConnectTimeout(3000);
            //设置请求方式为"GET"
            connection.setRequestMethod("GET");
            //默认为true,请求获取的时一个input body
            connection.setDoInput(true);
            connection.connect();
            publishProgress(DownloadCallback.Progress.CONNECT_SUCCESS,0);
            int responseCode = connection.getResponseCode();
            if(responseCode!=HttpURLConnection.HTTP_OK){
                throw new IOException("HTTP错误代码"+responseCode);
            }
            //获取InputStream
            stream = connection.getInputStream();
            publishProgress(DownloadCallback.Progress.GET_INPUT_STREAM_SUCCESS,0);
            if(stream!=null){
                //转换Stream为String最大长度为500
                result = readStream(stream,500);
            }
        } finally {
            //关闭Stream和切断HTTP连接
            if(stream!=null){
                stream.close();
            }
            if(connection!=null){
                connection.disconnect();
            }
        }
        return result;
    }
    //获取stream的处理操作
    private String readStream(InputStream stream, int maxLegth) throws IOException{
        String result = null;
        //设置Inputstream为UTF-8
        InputStreamReader reader = new InputStreamReader(stream,"UTF-8");
        //创建一个临时的buffer 为了根据最大长度掌控数据
        char[] buffer = new char[maxLegth];
        //填入buffer
        int numChars = 0;
        int readSize = 0;
        while (numChars1){
            numChars += readSize;
            int pct = (100*numChars)/maxLegth;
            publishProgress(DownloadCallback.Progress.PROCESS_INPUT_STREAM_IN_PROGRESS,pct);
            readSize = reader.read(buffer,numChars,buffer.length-numChars);
        }
        if(numChars!=-1){
            //stream不为空
            //如果实际长度小于最大长度,则创建响应体的实际长度
            numChars = Math.min(numChars,maxLegth);
            result = new String(buffer,0,numChars);
        }
        return result;
    }

    private void publishProgress(int processInputStreamInProgress, int pct) {
        mCallback.onProgressUpdate(processInputStreamInProgress,pct);
    }
}

最后在activity实例化fragment并复写DownloadCallback里面的方法

public class MainActivity extends FragmentActivity implements DownloadCallback{

    private NetworkFragment mNetworkFragment;
    //Boolean告诉我们在程序里是否有下载操作,避免重复操作。
    private Boolean mDownloading = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mNetworkFragment = NetworkFragment.getInstance(getSupportFragmentManager(),url);
        startDownload();
    }

    private void startDownload(){
        if(!mDownloading&&mNetworkFragment!=null){
            //执行一个异步下载
            mDownloading = true;
        }
    }


    @Override
    public void updateFormDownload(Object result) {
        //根据下载的结果更新UI
    }

    @Override
    public NetworkInfo getActiveNetWorkInfo() {
        //获取设备网络信息
        ConnectivityManager connectivityManager =
                (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        return networkInfo;
    }

    @Override
    public void onProgressUpdate(int progressCode, int percentComplete) {
        switch (progressCode){
            //你可以根据程序的更新,添加UI行为。
            case Progress.ERROR:
                break;
            case Progress.CONNECT_SUCCESS:
                break;
            case Progress.PROCESS_INPUT_STREAM_IN_PROGRESS:
                break;
            case Progress.PROCESS_INPUT_STREAM_SUCCESS:
                break;
        }
    }

    @Override
    public void finishDownloading() {
        mDownloading = false;
        if(mNetworkFragment!=null){
            mNetworkFragment.cancelDownload();
        }
    }
}

摘自android developer

你可能感兴趣的:(android学习)