Service基础笔记

Service基础:
一,Service 组件也是可执行程序,也有自己的生命周期。它与 Activity 的区别在于:Service 一直在后台运行而没有用户界面。
二,开发 Service 的步骤:
1.定义一个继承 Service 的子类。
类似于 Activity,Service 中也定义了系列生命周期方法如下:
1》IBinder onBind(Intent intent) :这是 Service 子类必须实现的方法。该方法返回一个 IBinder 对象,应用程序可通过该对象与 Service 组件通信。
2》void onCreate() :该 Service 被首次创建后回调该方法。一般在该 方法中进行数据初始化
3》void onDestroy() :该 Service 被关闭之前将回调该方法。一般在该方法中进行扫尾
4》void onStartCommand(Intent intent, int flags, int startId) :每次客户端调用 startService(Intent) 方法启动该 Service 时都会回调该方法。该方法的早期版本:
5》void onStart(Intent intent, int startId)
6》boolean onUnbind(Intent intent) :当该 Service 上绑定的所有客户端都断开连接时回调该方法。
2.在 AndroidManifest.xml 文件中配置该 Service。

使用的配置元素是 <service.../>,与配置 Activity 相似,也可为 <service.../> 元素配置 <intent-filter.../> 子元素,用于说明该 Service 可被哪些 Intent 启动。

<service android:name=".FirstService">
      <intent-filter>
        <!-- 为该Service组件的intent-filter配置action -->
        <action android:name="com.qf.service.FIRST_SERVICE" />
      </intent-filter>
    </service>
3.Service 与 Activity 都是从 Context 派生出来,因此都可调用 Context 里定义的 getResources()、getContentResolver() 等方法。
Android 系统中运行 Service 有如下两种方式:
1》通过 Context 的 startService() 方法:访问者与 Service 之间没有关联,即使访问者退出了,Service 仍然运行。
2》通过 Context 的 bindService() 方法:访问者与 Service 绑定,访问者一旦退出,Service 也就被终止。
4.例子:mp3播放器
1》把音频文件复制到res/raw目录下,raw目录主要用来存放音频或视频文件
2》写一个Service,来播放音频
package hsl.com.servicemusicplayer;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by Administrator on 2016/8/4 0004.
 */
public class MusicPlayServer extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //播放音频的player
    MediaPlayer player;

    @Override
    public void onCreate() {
        super.onCreate();
        //创建一个音频播放器,R.raw.xxx是音频文件
        player = MediaPlayer.create(this, R.raw.zmtlr);
    }

    //定时发广播
    Timer timer;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("TAG", "服务启动了");
        boolean isPlay = intent.getBooleanExtra("isPlay", false);
        int progress = intent.getIntExtra("progress", -1);
        if (progress != -1) {
            //表示用户移动了SeekBar,则移动到指定位置
            player.seekTo(progress * player.getDuration() / 100);
        }
        if (isPlay) {
            //如果是播放,则启动一个记时器,每隔一秒就发一条进度更新通知
            player.start();
            if (timer == null) {
                timer = new Timer();
                //执行定时任务,三个参数:
                //1.TimerTask,定时执行的任务
                //2.int 第一次执行任务延时时间
                //3.定时间隔,即下次执行任务与当前执行时间间隔 
                timer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        Intent intent = new Intent("com.qf.play.progress");
                        //获取当前进度
                        int per = (int) (player.getCurrentPosition() * 100f / player.getDuration());
                        intent.putExtra("progress", per);
                        LocalBroadcastManager.getInstance(MusicPlayServer.this).sendBroadcast(intent);
                    }
                }, 0, 1000);
            }
        } else {
            //如果是暂停,则取消记时器
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
            player.pause();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    //服务结束时,释放资源
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        if (player.isPlaying()) {
            player.stop();
            player.release();
        }

    }
}
//播放音频的player
    MediaPlayer player;
 //创建一个音频播放器,R.raw.xxx是音频文件
        player = MediaPlayer.create(this, R.raw.zmtlr);
  if (player.isPlaying()) {
            player.stop();
            player.release();
        }
player.start();
3》在Activity中,启动服务并带一个参数,表示是暂停还是播放
package hsl.com.servicemusicplayer;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.SeekBar;

public class MainActivity extends Activity {

