首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >6.网络编程

6.网络编程

作者头像
六月的雨
发布于 2018-05-14 01:41:35
发布于 2018-05-14 01:41:35
1.1K00
代码可运行
举报
文章被收录于专栏:Android开发指南Android开发指南
运行总次数:0
代码可运行

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

查看网络图片

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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请求

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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分配给每条线程的时间片相同,服务器带宽平均分配给每条线程,所以客户端开启的线程越多,就能抢占到更多的服务器资源

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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);后面

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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的实例传入,如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HttpUtil.sendHttpRequest(address,newHttpCallbackListener(){
@Override
publicvoid onFinish(String response){
// 在这里根据返回内容执行具体的逻辑
}
@Override
publicvoid onError(Exception e){
// 在这里对异常情况进行处理
}
});

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

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-10-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
腾讯SaaS加速器二期成员微盛·企微管家完成亿元级融资,腾讯红杉再度加码企业微信服务赛道|腾讯SaaS加速器·学员动态
来源 |腾讯SaaS加速器二期项目-微盛·企微管家 ---- 2021年1月29日,企业微信服务商 微盛·企微管家(腾讯SaaS加速器二期学员)发布消息,宣布完成由腾讯领投、红杉中国跟投的亿元级A+轮融资,继上轮腾讯和红杉的投资仅隔5个月;微盛创始人杨明表示,本轮融资主要用于产品研发和服务团队建设,继续夯实微盛在赛道中的领先优势。 对于本次投资,红杉资本中国基金合伙人郑庆生表示:企业微信的生态在2020年取得了长足的发展,建立了与消费者和工作者的强大连接能力,基于这种能力,企业能够构·成绩,并且取得
腾讯SaaS加速器
2021/01/29
8160
微盛·企微管家再获3亿元融资,继续领跑企业微信SCRM赛道
近日,微盛·企微管家宣布完成3亿元B1和B2轮融资,本轮融资由IDG领投,众为等机构跟投。对于本次投资,众为资本表示:“微盛是企业微信生态中的头部企业,基于大量的客户实践,形成了优秀的产品和服务体系。我们期待微盛继续扩大领先优势,助力企业微信的增长,以更好地推动各行业数智化客户经营能力的发展。”
微盛企微管家
2022/04/01
1K0
微盛·企微管家再获3亿元融资,继续领跑企业微信SCRM赛道
微盛企微管家客户案例:单店收益提升50%,悸动烧仙草是如何用好企业微信做增长?
伴随日益升级的消费需求,中国现制茶饮行业近年来迎来了飞速的增长,茶饮行业百花齐放。剧烈的竞争之下,开展线上渠道布局,通过精细化的用户运营提高客户粘性和复购率,成为现制茶饮企业实现增长的重要途径。
布鲁斯8号
2022/05/19
6480
微盛企微管家客户案例:单店收益提升50%,悸动烧仙草是如何用好企业微信做增长?
微盛·企微管家携手企业微信参加2021第六届中国抗衰老医学(官方)大会
4月17日,2021第六届中国抗衰老医学(官方)大会在杭州隆重召开。微盛·企微管家携手企业微信共同参加了此次大会。
微盛企微管家
2021/04/21
5410
企业微信生态也成创业赛道 这家公司5个月内连获两轮融资
很多网红在直播的过程中遇到了一个问题是:他们通过直播,将客户引流到个人微信或者公众号,虽然这些平台都有了大量粉丝,但是她发现跟粉丝互动却是一件困难的事情。 很典型的例子是信息传输的是单向的,也没有办法对这些粉丝进行归类。这对于主播薇娅的下一步私域流量管理,增大了不少难度。 “我们跟谦寻(薇娅所在公司主体)等很多知名网红公司接触,帮他们把公众号和个人微信号的粉丝企业微信好友,这样他们就能粉丝做很好的互动了,因为通过企业微信,可以针对粉丝更标签分类,也能给粉丝提供更好的福利”,微盛的CEO杨明说。 微
鹅老师
2021/02/09
4390
腾讯企业微信X微盛·企微管家联合发布会在广州顺利举行,共同宣布战略合作关系|腾讯SaaS加速器·案例库
来源|腾讯SaaS加速器二期项目-微盛·企微管家 ---- 2021年4月22日,企业微信与微盛·企微管家(腾讯SaaS加速器二期成员)的联合发布会在广州顺利举行。会上,企业微信产业生态合作总经理李致峰与微盛·企微管家创始人杨明共同完成了签约仪式,正式宣布了企业微信与微盛·企微管家的战略合作。 在现场数百名嘉宾与媒体朋友的见证下,企业微信产业生态合作总经理李致峰与微盛·企微管家创始人杨明共同签订了战略合作协议。 在发布会的开场演讲中,李致峰除了对企业微信生态化建设进行了介绍,还郑重宣布了腾讯
腾讯SaaS加速器
2021/05/06
8550
不在办公室搭帐篷,教培行业运营的出路在何处
图源:图虫创意 ♪ 作者|芥末堆 逍遥子 ♪ 编辑|芥末堆看教育 刚刚过去的暑假,在线教育巨头们捷报频传。对于运营者而言,却可谓是一半海水一半火焰。 运营者熬夜成日常 深夜十一点半,在教培机构从事用户运营工作的小张打了个哈欠。他刚刚将一位咨询课程的家长拉入课程优惠群。潜在用户多了一位,但更多的环节还在等着他:发送欢迎语,推送新的课程活动,活跃群用户,统计群数据…… 小张习惯性地摸了摸自己的发际线,熟练地编辑好了最新的课程优惠信息介绍。点下发送键的前一秒,小张眼前一突:他看见群内弹出了友商课程优惠
鹅老师
2020/09/07
1.3K0
功能更新 | 朋友圈营销必备,微盛这款帮客户用好企业微信做增长的“神器”升级啦!
前一阵子,企业微信发布了重磅更新:客户访问企业员工的个人信息页时,可以看到朋友圈入口,并能查看员工历史发表的内容。
微盛企微管家
2021/09/24
8300
DNSPod十问王海顺:为什么只有企业微信能盘活私域?
王海顺Eric,微盛·企微管家联合创始人。原美国托马斯中国区总经理,微渠网络创始人;10年B2B平台运营及销售管理经验,5年私域电商平台创业经历,擅长品牌定位及营销战略。微盛·企微管家由腾讯、红杉战略投资,2022年初再获3亿元B1和B2轮融资,累计服务企业客户15万+。 吴洪声,人称奶罩,腾讯云中小企业中心总经理,DNSPod创始人,洋葱令牌创始人,网络安全专家,域名及DNS技术专家,知名个人站长,中欧国际工商学院EMBA。 1 吴洪声:微盛2015年成立,其实最先做的是微信公众号开发、小程序平台研
腾讯云DNSPod团队
2022/04/02
1K0
DNSPod十问王海顺:为什么只有企业微信能盘活私域?
微盛·企微管家出席腾讯云合作伙伴招募会并现场分享
4月8日,腾讯云在上海召开了合作伙伴招募会,会议聚焦泛政行业、泛企业、金融、转售产品等领域,与华东区域各省市生态伙伴一起交流探讨,旨在共同助力产业生态的建设与发展。
微盛企微管家
2021/04/21
1.8K0
微盛·企微管家出席腾讯云合作伙伴招募会并现场分享
直面教培机构痛点!腾讯企微管家提供引流运营全链路服务
8月24日,腾讯教育正式发布了基于企业微信的私域流量运营工具——企微管家,为教培机构提供从引流获客到客户运营的全链路服务,助力企业实现私域数字化营销。 企业微信是唯一能和微信互通的办公商务工具,对内协同效率办公,对外实现客户,并且为教育企业提供招生流程的全链路管理工具。因此,用企业微信做学员运营链接客户,已经成为了一个必然趋势。 腾讯教育推出基于企业微信的私域流量运营工具企微管家 “今年,做教育太难了!”这句话是从大量教育行业从业者那里,听到最多的声音。流量红利逐渐消失给教培行业带来了极大的影响与改变
鹅老师
2020/08/28
2.2K0
微盛·企微管家荣获企业微信2020年度优秀合作伙伴并现场分享|腾讯SaaS加速器·学员动态
来源 |  腾讯SaaS加速器二期项目-微盛·企微管家 ---- 企业微信2020年度大会如期举行。 企业通过企业微信服务和连接的微信用户数已达4亿。目前,企业微信上已有的真实企业与组织数已经超过550万,活跃用户数也超过1.3亿。 为了帮助企业更加高效地沉淀和服务客户,本次大会发布了企业微信客户服务能力的升级:500人客户群、客户群红包、离职/在职继承、更多开放能力... 同时在大会现场,企业微信也正式发布了企航计划:企业微信将提供12亿元数字化扶持基金,帮助教育行业、区县政务行业和中小企业实
腾讯SaaS加速器
2021/01/05
1K0
私域案例实操手册:家电行业私域流量案例
长虹美菱这两个营销活动拆解的非常细,除了这两个活动之外,长虹在新品发布,跨界合作等活动类型的策划也是相当精细,并取得了非常不错的活动效果。私域运营当然也会需要强运营,有时,匹配经常性的强运营会取得事半功倍的效果。
微盛企微管家
2020/11/09
2.1K0
私域案例实操手册:家电行业私域流量案例
独家案例|小而美的水果生鲜社区电商增长实践
据艾媒咨询数据,2021年生鲜电商市场规模预计达到3117.4亿元,2023年将超过8000亿元。另据企查查数据,截至2021年4月,我国在业/存续的生鲜电商相关企业已达到2.15万家,包括农贸市场、小摊贩、便利店、小超市、大型商超、新零售、生鲜电商、社区超市、连锁店等等,庞大市场中的业态繁多,竞争激烈,88%的生鲜电商处于亏损状态。要想在竞争中赢得主动,扭亏为盈,脱颖而出,以数字化客户服务与营销为基础的熟客运营模式成为企业顺应时代要求的必然选择。 2020年,疫情说来就来,线下客流不断减少,
腾讯企点
2022/06/24
2.2K0
独家案例|小而美的水果生鲜社区电商增长实践
社群分享裂变场景化分析
作者的话 本文荣获2020年下半年腾讯知识奖 本文将重点介绍在微信生态下,如何借助小程序形态进行社群分享裂变的场景分析,希望可以给大家一些参考和借鉴。文中数据已脱敏处理,仅供参考。 社交裂变的价值 众所周知,一切产品业务发生的前提是有用户,在此基础上才有转化流程,尤其在企业初创期,最核心的指标是用户增长。且在如今的市场环境下,增长不再主要依赖广告投放,而是主要基于社交网络的裂变拉新。小程序处在微信生态下,分享功能是小程序拉新、获客的重要途径。微信作为国内最大社交网络,利用其生态进行社交裂变是当前的推广运营业
腾讯灯塔小明
2022/08/25
1.1K0
社群分享裂变场景化分析
SCRM与传统CRM有什么区别?
CRM英文是Customer Relationship Management,中文的意思是客户关系管理。SCRM英文全称是Social Customer Relationship Management, 即Social+CRM,借由社交化工具,实现对用户的个性化沟通,更重要的是SCRM通过互联技术将用户纳入到企业的营销体系中,鼓励用户与用户直接的个性化的沟通,在沟通过程中,用户收获更多的参与感、获得感,从而提升用户对品牌的认可和情感联结。
布鲁斯8号
2022/03/23
1.4K0
SCRM与传统CRM有什么区别?
如何搭建会员系统?
前两年,受疫情影响,国内外消费品行业都受到了巨大冲击;尤其是国内,最新的统计表明2022年比2021年的消费降低了2万亿。但随着疫情的影响逐渐减弱,随着政府的各项政策引导,相信2023年的第二季度开始会迎来消费复苏。各大消费品品牌也在尝试通过数字化、全渠道整合,构建全渠道会员系统。
博阳SCRM系统
2023/03/22
2.6K0
如何搭建会员系统?
企业微信在线零售行业解决方案
出于疫情防控需要,各企业陆续发布了延迟复工,零售企业的远程办公和加强线上经营成为新趋势,下面与大家分享微盛SCRM小程序结合企业微信,是如何帮助零售行业企业单位实现线上经营的?
微盛企微管家
2020/07/23
1.9K0
企业微信在线零售行业解决方案
腾讯教育推出企微管家 提供教培行业引流、获客、运营全链路服务
教培行业正在经历流量之殇,疫情带来的流量红利逐渐消失,头部机构在通过楼宇公交广告、明星代言、综艺冠名等营销手段获客的同时,也不断抬高着流量的获取成本,进一步加剧了整个行业的获客增长难度。对于重品牌和服务的教育行业来说,过于依赖广告投放并非长久之计,做好私域流量池运营,依靠忠实用户的留存和裂变实现低成本获客,才是教培机构健康持续发展的关键。 基于此,8月24日,腾讯教育正式发布了基于企业微信的私域流量运营工具——企微管家,为教培机构提供从引流获客到客户运营的全链路服务,助力企业实现私域数字化营销。
腾讯智慧教育
2020/08/25
2.2K0
案例 | 2个月沉淀25万精准客户,家清网携手销售智推打造私域增长新范式!
西安优露清科技股份有限公司(家清网)成立于2007年,主要经营⾐物洗护、厨卫清洁、⽪具护理、清洁⿊科技等全领域的家居清洁用品。公司产品获多项国家发明专利,部分爆款产品全年累计畅销上亿瓶,深受国内外消费者信赖与喜爱。 “家清网”携手腾讯企点-销售智推达成战略合作 使用销售智推前,在营销获客方面,家清网主要采取销售线下地推、陌拜、活动赞助宣传等方式,投入了大量人力和资金,投入产出比较低。也尝试过新媒体平台与社交电商获客,效果均不明显。 在经营模式上,家清网线下占比较大,公司业务发展受限于业
腾讯企点
2021/10/29
3.3K0
推荐阅读
腾讯SaaS加速器二期成员微盛·企微管家完成亿元级融资,腾讯红杉再度加码企业微信服务赛道|腾讯SaaS加速器·学员动态
8160
微盛·企微管家再获3亿元融资,继续领跑企业微信SCRM赛道
1K0
微盛企微管家客户案例:单店收益提升50%,悸动烧仙草是如何用好企业微信做增长?
6480
微盛·企微管家携手企业微信参加2021第六届中国抗衰老医学(官方)大会
5410
企业微信生态也成创业赛道 这家公司5个月内连获两轮融资
4390
腾讯企业微信X微盛·企微管家联合发布会在广州顺利举行,共同宣布战略合作关系|腾讯SaaS加速器·案例库
8550
不在办公室搭帐篷,教培行业运营的出路在何处
1.3K0
功能更新 | 朋友圈营销必备,微盛这款帮客户用好企业微信做增长的“神器”升级啦!
8300
DNSPod十问王海顺:为什么只有企业微信能盘活私域?
1K0
微盛·企微管家出席腾讯云合作伙伴招募会并现场分享
1.8K0
直面教培机构痛点!腾讯企微管家提供引流运营全链路服务
2.2K0
微盛·企微管家荣获企业微信2020年度优秀合作伙伴并现场分享|腾讯SaaS加速器·学员动态
1K0
私域案例实操手册:家电行业私域流量案例
2.1K0
独家案例|小而美的水果生鲜社区电商增长实践
2.2K0
社群分享裂变场景化分析
1.1K0
SCRM与传统CRM有什么区别?
1.4K0
如何搭建会员系统?
2.6K0
企业微信在线零售行业解决方案
1.9K0
腾讯教育推出企微管家 提供教培行业引流、获客、运营全链路服务
2.2K0
案例 | 2个月沉淀25万精准客户,家清网携手销售智推打造私域增长新范式!
3.3K0
相关推荐
腾讯SaaS加速器二期成员微盛·企微管家完成亿元级融资,腾讯红杉再度加码企业微信服务赛道|腾讯SaaS加速器·学员动态
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验