6.网络编程

tomcat

获取Tomcat安装程序包

tar.gz文件是Linux操作系统下的安装版本

exe文件是Windows系统下的安装版本x86 x64

zip文件是Windows系统下的压缩版本 (建议)

Tomcat启动方式

使用Tomcat服务程序(安装版)

        使用Tomcat程序组中的快捷菜单(安装版)

        使用Tomcat.exe程序(安装版)

        使用批处理程序(使用解压版)

双击 bin 目录下的 startup.bat 文件

输入 http://localhost:8080/,显示网页就成功

无论是开放式目录结构还是打包文件方式发布web应用,web应用的默认URL入口都是Web应用的根目录名。例如要访问MyApp应用,它的URL入口为/MyApp,如访问本地务

pc访问:http://localhost:8080/MyApp(http://127.0.0.1:8080/MyApp)本机ip访问、ip地址也可以

用模拟器加载本机的地址时,可以用 "http://10.0.2.2:8080/dd.jpg"  来替换

如果用手机:用iP地址访问

异步消息处理机制

主线程阻塞

  • 在Android中,主线程被阻塞会导致应用不能刷新ui界面,不能响应用户操作,用户体验将非常差
  • 主线程阻塞时间过长,系统会抛出ANR异常
  • ANR:Application Not Response;应用无响应
  • 任何耗时操作都不可以写在主线程
  • 因为网络交互属于耗时操作,如果网速很慢,代码会阻塞,所以网络交互的代码不能运行在主线程
  • ANR
    • application not responding
    • 应用无响应异常
    • 主线程阻塞时间过长,就会抛出ANR
  • 只有主线程能刷新ui
  • 刷新ui的代码只能运行在主线程,运行在子线程是没有任何效果的
  • 如果需要在子线程中刷新ui,使用消息队列机制