    //播放进度条
    SeekBar sb;
    //播放与暂停
    CheckBox cb;
    //接收进度更新广播
    MyReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setupViews();
        //采用LocalBroadcast,app内部广播,效率更高,更安全
        receiver = new MyReceiver();
        IntentFilter intentFilter = new IntentFilter("com.qf.play.progress");
        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);
    }

    private void setupViews() {
        sb = (SeekBar) findViewById(R.id.sb);
        cb = (CheckBox) findViewById(R.id.cb);
        sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser) {
                    //如果是用户操作的,则启动服务,并移动播放位置
                    Intent intent = new Intent(MainActivity.this, MusicPlayServer.class);
                    intent.putExtra("progress", progress);
                    intent.putExtra("isPlay", cb.isChecked());
                    startService(intent);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }

    public void doClick(View view) {
        CheckBox cb = (CheckBox) view;
        Intent intent = new Intent(this, MusicPlayServer.class);
        intent.putExtra("isPlay", cb.isChecked());
        startService(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
    }

    class MyReceiver extends BroadcastReceiver {

        //进度更新广播接收
        @Override
        public void onReceive(Context context, Intent intent) {
            int progress = intent.getIntExtra("progress", 0);
            sb.setProgress(progress);
        }
    }
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="com.qf.xs.day23countservicedemo.MainActivity">

    <TextView
        android:id="@+id/count_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="计数" />
    <Button
        android:id="@+id/click_start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始/暂停"/>
    <Button
        android:id="@+id/click_stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="停止"/>
</LinearLayout>
5.例子:下载图片,证明Service是在主线程中
package hsl.com.downloadservice;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;

/**
 * Created by Administrator on 2016/8/4 0004.
 */
public class DownlaodService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        //下载
        //获取url
        new Thread() {
            @Override
            public void run() {
                super.run();
                String url = intent.getStringExtra("url");
                try {
                    Bitmap bitmap = HttpUtils.download(url, null);
                    Intent in = new Intent("com.qf.download.FINISH");
                    in.putExtra("bitmap", bitmap);
                    LocalBroadcastManager.getInstance(DownlaodService.this).sendBroadcast(in);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();

        return super.onStartCommand(intent, flags, startId);
    }
}
ANR异常
package hsl.com.downloadservice;

import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;

/**
 * Created by Administrator on 2016/8/4 0004.
 */
public class DownlaodService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(final Intent intent, int flags, int startId) {
        //下载
        //获取url
       /* new Thread() {
            @Override
            public void run() {
                super.run();
                String url = intent.getStringExtra("url");
                try {
                    Bitmap bitmap = HttpUtils.download(url, null);
                    Intent in = new Intent("com.qf.download.FINISH");
                    in.putExtra("bitmap", bitmap);
                    LocalBroadcastManager.getInstance(DownlaodService.this).sendBroadcast(in);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }.start();*/
        for (int i = 0; i < 1000; i++) {
            SystemClock.sleep(100);
        }

        return super.onStartCommand(intent, flags, startId);
    }
}
6.例子:IntentService
工具类:
1》HttpUtils.java
package hsl.com.intentservicedemo;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by Administrator on 2016/8/4 0004.
 */
public class HttpUtils {
    /**
     * 进度更新
     */
    public final static int UPDATE_PROGRESS = 0x0001;
    /**
     * 下载开始
     */
    public final static int DOWNLOAD_START = 0x0002;
    /**
     * 下载完成
     */
    public final static int DOWNLOAD_FINISH = 0x0003;

    /**
     * 下载方法
     *
     * @param str     url
     * @param handler 当前状态更新时,发消息
     * @return
     * @throws Exception
     */
    public static Bitmap download(String str, Handler handler) throws Exception {
        //下载开始,通过handler发个下载开始通知
        if (handler != null) {
            Message msg = handler.obtainMessage();
            msg.what = DOWNLOAD_START;
            msg.obj = str;
            handler.sendMessage(msg);
        }

        HttpURLConnection conn = null;
        URL url = new URL(str);
        conn = (HttpURLConnection) url.openConnection();
        InputStream in = conn.getInputStream();
        int total = conn.getContentLength();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[2048];
        int tmp = 0;
        int sum = 0;
        while ((tmp = in.read(buffer)) != -1) {
            out.write(buffer, 0, tmp);
            sum += tmp;
            int per = (int) (sum * 100f / total);
            if (handler != null) {
                //进度更新,通过handler发消息
                Message msg = handler.obtainMessage();
                msg.what = UPDATE_PROGRESS;
                msg.arg1 = per;
                handler.sendMessage(msg);
            }
        }
        out.flush();
        Bitmap bitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length);
        if (handler != null) {
            //下载完成,通过handler发消息
            Message msg = handler.obtainMessage();
            msg.what = DOWNLOAD_FINISH;
            msg.obj = bitmap;
            handler.sendMessage(msg);
        }
        out.close();
        in.close();
        conn.disconnect();
        return bitmap;
    }

    /**
     * @param str      网址
     * @param fileName 保存的文件名
     * @param path     保存路径,不包含SD根目录
     * @param handler  用来发通知的Handler
     * @throws Exception
     */
    public static void saveFile(String str, String fileName, String path, Handler handler) throws Exception {
        //下载开始,通过handler发个下载开始通知
        if (handler != null) {
            Message msg = handler.obtainMessage();
            msg.what = DOWNLOAD_START;
            msg.obj = str;
            handler.sendMessage(msg);
        }

        HttpURLConnection conn = null;
        URL url = new URL(str);
        conn = (HttpURLConnection) url.openConnection();
        InputStream in = conn.getInputStream();
        int total = conn.getContentLength();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int tmp = 0;
        int sum = 0;
        while ((tmp = in.read(buffer)) != -1) {
            out.write(buffer, 0, tmp);
            sum += tmp;
            int per = (int) (sum * 100f / total);
            if (handler != null) {
                //进度更新,通过handler发消息
                Message msg = handler.obtainMessage();
                msg.what = UPDATE_PROGRESS;
                msg.arg1 = per;
                handler.sendMessage(msg);
            }
        }
        out.flush();
        //保存到SDcard
        String filePath = SDUtils.saveFile(out.toByteArray(), fileName, path);
        if (handler != null) {
            //下载完成,通过handler发消息
            Message msg = handler.obtainMessage();
            msg.what = DOWNLOAD_FINISH;
            msg.obj = filePath;
            handler.sendMessage(msg);
        }
        out.close();
        in.close();
        conn.disconnect();
    }
}
2》SDUtils.java
 package hsl.com.intentservicedemo;

