第二十五章 HTTP与后台任务(未完)
网络连接
- 获取网络权限
<uses-permission android:name="android.permission.INTERNET"/>
- 创建一个URL对象
- 建立连接, 调用
URL.openConnection()
方法创建一个指向要访问的URL的连接对象, 并强制类型转换成HttpURLConnection
- 创建输入. 输出流对象.
- 调用
InputStream.read(byte[] b)
方法, 将输入流读取到数组中, 且返回该数组的长度(int) - 调用
ByteArrayOutputStream.write(byte[] b, int off, int len)
. 写入out输出流中 ByteArrayOutputStream.toByteArray();
//创建新分配的字节数组
public byte[] getUrlBytes(String urlSpec) throws IOException{
URL url = new URL(urlSpec);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try{
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = connection.getInputStream();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK){
throw new IOException(connection.getResponseMessage() +
": with " +
urlSpec);
}
int bytesRead =0;
byte[] buffer = new byte[1024];
while((bytesRead = in.read(buffer)) > 0){
out.write(buffer, 0, bytesRead);
}
out.close();
return out.toByteArray();
}finally {
connection.disconnect();
}
}
- 由于要解析为Json格式, 故要返回String类型
public String getUrlString(String urlSpec) throws IOException{
return new String(getUrlBytes(urlSpec));
}
AsyncTask
- 由于主线程不能运行耗时操作, 所以要在后台进行请求网络, 下载数据等耗时的操作
AsyncTask<Params, Progress, Result>
- 第一个参数, 可指明转给
AsyncTask.execute(...)
方法参数的输入类型. 该参数会传入doInBackground(Params)
, 可传入一个或多个参数 - 第二个参数, 可指明转给
publishProgress(Progress... values)
方法参数的输入类型. 该参数会传入onProgressUpdate(Void... values)
- 第三个参数, 是指明
doInBackground(Params)
返回参数的类型, 返回的参数会传入onPostExecute(Result)
publishProgress(Progress... values)
在doInBackground(Params)
方法中执行,该方法会调用onProgressUpdate(Void... values)
, 且后者在UI线程上调用.onPostExecute(Result)
方法在doInBackground(Params)
运行完成后调用, 常用于更新UI线程, 避免由于在doInBackground(Params)
中更新UI造成内存对象相互践踏, 从而让应用崩溃.
- 可以直接创建AsyncTask的对象, 执行
AsyncTask.execute(...)
时可传入参数 - 继承AsyncTask并定义构造函数, 可完成其初始化
private class FetchItemsTask extends AsyncTask<Void, Void, List<GalleryItem>>{
private String mPage;
private String mCount;
public FetchItemsTask(String page, String count){
mPage = page;
mCount = count;
}
@Override
protected List<GalleryItem> doInBackground(Void... voids) {
if (mPage == null||mCount == null){
return new FlickrFetchr().fetchRecentPhoto();
}else{
return new FlickrFetchr().searchPhotos(mPage, mCount);
}
}
@Override
protected void onPostExecute(List<GalleryItem> galleryItems) {
mItems = galleryItems;
setupAdapter();
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
清理AsyncTask
- 在
fragment
的相关生命周期里清理.(如: onStop()
或onDestoty()
)
- 创建AsyncTask的实例, 然后调用该
AsyncTask.cancel(boolean)
方法;取消方法有两种:
cancel(true)
. 立即终止doInBackground(Params)
, 但在其中的不可终止操作
不会自动停止(如: IO流的操作). 可以自己手动停止并抛出异常, 但其就失去了意义.应尽量避免使用cancel(false)
, 会将isCancelled()
的状态设置为true, 通过判断其值达到终止操作的目的.
获取URI地址(URL地址)
Uri uri = Uri.parse(String)
.buildUpon()
.build();
String url = Uri.parse("https://...").
buildUpon().
appendQueryParameter("提交的键", "相应提取的值").
build().toString();
Json格式的解析
JSONObject jsonBody = new JSONObject(String);
JSONArray resultJsonArray = photosJsonObject.getJSONArray("photo");
JSONObject jsonObject = resultJsonArray.getJSONObject(i);
相关小记
- 由于
AsyncTask
可以在后台运行, 因而不能确定fragment是否相关联着activity. 若不关联, 则依赖activity相关的操作都会失效. 故开始要在fragment中用isAdded
方法确定activity的存在.
挑战练习
- 利用Gson工具库解析jJSON
- 分页
- 动态调整网格列数(???)