服务是什么
服务主要是安卓中为了解决后台运行的方案,适合去处理不需要与客户交互又能长期在线的任务。服务不依赖与任何用户界面,即使你打开后台或者其它应用程序服务任然进行中。不过要注意的是服务不是运行在单独的进程中而是依赖与创建服务时所依赖的程序中,当该程序被杀死,服务也就跟着完蛋了。还要注意服务不会自动开启线程,都是默认在主线程中,所以我们要在服务内部建立子线程,并且执行任务否则就会造成主线程阻塞。通俗的讲就是我们做些网络请求的时候如果网路很慢的话
服务器未必马上响应。如果不建立子线程的话,主线程就会卡死,从而很引影响用户体验。
服务中线程的学习
与JAVA类似同样要继承Thread类,重写run()方法,然后在里面写些逻辑就可以了。
继承方式
class MyThread extends Thread{
@override
public void run(){
//要处理的逻辑
}
}
实现这种接口只要new出一个实例然后调用star()方法如 new MyTread().start()。
以上的方法耦合性高。还有接口性质的
class MyTread implements Runnable{
@override
public void run(){
//要处理的逻辑
}
}
实现以上方法方式要注意以下同样要实例一下 MyThread myThread=new MyThread();
new Thread(myThread).start;
异步消息处理机制
利用异步请求对UI内容进行更新
Message:是用在线程中传递少量数据的,它可以用arg1携带整形数据,obj携带对象。
Handler:处理数据用的通常用sendMessage(数据源)发送数据,handleMessage(Message msg参数)方法接受数据并处理。
looper:像一个捕捉器一样只要发现有一条Message就会把它发给Handler进行处理。
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
//异步请求处理
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView text;
public static final int UPDATE_TEXT = 1;
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (TextView) findViewById(R.id.text);
Button changeText = (Button) findViewById(R.id.change_text);
changeText.setOnClickListener(this);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//在这里可以对UI进行操作
case UPDATE_TEXT:
text.setText("很高心认识你");
break;
default:
break;
}
}
};
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.change_text:
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = UPDATE_TEXT;
handler.sendMessage(message);
}
}).start();
break;
default:
break;
}
}
}
主要步骤是利用一个常量UPDATE_TEXT来更新TextView这个动作。然后新增一个对象Handler用于请求做个平台。再把这个请求做一个自己想做的什么样的逻辑处理。根据界面事件传来的msg.what做相应的处理方式。
事件中我们要向后面的Handler发送一个message常量值请求到后面解析。主要是通过内部的sendMessage();对这条请求进妆转发。当Handler接受到这条信息就会调用handleMessage()这个方法会对这条内容进行处理。
学习服务下载学习内容
AsyncTask<String ,Integer,Integer>:这个方法需要携带三个参数,第一个参数表示需要传入字符串给后台任务,第二个数据表示用整型数据作为进度显示,第三个参数表示用整型数据回馈执行的情况结果。
doInBackground()方法执行后台下载的具体逻辑。如文件的下载格式啊字节流,具体事例如下
@Override
//doInBackground()方法执行后台下载饿具体逻辑
protected Integer doInBackground(String... params) {
InputStream is = null;
RandomAccessFile savedFile = null;
File file = null;
try {
//定义文件下载格式
long downloadedLength = 0;//记录下载的长度
String downloadUrl = params[0];//通过参数获取URL地址
String directory = Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_DOWNLOADS).getPath();//将文件下载到指定的DIRECTORY_DOWNLOADS目录下SD卡的DOWNLOAD目录
String fileName=downloadUrl.substring(downloadUrl.lastIndexOf("/"));//根据地址解析文件名
file=new File(directory+fileName);//文件名拼接
if (file.exists()){
downloadedLength=file.length();
}
long contentLength=getContentLength(downloadUrl);//获取下载长度
if (contentLength==0){
return TYPE_FAILED;
}else if (contentLength==downloadedLength){
//已下载字节和文件字节相等说明下载完成
return TYPE_SUCCESS;
}
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().addHeader("RANGE","bytes="+downloadedLength+"-").url(downloadUrl).build();
Response response=client.newCall(request).execute();
if (response!=null){
is=response.body().byteStream();
savedFile=new RandomAccessFile(file,"rw");
//跳过以下载的字节
savedFile.seek(downloadedLength);
byte[]b=new byte[1024];
int total=0;
int len;
while ((len=is.read(b))!=-1){
if (isCanceled){
return TYPE_CANCELED;//请求取消
}else if (isPaused){
return TYPE_PAUSED;//请求暂停
}else {
total+=len;
savedFile.write(b,0,len);
// 计算以下载的百分比
int progress= (int)(((total+downloadedLength)*100)/contentLength);
publishProgress(progress);
}
}
response.body().close();
return TYPE_SUCCESS;
}
} catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (is!=null){
is.close();
}if (savedFile!=null){
savedFile.close();
}if (isCanceled&&file!=null){
file.delete();
}
}
catch (Exception e) {
e.printStackTrace();
}
}
return TYPE_FAILED;
}
@Override
//用于更新下载进度
protected void onProgressUpdate(Integer... values) {
int progress=values[0];//从参数中获取进度
if (progress>lastProgress);
listener.onProgress(progress);
lastProgress=progress;
}
@Override
//用于通知下载结果
protected void onPostExecute(Integer status) {
switch (status){
case TYPE_SUCCESS:
listener.onSuccess();
break;
case TYPE_FAILED:
listener.onFailed();
break;
case TYPE_CANCELED:
listener.onCanceled();
break;
case TYPE_PAUSED:
listener.onPaused();
default:
break;
}
}
public void pauseDownload(){
isPaused=true;
}
public void cancelDownload(){
isCanceled=true;
}
//构造方法获取文件长度
private long getContentLength(String downloadUrl)throws IOException{
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url(downloadUrl).build();
Response response=client.newCall(request).execute();
if (response!=null&&response.isSuccessful()){
long contentLength=response.body().contentLength();
response.close();
return contentLength;
}
return 0;
}
}
1。setProgress():这个方法用于下载时用需要传入三个参数第一个是通知最大进度,第二个是传入通知当前进度,第三个参数是表示是否使用模糊进度条是个boolean类型的值。
2。因为下载文件是要下载到SD卡上面所以必须给文件配权限不然程序无法使用。onRequestPermissionsResult()该方法是设置权限时使用的。
3。如果程序下载需要用到网络那么必须在AndroidMainfest.xml中加入
4. 启动服务用startService(intent)括号里放你要启动的服务。启动活动用startActivity();