import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Created by Administrator on 2016/8/5 0005.
 */
public class SDUtils {
    /**
     * 保存文件到SD卡中
     *
     * @param in       网络文件输入流
     * @param fileName 要保存的文件名
     * @param filePath 文件保存在哪个目录,不包含SD卡跟路径
     */
    public static void saveFile(InputStream in, String fileName, String filePath) throws Exception {
        //先判断SD卡是否可用
        if (!isMount()) {
            Log.e("TAG", "================SD卡不可用===========");
            return;
        }
        String path;
        //获取SDcart路径
        if (filePath == null) {
            //保存到SDcard根目录
            path = getSDcardPath();
        } else {
            path = getSDcardPath() + filePath;
        }
        //创建文件
        File file = new File(path);
        //如果目录文件不存在,则创建一个
        if (!file.exists()) {
            file.mkdirs();
        } else {
            //目录文件已经存在,但如果不是目录,则直接返回
            if (!file.isDirectory()) {
                Log.e("TAG", "============保存的路径不是有效的目录============");
                return;
            }
        }

        //创建文件
        File newFile = new File(file, fileName);
        OutputStream out = new FileOutputStream(newFile);
        byte[] buffer = new byte[2048];
        int tmp = 0;
        while ((tmp = in.read(buffer)) != -1) {
            out.write(buffer, 0, tmp);
        }
        out.flush();
        out.close();
        in.close();
    }

    /**
     * 保存文件到SD卡中
     *
     * @param arr      保存的字节数组
     * @param fileName 要保存的文件名
     * @param filePath 文件保存在哪个目录,不包含SD卡跟路径
     * @return 返回保存后的文件名及路径
     * @throws Exception
     */
    public static String saveFile(byte[] arr, String fileName, String filePath) throws Exception {
        //先判断SD卡是否可用
        if (!isMount()) {
            Log.e("TAG", "================SD卡不可用===========");
            return null;
        }
        String path;
        //获取SDcart路径
        if (filePath == null) {
            //保存到SDcard根目录
            path = getSDcardPath();
        } else {
            path = getSDcardPath() + filePath;
        }
        //创建文件
        File file = new File(path);
        //如果目录文件不存在,则创建一个
        if (!file.exists()) {
            file.mkdir();
        } else {
            //目录文件已经存在,但如果不是目录,则直接返回
            if (!file.isDirectory()) {
                Log.e("TAG", "============保存的路径不是有效的目录============");
                return null;
            }
        }

        //创建文件
        File newFile = new File(file, fileName);
        String newPath = newFile.getAbsolutePath();
        OutputStream out = new FileOutputStream(newFile);
        out.write(arr, 0, arr.length);
        out.flush();
        out.close();
        return newPath;
    }

