Androidc学习笔记七之Service服务

来源:互联网 发布:redis 缓存数据库表 编辑:程序博客网 时间:2024/06/10 04:36

android中的Service服务开发和理解

2017/3/13 记载

四大组件之Service服务

服务并不是运行在一个独立的进程当中的,而是依赖于创建服务时所在的应用程序进程中。
服务:
是实现android中实现程序后台运行的解决方案。它很适合去执行那些不需要在用户交互中长期运行的任务。
并且实际上服务是不会自动开启线程,所有服务代码都是运行在主线程上的,所以我们需要手动创建子线程。


继承:直接实现runable接口或者继承Thread父类(子线程run方法中),启动start()线程。
继承方式:New MyThread().start();  实现接口方法:new Thread(MyThread).start();



和很多UI库一样。android的UI库也是线程不安全,所以想要更新应用程序当中的UI元素,
必须在主线程中进行,否则就会出现异常。
我们写一个小例子看看就知道了
activity_main<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    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"    tools:context="com.example.ldp.com.androidthreadtest.MainActivity">    <Button        android:id="@+id/change_text"        android:text="Change Text"        android:textAllCaps="true"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/text"        android:layout_centerInParent="true"        android:textSize="20sp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World!" /></RelativeLayout>

MainActivitypackage com.example.ldp.com.androidthreadtest;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private TextView text;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text = (TextView)findViewById(R.id.text);        Button button = (Button)findViewById(R.id.change_text);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        text.setText("Nice to meet you");                    }                }).start();            }        });    }}

效果图:


