今天我们讲下Service的后台下载的实现。Service的后台下载是在onStartCommand()方法中执行的,由于不能再该方法中执行
耗时操作,所以我们必须在其中创建子线程实现下载。
所以我们在启动服务时必须给Service传一个地址用于解析图片。
MainActivity:
package com.example.text07;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
private String PATH = "https://www.baidu.com/img/bd_logo1.png";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void download(View v) {
// 创建Intent对象并传值给Service
Intent intent = new Intent(this, MyService.class);
intent.putExtra("path", PATH);
// 启动服务
startService(intent);
}
}
MyService:
package com.example.text07;
import com.example.http.ExternalStorageUtils;
import com.example.http.HttpUtils;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 获取Activity传来的路径--->下载图片到sdCard
final String path = intent.getStringExtra("path");
new Thread(new Runnable() {
@Override
public void run() {
// 网络下载图片(HttpUtils)--->下载图片保存到sdCard中(ExternalStorageUtil)
// 注意在服务中,Service子类本身就是一个Context的子类
if (HttpUtils.isNetWorkConn(MyService.this)) {
// 网络连通则把图片信息解析到byte在数组中
byte[] data = HttpUtils.getByteArray(path);
if (data != null && data.length != 0) {
// 数组中存在数据,图片下载成功
boolean f = ExternalStorageUtils
.writeExternalStorageRoot(getFileName(path),
data, MyService.this);
if (f) {
Log.i("main", "图片存储成功");
} else {
Log.i("main", "图片下载失败");
}
} else {
Log.i("main", "下载图片失败");
}
} else {
// 否则就是连不通的,在服务中不能操控UI的任何组件,包括吐司
Log.i("main", "网络连接异常");
}
// 停止服务
stopSelf();
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
// 得到下载的文件名
public String getFileName(String path) {
return path.substring(path.lastIndexOf("/") + 1);
}
}
接下来是HttpUtils工具类:
package com.example.http;
import java.io.IOException;
import org.apache.http.HttpResponse;
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.util.EntityUtils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class HttpUtils {
//判断网络是否连接正常
public static boolean isNetWorkConn(Context context){
boolean flag = false;
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo info = manager.getActiveNetworkInfo();
if (info != null) {
return info.isConnected();
}
return flag;
}
//把网址中的数据解析到byte数组中
public static byte[] getByteArray(String path){
HttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet(path);
try {
HttpResponse res = client.execute(get);
if (res.getStatusLine().getStatusCode() == 200) {
return EntityUtils.toByteArray(res.getEntity());
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
接下来是向sdCard写入文件的工具类ExternalStorageUtils:
package com.example.http;
import java.io.File;
import java.io.FileOutputStream;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
public class ExternalStorageUtils {
//判断sdCard是否可用
public static boolean isSdcardUseful(){
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
return true;
}
return false;
}
//存储内容
public static boolean writeExternalStorageRoot(String name,byte[] data,Context context){
if (isSdcardUseful()) {
//获取sdCard的根目录
File sdFile = Environment.getExternalStorageDirectory();
//创建文件的抽象路径
File file = new File(sdFile, name);
//向文件中写数据
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(data, 0, data.length);
fos.flush();
fos.close();
//返回true
return true;
} catch (Exception e) {
e.printStackTrace();
}
}else{
Log.i("main", "sdCard不可用");
}
return false;
}
}
最后是在清单文件中注册并加上对应的权限:
<service android:name="com.example.text07.MyService" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
这样就实现了图片的下载,整体的思路很简单,唯一需要注意的是对于工具类的封装以及对要穿的参数的明确。