    /**
     * 判断SD卡是否挂载
     *
     * @return
     */
    public static boolean isMount() {
        return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
    }

    /**
     * 获取SD卡路径,后面加上分隔符File.separator:/
     *
     * @return
     */
    public static String getSDcardPath() {
        return Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator;
    }
}
3》ImageService.java,即IntentService
package hsl.com.intentservicedemo;

import android.app.IntentService;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.io.File;

/**
 * Created by Administrator on 2016/8/4 0004.
 */
public class ImageService extends IntentService {
    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public ImageService() {
        super("myService");
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case HttpUtils.DOWNLOAD_START: {
                    Log.d("TAG", "download start");
                }
                break;
                case HttpUtils.DOWNLOAD_FINISH: {
                    Log.d("TAG", "download finish");
                    //启动播放
                    Intent mIntent = new Intent(Intent.ACTION_VIEW);
                    mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    Uri uri = Uri.fromFile(new File((String) msg.obj));
                    mIntent.setDataAndType(uri, "video/*");
                    startActivity(mIntent);
                }
                break;
                case HttpUtils.UPDATE_PROGRESS: {
                    Log.d("TAG", "download progress:" + msg.arg1);
                }
                break;
            }
        }
    };

    @Override
    protected void onHandleIntent(Intent intent) {
        String url = intent.getStringExtra("url");
        if (url != null) {
            try {
                HttpUtils.saveFile(url, "abc.mp3", "abc", handler);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
4》Activity.java
package hsl.com.intentservicedemo;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void start(View view) {
        Intent intent = new Intent(this, ImageService.class);
        intent.putExtra("url", "http://96.ierge.cn/11/168/336613.mp3");
//        intent.putExtra("url","http://www.ytmfdw.com/image/img3.jpg");
        startService(intent);
    }
}
5》权限
 <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
7.例子:DownloadManager
package com.qf.xs.day23dowloadmanagerdemo;

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.graphics.drawable.DrawableWrapper;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import java.io.File;

/**
 * 1.获得DownloadManager对象
 * 2.通过DownloadManager的内部类Request对象发起下载请求
 *     下载过程中,会自动发出通知,提示下载的进度
 *    如果下载完成,DownloadManager会发出广播,action为ACTION_DOWNLOAD_COMPLETE
 *
 * 3.注册广播接收器,接收下载完成广播,收到广播,通过Query对象查询下载结果
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button button;
//    String urlString = "http://10.20.163.12:8080/webserver/mp3/1.mp3";
    String urlString = "http://96.ierge.cn/11/168/336613.mp3";
    private DownloadManager downloadManager;
    private long id;
    private MyReceiver receiver;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.start_btn);
        button.setOnClickListener(this);

        downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);

        //注册下载状态的广播接收器
        receiver = new MyReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
        registerReceiver(receiver,filter);
    }

    @Override
    public void onClick(View v) {
        //用DownloadManager下载
        Uri uri = Uri.parse(urlString);
        //创建请求对象
        DownloadManager.Request request = new DownloadManager.Request(uri);
        //做一些设置
        //设置仅在wifi网络可下载
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        request.setTitle("屯里人下载中");
        request.setDescription("下载中,请稍后倾听。。。。");

        //通过DownloadManager,发起下载请求,得到该下载任务的id
        id = downloadManager.enqueue(request);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(receiver);
    }

    private class MyReceiver extends  BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                Log.e("print", "收到广播!");
                //获得完成下载任务的请求id号和要获取请求信息的id进行比较
                if (id == intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1)) {
                    //获得下载的信息
                    getDownloadMsg(id);
                }

            }
        }

        //根据请求的id过滤下载信息
        private void getDownloadMsg( long id) {
            DownloadManager.Query query = new DownloadManager.Query();
            //设置过滤条件
            query.setFilterById(id);

            //通过DownloadManager的对象,查询数据,过滤条件是id,所以返回的Cursor,一条记录对应一个id号
            Cursor cusor = downloadManager.query(query);
            if (cusor.moveToFirst())
            {
                String filePath = cusor.getString(cusor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                Log.e("print","文件路径:"+filePath);

                //发出通知:提示用户,文件下载完成,路径在哪里,点击通知就可以播放文件
                Intent playIntent = new Intent(Intent.ACTION_VIEW);
                playIntent.setDataAndType(Uri.fromFile(new File(filePath)), "video/*");
                startActivity(playIntent);

            }

        }
    }
}
1》获得DownloadManager对象
downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
2》.通过DownloadManager的内部类Request对象发起下载请求
Uri uri = Uri.parse(urlString);
        //创建请求对象
        DownloadManager.Request request = new DownloadManager.Request(uri);
        //做一些设置
        //设置仅在wifi网络可下载
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
        request.setTitle("屯里人下载中");
        request.setDescription("下载中,请稍后倾听。。。。");

        //通过DownloadManager,发起下载请求,得到该下载任务的id
        id = downloadManager.enqueue(request);
下载过程中,会自动发出通知,提示下载的进度
如果下载完成,DownloadManager会发出广播,action为ACTION_DOWNLOAD_COMPLETE
3》.注册广播接收器,接收下载完成广播,收到广播,通过Query对象查询下载结果
  private class MyReceiver extends  BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                Log.e("print", "收到广播!");
                //获得完成下载任务的请求id号和要获取请求信息的id进行比较
                if (id == intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID,-1)) {
                    //获得下载的信息
                    getDownloadMsg(id);
                }

            }
        }

        //根据请求的id过滤下载信息
        private void getDownloadMsg( long id) {
            DownloadManager.Query query = new DownloadManager.Query();
            //设置过滤条件
            query.setFilterById(id);

            //通过DownloadManager的对象,查询数据,过滤条件是id,所以返回的Cursor,一条记录对应一个id号
            Cursor cusor = downloadManager.query(query);
            if (cusor.moveToFirst())
            {
                String filePath = cusor.getString(cusor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                Log.e("print","文件路径:"+filePath);

                //发出通知:提示用户,文件下载完成,路径在哪里,点击通知就可以播放文件
                Intent playIntent = new Intent(Intent.ACTION_VIEW);
                playIntent.setDataAndType(Uri.fromFile(new File(filePath)), "video/*");
                startActivity(playIntent);

            }

        }
    }
4》扩展知识:打开系统播放器播放音乐
 String filePath = cs.getString(cs.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                Log.d("TAG", filePath);
                //启动播放
                Intent mIntent = new Intent(Intent.ACTION_VIEW);
                Uri uri = Uri.fromFile(new File(filePath));
                mIntent.setDataAndType(uri, "video/*");
                startActivity(mIntent);
8.例子:粘性服务与非粘性服务
 package com.qf.xs.day23startservicelife;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

public class ZhiLingService extends Service {
    public ZhiLingService() {
    }
    boolean flag = true;

    //暂时不管:
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.

        Log.e("print","onBind.....");
        throw new UnsupportedOperationException("Not yet implemented");

    }

    //在Destroy之前,只调用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("print","onCreate.....");
    }

    //可以调用多次
    /**
     * onStartCommand的返回值就代表了服务的粘性
     *
     * START_STICKY:粘性服务,被意外杀死后,服务会在资源足够的情况下重建,不会重传intent
     * START_REDELIVER_INTENT:粘性服务, 被意外杀死后,服务会在资源足够的情况下重建,同时会重传intent
     *
     * * START_NOT_STICKY:非粘性服务,被意外中止后,服务不能自动重建
     */
    @Override
    public int onStartCommand(Intent intent, final int flags, int startId) {
        if (intent != null) {
            Log.e("print", "onStartCommand....."+intent.getStringExtra("msg"));
        }else
        {
            Log.e("print", "onStartCommand....."+"没有intent");
        }

      /* 服务的生命周期方法其实也是运行在主线程上的,主线程不能被阻塞,阻塞会出现无响应关闭异常
       for (int i = 0; i < 10000; i++) {
            SystemClock.sleep(500);
            Log.e("print",i+".....");
        }*/
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    if (!flag)
                    {
                        break;
                    }
                    SystemClock.sleep(500);
                    Log.e("print",i+".....");
                }
            }
        }.start();

        return START_REDELIVER_INTENT;

    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("print","onUnbind.....");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("print","onDestroy.....");
        flag = false;
    }
}
三,粘性与非粘性服务
1.onStartCommand的返回值就代表了服务的粘性
2.START_STICKY:粘性服务,被意外杀死后,服务会在资源足够的情况下重建,不会重传intent
3.START_REDELIVER_INTENT:粘性服务, 被意外杀死后,服务会在资源足够的情况下重建,同时会重传intent
4.START_NOT_STICKY:非粘性服务,被意外中止后,服务不能自动重建
四,启动Service
startService
1.第一次调用时,onCreate()-->onCommandStart(),以后再次调用,只要该服务没有停止,不会再调用onCreate()方法,而会再次调用onCommandStart()方法
2.粘性服务与非粘性服务
 package com.qf.xs.day23startservicelife;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;

