在做项目中,获取网络数据是一件很常见的事情,各类数据在服务器端或直接print,或封以实体类扔进List转换为json,由客户端使用HttpClient的execute()方法接收,以完成数据交互的过程。
这是V1.0版本的方法,最朴实的毫无优化的获取方式:通过HttpClient获取,然后return到要用的地方,更新UI
GetPicture.java
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreConnectionPNames;
import java.io.IOException;
import java.io.InputStream;
/**
* 获取网络图片工具类
* pictureUrl:图片url,可网络地址,可服务器路径
*/
public class GetPicture {
private Bitmap picture;
public Bitmap getNetPicture(final String pictureUrl){
new Thread(new Runnable() {
@Override
public void run() {
Bitmap img = null;
HttpClient client = null;
HttpGet request = null;
HttpResponse response = null;
try {
request = new HttpGet(pictureUrl);
client = new DefaultHttpClient();
client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000 * 5); // 链接超时
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,1000 * 5); // 读取超时
response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
InputStream is = response.getEntity().getContent();
img = BitmapFactory.decodeStream(is);
showToast("网络图片:"+pictureUrl+"获取成功!");
} else {
showToast("网络图片:"+pictureUrl+"获取失败!");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
showToast(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
showToast(e.getMessage());
}
picture = img;
}
}).start();
return picture;
}
private void showToast(String words) {
System.out.println(words);
}
}
如代码所示,通过访问url来获取图片对象,利用文件流来实现缓存到内存,最后return给需要的地方
使用方法:
//获取图片对象
String url =”图片url”;
GetPicture getPicture = new GetPicture();
Bitmap picture = getPicture.getNetPicture(url);
MainActivity.java:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.absolom.GetNetPicture.Tools.GetPicture;
public class MainActivity extends AppCompatActivity {
Button GetPicture1;
Button GetPicture2;
ImageView ImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String url1 = "http://e.hiphotos.baidu.com/zhidao/pic/item/8cb1cb1349540923f12939199458d109b3de4910.jpg";
String url2 = "http://e.hiphotos.baidu.com/zhidao/pic/item/aec379310a55b31907d3ba3c41a98226cffc1754.jpg";
ImageView = (ImageView)findViewById(R.id.ImageView);
GetPicture getPicture = new GetPicture();
GetPicture1 = (Button)findViewById(R.id.GetPicture1);
GetPicture2 = (Button)findViewById(R.id.GetPicture2);
GetPicture1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageView.setImageBitmap(getPicture.getNetPicture(url1));
}
});
GetPicture2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImageView.setImageBitmap(getPicture.getNetPicture(url2));
}
});
}
}
在使用的过程中,博主逐渐发现这种方法的不足之处:
在同时获取多个图片时会造成线程拥堵,导致return的对象不对或重叠
比如用循环遍历json串获取图片url,然后添加到ArrayList中来实现新闻列表功能,在网络状态不加的情况下回因为return的速度跟不上for循环的速度而导致图片错误或重叠。
为了解决这一问题,楼主加入了异步机制来处理,即AsynTask
下面这段关于AsynTask的介绍引用自http://www.cnblogs.com/xiaoluo501395377/p/3430542.html
AsyncTask:异步任务,从字面上来说,就是在我们的UI主线程运行的时候,异步的完成一些操作。AsyncTask允许我们的执行一个异步的任务在后台。我们可以将耗时的操作放在异步任务当中来执行,并随时将任务执行的结果返回给我们的UI线程来更新我们的UI控件。通过AsyncTask我们可以轻松的解决多线程之间的通信问题。
怎么来理解AsyncTask呢?通俗一点来说,AsyncTask就相当于Android给我们提供了一个多线程编程的一个框架,其介于Thread和Handler之间,我们如果要定义一个AsyncTask,就需要定义一个类来继承AsyncTask这个抽象类,并实现其唯一的一个 doInBackgroud 抽象方法。要掌握AsyncTask,我们就必须要一个概念,总结起来就是: 3个泛型,4个步骤。
3个泛型指的是什么呢?我们来看看AsyncTask这个抽象类的定义,当我们定义一个类来继承AsyncTask这个类的时候,我们需要为其指定3个泛型参数:
AsyncTask <Params, Progress, Result>
- Params: 这个泛型指定的是我们传递给异步任务执行时的参数的类型
- Progress: 这个泛型指定的是我们的异步任务在执行的时候将执行的进度返回给UI线程的参数的类型
- Result: 这个泛型指定的异步任务执行完后返回给UI线程的结果的类型
我们在定义一个类继承AsyncTask类的时候,必须要指定好这三个泛型的类型,如果都不指定的话,则都将其写成Void,例如:
AsyncTask <Void, Void, Void>
4个步骤:当我们执行一个异步任务的时候,其需要按照下面的4个步骤分别执行
- onPreExecute(): 这个方法是在执行异步任务之前的时候执行,并且是在UI Thread当中执行的,通常我们在这个方法里做一些UI控件的初始化的操作,例如弹出要给ProgressDialog
- doInBackground(Params… params): 在onPreExecute()方法执行完之后,会马上执行这个方法,这个方法就是来处理异步任务的方法,Android操作系统会在后台的线程池当中开启一个worker thread来执行我们的这个方法,所以这个方法是在worker thread当中执行的,这个方法执行完之后就可以将我们的执行结果发送给我们的最后一个 onPostExecute 方法,在这个方法里,我们可以从网络当中获取数据等一些耗时的操作
- onProgressUpdate(Progess… values): 这个方法也是在UI Thread当中执行的,我们在异步任务执行的时候,有时候需要将执行的进度返回给我们的UI界面,例如下载一张网络图片,我们需要时刻显示其下载的进度,就可以使用这个方法来更新我们的进度。这个方法在调用之前,我们需要在 doInBackground 方法中调用一个 publishProgress(Progress) 的方法来将我们的进度时时刻刻传递给 onProgressUpdate 方法来更新
- onPostExecute(Result… result): 当我们的异步任务执行完之后,就会将结果返回给这个方法,这个方法也是在UI Thread当中调用的,我们可以将返回的结果显示在UI控件上
除了 doInBackground 方法之外的三个方法,都不是必须有的,因此我们必须要实现的方法是 doInBackground 方法。
引用完毕。
一番研究之后楼主写出了第二种获取方法,也是就V2.0版本:
/**
* 获取新闻图片类
*/
public class GetNetPicture extends AsyncTask<String,Integer,Bitmap> {
//Context context;
String pictureUrl;
@Override
protected Bitmap doInBackground(String... params) {
pictureUrl = params[0];
Bitmap img = null;
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(pictureUrl);
HttpResponse response = null;
try {
client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000 * 5); // 链接超时
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,1000 * 5); // 读取超时
response = client.execute(request);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
InputStream is = response.getEntity().getContent();
img = BitmapFactory.decodeStream(is);
showToast("网络图片:"+pictureUrl+"获取成功!");
} else {
showToast("网络图片:"+pictureUrl+"获取失败!");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
showToast(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
showToast(e.getMessage());
}finally {
client.getConnectionManager().shutdown();
}
return img;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
// ACache mCache = ACache.get(context);
// mCache.put(pictureUrl,bitmap);
}
// public void getContext(Context context){
// this.context = context;
// }
private void showToast(String words) {
System.out.println(words);
}
}
楼主这里引用了来自杨神的ACache缓存框架,所以需要获取一下上下文对象,大家用的时候可以根据需要进行改动。
使用方法也非常简单:
GetNetPicture getNetPicture = new GetNetPicture();
getNetPicture.getContext(this);
getNetPicture.execute(newsImagePath);
或者直接写成:
new GetNetPicture().execute(newsImagePath);
V2.0版本的获取方式好像比V1.0效率提升了不少?【应该不是幻觉】
好吧,说实话这种方法的性能也不咋地,最终我们走上了用别人轮子的道路……
ImageLoader、Gilde等等各种图片加载框架,方便又简单,你值得拥有~
【滑稽】