用android中自带的异步消息处理的使用方法来更新UI就可以解决了
改一下代码:MainActivity
package com.example.ldp.com.androidthreadtest;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    public static final int UPDATE_TEXT=1;    private TextView text;    private Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            switch (msg.what){                //这样就可以实现多个异步消息来实现UI的更新了                case UPDATE_TEXT:                    text.setText("Nice to meet you");                    break;                default:                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text = (TextView)findViewById(R.id.text);        Button button = (Button)findViewById(R.id.change_text);        button.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                new Thread(new Runnable() {                    @Override                    public void run() {                        //使用Message对象调用                        Message message = new Message();                        message.what = UPDATE_TEXT;                        handler.sendMessage(message);                    }                }).start();            }        });    }}

再运行一次就没问题了,可以看到在子线程中并没有执行UI操作,只是创建了一个Message的对象
把这个对象传给handle,然后handleMessage()对它进行处理,这个时候这个方法就是让操作在主线程中运行而不是在子线程。

解析异步消息机制:

它共分四部分:Message、Handle、MessafeQueue、Looper
Message
:用于在线程之间传递消息,也可以发送整形数据
handler:处理者,用于发送和处理消息。sendMessage() handleMessage()
MessageQueue:消息队列,在其中存放Handler发送的消息,会一直存在,每一个线程中只会有一个MessageQueue对象
Looper:是每个线程中的MessageQueue的管家,调动loop()方法后就会进入到找消息的无线循环中,找到传给handleMessage()中,每一个线程中只会有一个Looper对象。
效果图:
               

如果嫌上面的处理步骤很麻烦可以去了解一下android中提供的另外一种工具AsyncTask(基于异步机制的封装)
当然步骤是简单多了。

服务的基本与用法:
直接在项目上就可以新建service服务类,需要去继承service这个类,并实现几个方法
注意:服务是需要在AndroidManifast.xml中注册的
如:新建一个MyService类,在上一个异步消息机制项目上修改
package com.example.ldp.com.androidthreadtest;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.util.Log;public class MyService extends Service {    public MyService() {    }    @Override    public IBinder onBind(Intent intent) {        // TODO: Return the communication channel to the service.        throw new UnsupportedOperationException("Not yet implemented");    }    @Override    public void onCreate() {        super.onCreate();        Log.d("MyService","OnCreat Method Start");    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d("MyService","onStartCommand Method Start");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        super.onDestroy();        Log.d("MyService","onDestroy Method Start");    }}

activity_main<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent">    <Button        android:id="@+id/change_text"        android:text="Change Text"        android:textAllCaps="false"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/start_service"        android:text="Start Service"        android:textAllCaps="false"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/stop_service"        android:text="Stop Service"        android:textAllCaps="false"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/text"        android:layout_centerInParent="false"        android:textSize="20sp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World!" /></LinearLayout>

MainActivity.javapackage com.example.ldp.com.androidthreadtest;import android.content.Intent;import android.os.Handler;import android.os.Message;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends AppCompatActivity implements View.OnClickListener{    public static final int UPDATE_TEXT=1;    private TextView text;    private Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            switch (msg.what){                //这样就可以实现多个异步消息来实现UI的更新了                case UPDATE_TEXT:                    text.setText("Nice to meet you");                    break;                default:                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text = (TextView)findViewById(R.id.text);        Button button = (Button)findViewById(R.id.change_text);        Button startButton = (Button)findViewById(R.id.start_service);        Button stopButton = (Button)findViewById(R.id.stop_service);        startButton.setOnClickListener(this);        stopButton.setOnClickListener(this);        button.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.change_text:                new Thread(new Runnable() {                    @Override                    public void run() {                        //使用Message对象调用                        Message message = new Message();                        message.what = UPDATE_TEXT;                        handler.sendMessage(message);                    }                }).start();                break;            case R.id.start_service:                Intent startIntent = new Intent(this,MyService.class);                startService(startIntent);                break;            case R.id.stop_service:                Intent stopIntrnt = new Intent(this,MyService.class);                stopService(stopIntrnt);                break;            default:                break;        }    }}

效果图,点击startService发现有oncreat方法和onStartCommand方法执行,多点击几次却只有onStartCommand方法执行
点击停止就执行onDestory方法
效果图:


有没有发现我们是通过活动来通知服务可以执行的。并没有用到活动的作用。

服务的生命周期
效果图:
                

比如天气软件,当使用的时候会在状态栏显示天气状态,这是前台服务的一种应用方式。
刚刚那个例子当中修改例子:MyService
 
@Override    public void onCreate() {        super.onCreate();        Log.d("MyService","OnCreat Method Start");        Intent intent = new Intent(this,MainActivity.class);        PendingIntent pi = PendingIntent.getActivity(this,0,intent,0);        Notification notification = new NotificationCompat.Builder(this)                .setContentTitle("This is content title").setContentText("This is content ")                .setWhen(System.currentTimeMillis()).setSmallIcon(R.mipmap.ic_launcher)                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher))                .setContentIntent(pi).build();        startForeground(1,notification);    }

效果图:
                                             

注意,如果在服务当中发写大量的逻辑代码处理,很有可能导致应用出现ANR(Application Not Response)
所以一个标准的服务,应该写成MyService
 
@Override    public int onStartCommand(Intent intent, int flags, int startId) {        Log.d("MyService","onStartCommand Method Start");        new Thread(new Runnable() {            @Override            public void run() {                //具体逻辑实现                stopSelf();//在这里实现停止服务的目的是为了避免一直运行下去,也可以写成stopService()            }        }).start();        return super.onStartCommand(intent, flags, startId);    }

在开始过程中时常会忘记开启线程或者是忘记调用停止服务,导致程序老出问题,所以android中提供了
IntentService父类
package com.example.ldp.com.androidthreadtest;import android.app.IntentService;import android.content.Intent;import android.util.Log;/** * Created by Administrator on 2017/3/13. */public class MyIntentService extends IntentService {    public MyIntentService(){        super("MyIntentService");//调用父类的构造函数    }    @Override    protected void onHandleIntent(Intent intent) {        //实现逻辑而不用担心ARN的问题        Log.d("MyIntentService","Thread is "+Thread.currentThread().getId());    }    @Override    public void onDestroy() {        super.onDestroy();        Log.d("MyIntentService","OnDestory Method");    }}

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <Button
        android:id="@+id/change_text"
        android:text="Change Text"
        android:textAllCaps="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/start_service"
        android:text="Start Service"
        android:textAllCaps="false"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/
stop_service"        android:text="Stop Service"        android:textAllCaps="false"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <Button        android:id="@+id/myintent_service_start"        android:text="Start MyIntent Service"        android:textAllCaps="false"        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <TextView        android:id="@+id/text"        android:layout_centerInParent="false"        android:textSize="20sp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Hello World!" /></LinearLayout>

在AndroidManfest.xml中注册服务

  <service            android:name=".MyService"            android:enabled="true"            android:exported="true">        </service>        <service android:name=".MyIntentService"/>

MyService.java不变


MainActivity.java package com.example.ldp.com.androidthreadtest;import android.content.Intent;import android.os.Handler;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{    public static final int UPDATE_TEXT=1;    private TextView text;    private Handler handler = new Handler(){        @Override        public void handleMessage(Message msg) {            switch (msg.what){                //这样就可以实现多个异步消息来实现UI的更新了                case UPDATE_TEXT:                    text.setText("Nice to meet you");                    break;                default:                    break;            }        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        text = (TextView)findViewById(R.id.text);        Button button = (Button)findViewById(R.id.change_text);        Button startButton = (Button)findViewById(R.id.start_service);        Button stopButton = (Button)findViewById(R.id.stop_service);        Button myintetnbutton = (Button)findViewById(R.id.myintent_service_start);        myintetnbutton.setOnClickListener(this);        startButton.setOnClickListener(this);        stopButton.setOnClickListener(this);        button.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.change_text:                new Thread(new Runnable() {                    @Override                    public void run() {                        //使用Message对象调用                        Message message = new Message();                        message.what = UPDATE_TEXT;                        handler.sendMessage(message);                    }                }).start();                break;            case R.id.start_service:                Intent startIntent = new Intent(this,MyService.class);                startService(startIntent);                break;            case R.id.stop_service:                Intent stopIntrnt = new Intent(this,MyService.class);                stopService(stopIntrnt);                break;            case R.id.myintent_service_start:                Log.d("MainActivity","Thread is "+Thread.currentThread().getId());                Intent intentService = new Intent(this,MyIntentService.class);                startService(intentService);                break;            default:                break;        }    }}

效果图:



做一个集合前面学习的例子:

0 0