public class ZhiLingService extends Service {
    public ZhiLingService() {
    }
    boolean flag = true;

    //暂时不管:
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.

        Log.e("print","onBind.....");
        throw new UnsupportedOperationException("Not yet implemented");

    }

    //在Destroy之前,只调用一次
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("print","onCreate.....");
    }

    //可以调用多次
    /**
     * onStartCommand的返回值就代表了服务的粘性
     *
     * START_STICKY:粘性服务,被意外杀死后,服务会在资源足够的情况下重建,不会重传intent
     * START_REDELIVER_INTENT:粘性服务, 被意外杀死后,服务会在资源足够的情况下重建,同时会重传intent
     *
     * * START_NOT_STICKY:非粘性服务,被意外中止后,服务不能自动重建
     */
    @Override
    public int onStartCommand(Intent intent, final int flags, int startId) {
        if (intent != null) {
            Log.e("print", "onStartCommand....."+intent.getStringExtra("msg"));
        }else
        {
            Log.e("print", "onStartCommand....."+"没有intent");
        }

      /* 服务的生命周期方法其实也是运行在主线程上的,主线程不能被阻塞,阻塞会出现无响应关闭异常
       for (int i = 0; i < 10000; i++) {
            SystemClock.sleep(500);
            Log.e("print",i+".....");
        }*/
        new Thread(){
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    if (!flag)
                    {
                        break;
                    }
                    SystemClock.sleep(500);
                    Log.e("print",i+".....");
                }
            }
        }.start();

        return START_REDELIVER_INTENT;

    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.e("print","onUnbind.....");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e("print","onDestroy.....");
        flag = false;
    }
}
1》在StartService的时候,每次都会调用onStartCommand(Intent intent, int flags, int startId)方法,所以我们关注下该方法:
参数一:Intent:启动服务的Intent,可传参数进来
参数二:int flags:有3种取值,表示启动服务的方式
0:常用
START_FLAG_REDELIVERY:如果你的服务在处理它的时候被Kill掉, Intent不会丢失
START_FLAG_RETRY:表示服务之前被设为START_STICKY,则会被传入这个标记
参数三:startId的值为对这个service请求的activity或者其他实体的编号,唯一,每次调用onStartCommand会递增
2》其中参数flags默认情况下是0,对应的常量名为 START_STICKY_COMPATIBILITY。startId是一个唯一的整型,用于表示此次Client执行 startService(.)的请求请求标识,在多次startService(.)的情况下,呈现0,1,2....递增。另外,此函数具有 一个int型的返回值,具体的可选值及含义如下:
START_NOT_STICKY:当 Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中 Client明确再次调用startService(.)启动此Service。
START_STICKY:当Service因 为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调 onStartCommand(.)方法,但其中的Intent将是null。
START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(.)方法时,其中的Intent将是非空,将是最后一次调用startService(.)中的intent。
bindService
1.如果 Service 和访问者之间需要进行方法调用或数据交换,则应该使用 bindService() 和 unbindService() 方法启动、关闭 Service。
2.bindService(Intent service, ServiceConnection conn, int flags)
service :通过 Intent 指定要启动的 Service。
conn :该对象用于监听访问者与 Service 的连接情况,并相应回调如下方法
onServiceConnected(ComponentName name, IBinder service) :连接成功时回调该方法。IBinder参数对象可实现程序与被绑定 Service 之间的通信。实际开发时通常会采用继承 Binder(IBinder 的实现类)的方式实现自己的 IBinder 对象。
onServiceDisconnected(ComponentName name) :当 Service 所在的宿主进程由于异常中止而导致连接断开时回调该方法。
注:当调用者主动通过 unBindService() 方法断开连接时该方法不会被调用。
flags :指定绑定时是否自动创建 Service
0 :不自动创建。
BIND_AUTO_CREATE :自动创建。
3.注:多次调用 bindService() 方法并不会执行重复绑定,因而 onBind() 方法只会被回调一次。
4.开发步骤:
1》写一个class extends Service,别忘了注册
2》在Service类中,一般定义一个内部类class extends Binder,这个类中,可以写一些供Activity调用的方法
3》在Service类中,重写onBind()方法,返回内部类Binder实体对象
4》在Activity中,声明对应变量:Binder(即Service中定义的内部类);
5》在Activity中,声明一个ServiceConnection变量,重写onServiceConnected、onServiceDisconnected方法,在onServiceConnected方法中,对开始声明的Binder变量进行赋值
6》在Activity中,调用bindService()方法进行绑定,绑定成功后,即获取Binder对象实体,即可与Service进行交互
5.例子:绑定Activity与Service
Service
 package hsl.com.bindservice;