消息队列机制

  • 主线程创建时,系统会同时创建消息队列对象(MessageQueue)和消息轮询器对象(Looper)
  • 轮询器的作用,就是不停的检测消息队列中是否有消息(Message)
  • 消息队列一旦有消息,轮询器会把消息对象传给消息处理器(Handler),处理器会调用handleMessage方法来处理这条消息,handleMessage方法运行在主线程中,所以可以刷新ui
  • 总结:只要消息队列有消息,handleMessage方法就会调用
  • 子线程如果需要刷新ui,只需要往消息队列中发一条消息,触发handleMessage方法即可
  • 子线程使用处理器对象的sendMessage方法发送消息
  • postDelayed(Runnable r, long delayMillis 延时delayMillis毫秒 将Runnable插入消息列队 Runnable将在handle绑定的线程中运行 post 是立即插入消息列队,当消息列队处理到该消息时才运行

WebView的用法

  1. 在布局文件中使用一个新的控件WebView。这个控件当然也就是用来显示网页的了,写法很简单,给它设置了一个 id,并让它充满整个屏幕。
  2. //1.调用WebView的getSettings()方法可以去设置一些浏览器的属性,这里我们并不去
  3. // 设置过多的属性,只是调用了setJavaScriptEnabled()方法来让WebView支持JavaScript脚本。
  4. webView.getSettings().setJavaScriptEnabled(true);
  5. //2.调用WebView的setWebViewClient()方法,并传入了WebViewClient的匿名类作为参数,然后
  6. // 重写了shouldOverrideUrlLoading()方法。这就表明当需要从一个网页跳转到另一个网页时,
  7. // 我们希望目标网页仍然在当前WebView中显示,而不是打开系统浏览器。
  8. webView.setWebViewClient(newWebViewClient(){
  9. @Override
  10. publicboolean shouldOverrideUrlLoading(WebView view,String url){
  11. view.loadUrl(url);// 根据传入的参数再去加载新的网页,这是方法
  12. returntrue;// 表示当前WebView可以处理打开新网页的请求,不用借助系统浏览器
  13. }
  14. });
  15. //3.调用WebView的loadUrl()方法,并将网址传入,即可展示相应网页的内容
  16. webView.loadUrl("http://www.baidu.com");
  17. //4.程序使用到了网络功能,而访问网络是需要声明权限的

对于HTTP协议工作原理:就是客户端向服务器发出一条HTTP请求,服务器收到请求之后会返回一些数据给客户端,然后客户端再对这些数据进行解析和处理就可以了。是不是非常简单?一个浏览器的基本工作原理也就是如此了.WebView控件,其实也就是向百度的服务器发起了一条HTTP请求,接着服务器分析出我们想要访问的是百度的首页,于是会把该网页的HTML代码进行返回,然后WebView再调用手机浏览器的内核对返回的HTML代码进行解析,最终将页面展示出来。简单来说,WebView已经在后台帮我们处理好了发送HTTP请求、接收服务响应、解析返回数据,以及最终的页面展示这几步工作,不过由于它封装得实在是太好了,反而使得我们不能那么直观地看出HTTP协议到底是如何工作的。因此,接下来就让我们通过手动发送HTTP请求的方式,来更加深入地理解一下这个过程。

在Android上发送HTTP请求的方式一般有两种,HttpURLConnection和HttpClient

查看网络图片

publicclassMainActivityextendsActivity{

staticImageView iv;
staticMainActivity ma;
staticHandler handler =newHandler(){
//此方法在主线程中调用,可以用来刷新ui
publicvoid handleMessage(android.os.Message msg){
//处理消息时,需要知道到底是成功的消息,还是失败的消息
switch(msg.what){
case1:
//把位图对象显示至imageview
				iv.setImageBitmap((Bitmap)msg.obj);
break;
//将handler设成静态是节省内存,防止内存溢出,那么imageview也的设成静态,
//而toast方法运行时上下文可能还没有,但是本例子的this是存在的,因为oncreat方法先运行
case0:
Toast.makeText(ma,"请求失败",0).show();
break;
}
}
};
@Override
protectedvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		iv =(ImageView) findViewById(R.id.iv);
		ma =this;
}

publicvoid click(View v){
//下载图片
//1.确定网址
finalString path ="http://192.168.13.13:8080/dd.jpg";
finalFile file =newFile(getCacheDir(), getFileName(path));
//判断,缓存中是否存在该文件
if(file.exists()){
//如果缓存存在,从缓存读取图片
System.out.println("从缓存读取的");
Bitmap bm =BitmapFactory.decodeFile(file.getAbsolutePath());
			iv.setImageBitmap(bm);
}
else{
//如果缓存不存在,从网络下载
System.out.println("从网上下载的");
Thread t =newThread(){
@Override
publicvoid run(){

try{
//2.把网址封装成一个url对象
						URL url =new URL(path);
//3.获取客户端和服务器的连接对象,此时还没有建立连接
HttpURLConnection conn =(HttpURLConnection) url.openConnection();
//4.对连接对象进行初始化
//设置请求方法,注意大写
						conn.setRequestMethod("GET");
//设置连接超时
						conn.setConnectTimeout(5000);
//设置读取超时
						conn.setReadTimeout(5000);
//5.发送请求,与服务器建立连接
						conn.connect();
//如果响应码为200,说明请求成功
if(conn.getResponseCode()==200){
//获取服务器响应头中的流,流里的数据就是客户端请求的数据
InputStream is = conn.getInputStream();

//读取服务器返回的流里的数据,把数据写到本地文件,缓存起来

FileOutputStream fos =newFileOutputStream(file);
byte[] b =newbyte[1024];
int len =0;
while((len = is.read(b))!=-1){
								fos.write(b,0, len);
}
							fos.close();

//读取出流里的数据,并构造成位图对象
//流里已经没有数据了
//							Bitmap bm = BitmapFactory.decodeStream(is);
Bitmap bm =BitmapFactory.decodeFile(file.getAbsolutePath());

Message msg =newMessage();
//消息对象可以携带数据
							msg.obj = bm;
							msg.what =1;

//把消息发送至主线程的消息队列
							handler.sendMessag
}
else{
Message msg = handler.obtainMessage();
							msg.what =0;
							handler.sendMessage(msg);
}
}catch(Exception e){
// TODO Auto-generated catch block
						e.printStackTrace();
}
                   finally { //					if (connection != null) { //						//最后可以调用disconnect()方法将这个HTTP连接关闭掉,如下所示: //						connection.disconnect(); //					}
}
};
			t.start();
}
}

publicString getFileName(String path){
int index = path.lastIndexOf("/");
return path.substring(index +1);
}
}

注意权限  <uses-permission android:name="android.permission.INTERNET"/>

发消息如果消息不需要携带数据,可以发送空消息。例如,让主线程设置listview的适配器,listview处理的消息是list,而list是全局变量handler.sendEmptyMessage(1);

获取开源代码的网站

  • code.google.com
  • github.com
  • 在github搜索smart-image-view
  • 下载开源项目smart-image-view
  • 如果是源码直接把sac目录复制到项目中,如果是jar包把他复制到libs目录下
  • 使用自定义组件时,标签名字要写包名 <com.loopj.android.image.SmartImageView/>
  • SmartImageView的使用 SmartImageView siv =(SmartImageView) findViewById(R.id.siv); siv.setImageUrl("http://192.168.1.102:8080/dd.jpg");

Html源文件查看器

  • 发送GET请求 URL url =new URL(path); //获取连接对象 HttpURLConnection conn =(HttpURLConnection) url.openConnection(); //设置连接属性 conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); //建立连接,获取响应吗 if(conn.getResponseCode()==200){ }
  • 获取服务器返回的流,从流中把html源码读取出来
    1. byte[] b =newbyte[1024];
    2. int len =0;
    3. ByteArrayOutputStream bos =newByteArrayOutputStream();
    4. while((len = is.read(b))!=-1){
    5. //把读到的字节先写入字节数组输出流中存起来
    6. bos.write(b,0, len);
    7. }
    8. //把字节数组输出流中的内容转换成字符串
    9. //默认使用utf-8
    10. text =newString(bos.toByteArray());
    11. 另一种读取的方法
    12. BufferedReader reader =newBufferedReader(newInputStreamReader(is));
    13. StringBuilder builder =newStringBuilder();
    14. String line;
    15. while((line=reader.readLine())!=null){
    16. builder.append(line);
    17. }
    18. String text=builder.toString();

    stringbuilder是个容器,长度的可变的,可以存储不同类型数据,可以对字符串进行修改,它是线程不同步的,通常用于单线程,效率高,当然也用于多线程,只不过是不安全了 乱码的处理

  • 乱码的出现是因为服务器和客户端码表不一致导致 //手动指定码表 text =newString(bos.toByteArray(),"UTF-8");

提交数据

GET方式提交数据

  • get方式提交的数据是直接拼接在url的末尾 finalString path ="http://192.168.1.104/Web/servlet/CheckLogin?name="+ name +"&pass="+pass;
  • 发送get请求,代码和之前一样 URL url =new URL(path); HttpURLConnection conn =(HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); if(conn.getResponseCode()==200){ }
  • 浏览器在发送请求携带数据时会对数据进行URL编码,提交的是中文 String path ="http://192.168.1.104/Web/servlet/CheckLogin?name="+URLEncoder.encode(name)+"&pass="+pass; POST方式提交数据
  • post提交数据是用流写给服务器的
  • 协议头中多了两个属性
    • Content-Type: application/x-www-form-urlencoded,描述提交的数据的mimetype
    • Content-Length: 32,描述提交的数据的长度 注意每条数据都要以键值对的形式存在,数据与数据之间用&符号隔开 //给请求头添加post多出来的两个属性 String data ="name="+URLEncoder.encode(name)+"&pass="+pass; conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded"); conn.setRequestProperty("Content-Length", data.length()+"");
  • 设置允许打开post请求的流 conn.setDoOutput(true);
  • 获取连接对象的输出流,往流里写要提交给服务器的数据,后面都一样 OutputStream os = conn.getOutputStream(); os.write(data.getBytes());

HttpClient

发送get请求

  • 创建一个客户端对象 HttpClient client = new DefaultHttpClient();
  • 创建一个get请求对象 HttpGet hg = new HttpGet(path);
  • 发送get请求,建立连接,返回响应头对象 HttpResponse hr = hc.execute(hg);
  • 获取状态行对象,获取状态码,如果为200则说明请求成功 if(hr.getStatusLine().getStatusCode()==200){ //拿到响应头的实体 InputStreamis= hr.getEntity().getContent(); //拿到服务器返回的输入流 String text =Utils.getTextFromStream(is); }

发送post请求

Thread t =newThread(){
@Override
publicvoid run(){
String path ="http://192.168.13.13/Web/servlet/CheckLogin";
//1.创建客户端对象
HttpClient hc =newDefaultHttpClient();
//2.创建post请求对象
HttpPost hp =newHttpPost(path);

//封装form表单提交的数据
BasicNameValuePair bnvp =newBasicNameValuePair("name", name);
BasicNameValuePair bnvp2 =newBasicNameValuePair("pass", pass);
List<BasicNameValuePair> parameters =newArrayList<BasicNameValuePair>();
//把BasicNameValuePair放入集合中
    	    	parameters.add(bnvp);
    	    	parameters.add(bnvp2);

try{
//要提交的数据都已经在集合中了,把集合传给实体对象
UrlEncodedFormEntity entity =newUrlEncodedFormEntity(parameters,"utf-8");
//设置post请求对象的实体,其实就是把要提交的数据封装至post请求的输出流中
    		    	hp.setEntity(entity);
//3.使用客户端发送post请求
HttpResponse hr = hc.execute(hp);
if(hr.getStatusLine().getStatusCode()==200){
InputStream is = hr.getEntity().getContent();
String text =Utils.getTextFromStream(is);

//发送消息,让主线程刷新ui显示text
Message msg = handler.obtainMessage();
    					msg.obj = text;
    					handler.sendMessage(msg);
}
}catch(Exception e){
// TODO Auto-generated catch block
    				e.printStackTrace();
}
}
};
    	t.start();

异步HttpClient框架

发送get请求

//创建异步的httpclient对象

AsyncHttpClient ahc =newAsyncHttpClient();

//发送get请求

ahc.get(path,newMyHandler());

  • 注意AsyncHttpResponseHandler两个方法的调用时机 classMyHandlerextendsAsyncHttpResponseHandler{ //http请求成功,返回码为200,系统回调此方法 @Override publicvoid onSuccess(int statusCode,Header[] headers, //responseBody的内容就是服务器返回的数据 byte[] responseBody){ Toast.makeText(MainActivity.this,newString(responseBody),0).show(); } //http请求失败,返回码不为200,系统回调此方法 @Override publicvoid onFailure(int statusCode,Header[] headers, byte[] responseBody,Throwable error){ Toast.makeText(MainActivity.this,"返回码不为200",0).show(); } } 发送post请求
  • 使用RequestParams对象封装要携带的数据 //创建异步httpclient对象 AsyncHttpClient ahc =newAsyncHttpClient(); //创建RequestParams封装要携带的数据 RequestParams rp =newRequestParams(); rp.add("name", name); rp.add("pass",pass); //发送post请求 ahc.post(path, rp,newMyHandler());

多线程断点续传下载

原理:服务器CPU分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源

publicclassMainActivityextendsActivity{

staticintThreadCount=3;
staticint finishedThread =0;

int currentProgress;
String fileName ="QQPlayer.exe";
//确定下载地址
String path ="http://192.168.13.13:8080/"+ fileName;
privateProgressBar pb;
TextView tv;

Handler handler =newHandler(){
publicvoid handleMessage(android.os.Message msg){
//把变量改成long,在long下运算
			tv.setText((long)pb.getProgress()*100/ pb.getMax()+"%");
}
};
@Override
protectedvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		pb =(ProgressBar) findViewById(R.id.pb);
		tv =(TextView) findViewById(R.id.tv);
}

publicvoid click(View v){

Thread t =newThread(){
@Override
publicvoid run(){
//发送get请求,请求这个地址的资源
try{
					URL url =new URL(path);
HttpURLConnection conn =(HttpURLConnection) url.openConnection();
					conn.setRequestMethod("GET");
					conn.setConnectTimeout(5000);
					conn.setReadTimeout(5000);

if(conn.getResponseCode()==200){
//拿到所请求资源文件的长度
int length = conn.getContentLength();

//设置进度条的最大值就是原文件的总长度
						pb.setMax(length);

File file =newFile(Environment.getExternalStorageDirectory(), fileName);
//生成临时文件
RandomAccessFile raf =newRandomAccessFile(file,"rwd");
//设置临时文件的大小
						raf.setLength(length);
						raf.close();
//计算出每个线程应该下载多少字节
int size = length /ThreadCount;

for(int i =0; i <ThreadCount; i++){
//计算线程下载的开始位置和结束位置
int startIndex = i * size;
int endIndex =(i +1)* size -1;
//如果是最后一个线程,那么结束位置写死
if(i ==ThreadCount-1){
								endIndex = length -1;
}
//							System.out.println("线程" + i + "的下载区间是:" + startIndex + "---" + endIndex);
newDownLoadThread(startIndex, endIndex, i).start();
}
}
}catch(Exception e){
// TODO Auto-generated catch block
					e.printStackTrace();
}
}
};
		t.start();
}

classDownLoadThreadextendsThread{
int startIndex;
int endIndex;
int threadId;

publicDownLoadThread(int startIndex,int endIndex,int threadId){
super();
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}

@Override
publicvoid run(){
//再次发送http请求,下载原文件
try{
File progressFile =newFile(Environment.getExternalStorageDirectory(), threadId +".txt");
//判断进度临时文件是否存在
if(progressFile.exists()){
FileInputStream fis =newFileInputStream(progressFile);
BufferedReader br =newBufferedReader(newInputStreamReader(fis));
//从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
int lastProgress =Integer.parseInt(br.readLine());
					startIndex += lastProgress;

//把上次下载的进度显示至进度条
					currentProgress += lastProgress;
					pb.setProgress(currentProgress);

//发送消息,让主线程刷新文本进度
					handler.sendEmptyMessage(1);
					fis.close();
}
System.out.println("线程"+ threadId +"的下载区间是:"+ startIndex +"---"+ endIndex);
HttpURLConnection conn;
				URL url =new URL(path);
				conn =(HttpURLConnection) url.openConnection();
				conn.setRequestMethod("GET");
				conn.setConnectTimeout(5000);
				conn.setReadTimeout(5000);
//设置本次http请求所请求的数据的区间
				conn.setRequestProperty("Range","bytes="+ startIndex +"-"+ endIndex);

//请求部分数据,相应码是206
if(conn.getResponseCode()==206){
//流里此时只有1/3原文件的数据
InputStream is = conn.getInputStream();
byte[] b =newbyte[1024];
int len =0;
int total =0;
//拿到临时文件的输出流
File file =newFile(Environment.getExternalStorageDirectory(), fileName);
RandomAccessFile raf =newRandomAccessFile(file,"rwd");
//把文件的写入位置移动至startIndex
					raf.seek(startIndex);
while((len = is.read(b))!=-1){
//每次读取流里数据之后,同步把数据写入临时文件
						raf.write(b,0, len);
						total += len;
System.out.println("线程"+ threadId +"下载了"+ total);

//每次读取流里数据之后,把本次读取的数据的长度显示至进度条
						currentProgress += len;
						pb.setProgress(currentProgress);
//发送消息,让主线程刷新文本进度
						handler.sendEmptyMessage(1);

//生成一个专门用来记录下载进度的临时文件
RandomAccessFile progressRaf =newRandomAccessFile(progressFile,"rwd");
//每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
						progressRaf.write((total +"").getBytes());
						progressRaf.close();
}
System.out.println("线程"+ threadId +"下载完毕-------------------小志参上!");
					raf.close();

					finishedThread++;
synchronized(path){
//三条线程都下载完毕之后,删除缓存文件
if(finishedThread ==ThreadCount){
for(int i =0; i <ThreadCount; i++){
File f =newFile(Environment.getExternalStorageDirectory(), i +".txt");
								f.delete();
}
							finishedThread =0;
}
}
}
}catch(Exception e){
// TODO Auto-generated catch block
				e.printStackTrace();
}
}
}
}

多线程断点续传 1.定义进度条,定义文字显示进度,按钮开始下载 2.加俩个权限,访问网络和读取sd卡 3.定义全局变量线程数和hander用于修改textview 4.在按钮监听事件中: ①开启子线程,请求网络,请求成功后获取返回资源的长度 ②设置进度条的最大值就是资源长度,并发送 ③生成临时文件,设置每个线程的开始和结束位置,再几条开启线程用来下载,将开始,结束和线程id成为它的构造函数的参数 5.在新线程中: ①读取进度文件的大小,如果存在就将开始位置改变 ②再次请求网络,读取资源并写入临时文件,写入的位置移动到开始位置,将读取的进度设置进进度条并发送,到这里下载完成了 ③断点续传需要文件记录住文件下载了的大小,生成专门记录文件大的进度文件,并写进去 ④下载完删除进度文件

HttpUtils的使用

HttpUtils本身就支持多线程断点续传,使用起来非常的方便

  • 创建HttpUtils对象 HttpUtils http =newHttpUtils();
  • 下载文件 http.download(url,//下载请求的网址 target,//下载的数据保存路径和文件名 true,//是否开启断点续传 true,//如果服务器响应头中包含了文件名,那么下载完毕后自动重命名 newRequestCallBack<File>(){//侦听下载状态 //下载成功此方法调用,不是请求成功, @Override publicvoid onSuccess(ResponseInfo<File> arg0){ tv.setText("下载成功"+ arg0.result.getPath());//弹出结果路径 } //下载失败此方法调用,比如文件已经下载、没有网络权限、文件访问不到,方法传入一个字符串参数告知失败原因 @Override publicvoid onFailure(HttpException arg0,String arg1){ tv.setText("下载失败"+ arg1);//下载失败的原因 } //在下载过程中不断的调用,用于刷新进度条 @Override publicvoid onLoading(long total,long current,boolean isUploading){ super.onLoading(total, current, isUploading); //设置进度条总长度 pb.setMax((int) total); //设置进度条当前进度 pb.setProgress((int) current); tv_progress.setText(current *100/ total +"%"); } });

访问网络写在公共的类

因为一个应用程序很可能会在许多地方都使用到网络功能, 而发送 HTTP请求的代码基本都是相同的,如果每次都去编写一遍发送 HTTP请求的代码,这显然是非常差劲的做法。通常情况下我们都应该将这些通用的网络操作提取到一个公共的类里,并提供一个静态方法,当想要发起网络请求的时候只需简单地调用一下这个方法即可。比如使用如下的写法:

1.首先需要定义一个接口,比如将它命名成 HttpCallbackListener,代码如下所示:

public interface HttpCallbackListener {

void onFinish(String response);

void onError(Exception e);

}

可以看到,我们在接口中定义了两个方法,onFinish()方法表示当服务器成功响应我们请求的时候调用, onError()表示当进行网络操作出现错误的时候调用。 这两个方法都带有参数,onFinish()方法中的参数代表着服务器返回的数据,而 onError()方法中的参数记录着错误的详细信息。

2.HTTPutils

conn.conntion连接不知要不要写,书上没写,视频里写了,如果要写就写在urlConn.setDoOutput(true);后面

publicclassHttpUtil{
publicstaticvoid sendHttpRequest(finalString address,
finalHttpCallbackListener listener){
newThread(newRunnable(){
@Override
publicvoid run(){
HttpURLConnection connection =null;
try{
					URL url =new URL(address);
					connection =(HttpURLConnection) url.openConnection();
					connection.setRequestMethod("GET");
					connection.setConnectTimeout(8000);
					connection.setReadTimeout(8000);
					connection.setDoInput(true);
					connection.setDoOutput(true);

InputStream in = connection.getInputStream();
BufferedReader reader =newBufferedReader(
newInputStreamReader(in));
StringBuilder response =newStringBuilder();
String line;
while((line = reader.readLine())!=null){
						response.append(line);
}
if(listener !=null){
// 回调onFinish()方法
						listener.onFinish(response.toString());
}
}catch(Exception e){
if(listener !=null){
// 回调onError()方法
						listener.onError(e);
}
}finally{
if(connection !=null){
						connection.disconnect();
}
}
}
}).start();
}
}

首先给 sendHttpRequest()方法添加了一个 HttpCallbackListener参数,并在方法的内部开启了一个子线程,然后在子线程里去执行具体的网络操作。注意子线程中是无法通过return语句来返回数据的,因此这里我们将服务器响应的数据传入了 HttpCallbackListener的onFinish()方法中,如果出现了异常就将异常原因传入到 onError()方法中。

3.现在 sendHttpRequest()方法接收两个参数了,因此我们在调用它的时候还需要将HttpCallbackListener的实例传入,如下所示:

HttpUtil.sendHttpRequest(address,newHttpCallbackListener(){
@Override
publicvoid onFinish(String response){
// 在这里根据返回内容执行具体的逻辑
}
@Override
publicvoid onError(Exception e){
// 在这里对异常情况进行处理
}
});

这样的话,当服务器成功响应的时候我们就可以在 onFinish()方法里对响应数据进行处理了,类似地,如果出现了异常,就可以在 onError()方法里对异常情况进行处理。如此一来,我们就巧妙地利用回调机制将响应数据成功返回给调用方了。

另外需要注意的是,onFinish()方法和 onError()方法最终还是在子线程中运行的,因此我们不可以在这里执行任何的 UI操作,如果需要根据返回的结果来更新 UI,则仍然要使用异步消息处理机制。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏刘望舒

Android系统启动流程(四)Launcher启动过程与系统启动流程

前言 此前的文章我们学习了init进程、Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:L...

2278
来自专栏向治洪

Universal-Image-Loader完全解析--从源代码分析Universal-Image-Loader中的线程池

一般来讲一个网络访问就需要App创建一个线程来执行,但是这也导致了当网络访问比较多的情况下,线程的数目可能积聚增多,虽然Android系统理论上说可以创建无数...

19110
来自专栏我的博客

安卓开发之调试程序

一、DDMS中LogCat(这样就能调试程序了) 代码下方显示LogCat,windows/show view/other选中logcat点击ok就会在代码下面...

3528
来自专栏酷玩时刻

支付宝Wap支付你了解多少?

为了方便开发者生成一对RSA密钥支付宝提供一键生成工具,具体如何生成与配置密钥详见签名专区。

2732
来自专栏MelonTeam专栏

一种下载管理方案的设计与实现

导语: 4G时代流量资费大幅下降,各种“WBQ”卡惊艳出世——在此背景下,下载对于移动端已不再是一种昂贵的高成本行为。同时EMMC、UFS等存储介质的发展也...

28311
来自专栏Android群英传

Google I/O 之 Android App Bundles 是个啥

2992
来自专栏Android-JessYan

看到如此多的MVP+Dagger2+Retrofit+Rxjava项目,轻松拿star,心动了吗?

原文地址: http://www.jianshu.com/p/4bbecd0bb027

4143
来自专栏Jerry的SAP技术分享

Cordova插件中JavaScript代码与Java的交互细节介绍

在Cordova官网中有这么一张架构图:大家看右下角蓝色的矩形框"Custom Plugin"——自定义插件。意思就是如果您用Cordova打包Mobile应用...

902
来自专栏月牙寂

k8s源码分析-----kubectl(3)主要框架

第一时间获取文章,可以关注本人公众号 月牙寂道长 yueyajidaozhang

5984
来自专栏Android开发指南

很全面的Android面试题

2.6K7

扫码关注云+社区