import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by Administrator on 2016/8/4 0004.
 */
public class MyService extends Service {

    int count=-1000;
    boolean quit = false;

    class MyBinder extends Binder {
        public int getCount() {
            return count;
        }
    }

    MyBinder binder;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("TAG", "=======onCreate===");

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("TAG", "======onBind");
        if (binder == null) {
            binder = new MyBinder();
        }
        return binder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("TAG", "======onStartCommand");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void unbindService(ServiceConnection conn) {
        super.unbindService(conn);
        Log.d("TAG", "======unbindService");
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d("TAG", "======onUnbind");
        return super.onUnbind(intent);
    }
}
Activity
 package hsl.com.bindservice;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    ServiceConnection conn;
    MyService.MyBinder binder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d("TAG", "==========onServiceConnected");
                binder = (MyService.MyBinder) service;
                Log.d("TAG", "这是Activity调用bindService,得到的:" + binder.getCount());
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {
                Log.d("TAG", "==========onServiceConnected");
            }
        };
    }

    public void doClick(View view) {
        switch (view.getId()) {
            case R.id.btn1: {
                //启动服务
            }
            break;
            case R.id.btn2: {
                //绑定服务
                Intent intent = new Intent(this, MyService.class);
                bindService(intent, conn, MyService.BIND_AUTO_CREATE);
            }
            break;
            case R.id.btn3: {
                //解绑服务
                unbindService(conn);
            }
            break;
            case R.id.btn4: {
                //结束服务
            }
            break;
        }
    }
}
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="hsl.com.bindservice.MainActivity">

    <Button
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="doClick"
        android:text="start服务" />

    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="doClick"
        android:text="bind服务" />

    <Button
        android:id="@+id/btn3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="doClick"
        android:text="unbind服务" />

    <Button
        android:id="@+id/btn4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="doClick"
        android:text="stop服务" />
</LinearLayout>
6.例子:音乐播放器
Service
 package hsl.com.musicbind;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 音乐播放服务
 * 功能:
 * 播放/暂停音频
 * 定时发送一个广播,告诉当前播放百分比
 * <p/>
 * 实现音乐播放:
 * MediaPlayer
 * <p/>
 * 把音频文件存放到res/raw目录下
 * <p/>
 * 使用定时器来定时发广播 Timer
 */
public class MusicService extends Service {

    class MusicBinder extends Binder {
        public int getPer() {
            try {
                if (player != null && player.isPlaying()) {
                    int per = (int) (player.getCurrentPosition() * 100f / player.getDuration());
                    return per;
                }


            } catch (Exception e) {

            }
            return 0;
        }

        public void pause() {
            if (player != null && player.isPlaying()) {
                player.pause();
            }
        }

        public void play() {
            if (player != null) {
                player.start();
            }
        }

        public void playOrPause(boolean isPlay) {
            if (isPlay) {
                play();
            } else {
                pause();
            }
        }
    }

    MusicBinder binder = new MusicBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d("TAG", "onBind=============");
        player.start();
        return binder;
    }

    //声明音乐播放器
    MediaPlayer player;

    //初始化工作
    @Override
    public void onCreate() {
        Log.d("TAG", "onCreate========");
        super.onCreate();
        //初始化player
        //加载mp3音频文件
        //参数一:Context
        //参数二:R资源
        player = MediaPlayer.create(this, R.raw.zmtlr);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        //音频播放器也要释放
        if (player != null) {
            player.stop();
            //释放资源
            player.release();
        }
    }
}
Activity
 package hsl.com.musicbind;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;
import android.widget.SeekBar;

import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    SeekBar sb;
    CheckBox cb;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        sb = (SeekBar) findViewById(R.id.sb);
        cb = (CheckBox) findViewById(R.id.cb);
        //注册广播

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //反注册本地广播
    }

    MusicService.MusicBinder binder;

    ServiceConnection conn = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            binder = (MusicService.MusicBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    Timer timer;

    //点击播放/暂停
    public void doClick(View view) {
        //启动服务,播放音乐
        //把view强转成CheckBox,并获取其状态
        CheckBox cb = (CheckBox) view;
        boolean isPlay = cb.isChecked();
        if (binder != null) {
            binder.playOrPause(isPlay);
        } else {
            Intent intent = new Intent(this, MusicService.class);
            bindService(intent, conn, Service.BIND_AUTO_CREATE);
            if (binder != null) {
                binder.playOrPause(isPlay);
            }
        }
        //启动定时器
        if (timer == null) {
            timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    if (binder != null) {
                        int per = binder.getPer();
                        sb.setProgress(per);
                    }
                }
            }, 0, 1000);
        }
    }

    //停止
    public void stop(View view) {
        Intent intent = new Intent(this, MusicService.class);
        intent.putExtra("isStop", true);
        startService(intent);
    }


}
五,IntentService
1.IntentService 是 Service 的子类,扩展了额外的功能。
2.Service 本身存在的两个问题:
Service 不会专门启动一条单独的进程,而是跟它所在的应用位于同一个进程中。
Service 也不是专门一条新的线程,因此不应在 Service 中直接处理耗时的任务及联网操作。
3.IntentService 弥补了 Service 的不足:它将使用队列来管理请求 Intent。对于异步的 startService() 请求,IntentService 会依次处理队列中的 Intent。由于 IntentService 使用新的 worker 线程处理 Intent 请求,因此不会阻塞主线程。
4.归纳 IntentService 的特征:
1》IntentService 会创建单独的 worker 线程来处理所有的 Intent 请求。
2》IntentService 会创建单独的 worker 线程来处理 onHandleIntent() 方法实现的代码,因此开发者无须处理多线程问题。
3》当所有请求处理完成后,IntentService 会自动停止,因此开发者无须调用 stopSelf()。
4》为 Service 的 onBind() 方法提供了默认实现(返回 null)。
5》为 Service 的 onStartCommand() 方法提供了默认实现,该实现将请求 Intent 添加到队列中。
5.扩展 IntentService 无须重写 onBind()、onStartCommand() 方法,只要重写 onHandleIntent() 方法及无参构造方法(构造方法中,必需调用super("workerThreadName"))
六,几个需要注意的地方
扩展 IntentService 无须重写 onBind()、onStartCommand() 方法,只要重写 onHandleIntent() 方法及无参构造方法(构造方法中,必需调用super("workerThreadName"))
1) Service 无论以何种方式创建,都是在应用的主线程里创建的,也就是说创建一个 Service 并不意味着生成了一个新的线程, Service 的创建过程是阻塞式的,因此也需要考虑性能,不能影响界面和逻辑上的后续操作。
2) 如果 Service 自己没有生成新的线程,那它也是运行在应用的主线程里的,因此 Service 本身并不能提高应用的响应速度和其他的性能,而是说通过这个后台服务生成新的线程来处理比较耗时的操作如大数据的读取等来提高响应, Service 自己并不能保证这一点。 Service 相当于提供了一个这些费时操作的平台,由它在后台创建新线程完成这些任务,以及视各种情况管理这些线程,包括销毁。
3) stopService 和 unbindService 都可以把 Service 停掉,但是如果希望明确立刻停掉 Service ,则使用 stopService 更安全,因为 unbindService 实质上是将与 Service 的连接数减一,当减为 0 的时候才会销毁该服务实例, stopService 的效果相当于将连接数立即减为 0 ,从而关闭该服务,所以在选择关闭方式上要视不同情况而定。
七,Service生命周期
八,Service与Thread
1.Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。
2.Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。
3.Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值