Android学习笔记重点笔记------探索服务(第一行代码)

一、服务

1、服务

服务是Android实现程序后台运行的方案,其不依赖于任何用户界面

2、Android多线程
(1)线程的启动方法一:
A:

class MyThread extends Thread{
      public void run(){
        // 这里输入处理事件的逻辑
          ··············
       }
 }
//启动该线程
new MyThread().start();

(2)线程启动的方法二:
B:

class MyThread implements Runnable{
         public void run(){
             // 这里输入处理事件的逻辑
             ··············
         }
}
//启动线程
MyThread myThread = new MyThread();
new Thread(myThread) .start();

(3)线程启动的方法三(常用):
C:

new Thread(new Runnable(){
    public void run(){
    // // 这里输入处理事件的逻辑
          ··············
    }).start;
}

注意:UI元素必须在主线程中进行,不能在子线程中进行。

这里我们创建一个工程为AndroidThreadTest的工程来学习:
具体思想为创建一个按钮和文本显示内容,在点击事件中创建子线程,用该线程实现文本内容的变化,具体代码如下:
activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <Button
        android:id="@+id/chang_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="改变文本内容"/>


    <TextView
        android:id="@+id/text"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="Hello World!"
        />

</RelativeLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView text;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button changText = (Button)findViewById(R.id.chang_text);
        text = (TextView)findViewById(R.id.text);
        changText.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.chang_text:
                //开始创建子线程
                new Thread(new Runnable() {
                    @Override
                    //执行线程操作
                    public void run() {
                        Log.d("MainActivity","子线程创建成功,正在运行,下一步,执行UI操作");
                        text.setText("修改界面成功,欢迎看见你");
                    }
                }).start();
        }
    }
}

然后运行,点击按钮后发现程序崩溃了。

查看错误信息可知,我们在子线程中进行UI操作这是不行的,UI操作应该切换至主线程中去完成。

那么,我们可以采用异步消息处理机制去解决在子线程中的UI操作。

异步通信机制通过在主线程中运行的handleMessage()方法进行处理子线程的想要完成的UI操作,我们通过消息(data数据)来通知主线程的进行UI显示。
在AndroidThreadTest的基础上进行修改。

扫描二维码关注公众号,回复: 8839391 查看本文章

在MainActivity中,

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView text;
    //定义整形变量,用于更新TextView这个动作
    public static final int UPDATE_TEXT = 1;
    //定义一个Handler对象
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {  //重写父类的handleMessage()方法
            /*如果接受字段等于UPDATE_TEXT,将修改UI内容*/
            switch (msg.what) {
                case UPDATE_TEXT:
                    Log.d("MainActivity","修改内容...");
                    text.setText("修改界面成功");
                    break;
                default:
                    break;
            }
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button changText = (Button)findViewById(R.id.chang_text);
        text = (TextView)findViewById(R.id.text);
        changText.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.chang_text:
                //开始创建子线程
                new Thread(new Runnable() {
                    @Override
                    //执行线程操作
                    public void run() {
                        Log.d("MainActivity","子线程创建成功");
                        //创建一个Message对象,
                        Message message = new Message();
                        //将对象的what字段设置为UPDATE_TEXT
                        message.what = UPDATE_TEXT;
                        //将信息发送出去,就会调用handler方法去修改文本内容。
                        handler.sendMessage(message);
                        /*Log.d("MainActivity","子线程创建成功,正在运行,下一步,执行UI操作");
                        text.setText("修改界面成功,欢迎看见你");*/
                    }
                }).start();
                break;
                default:
                    break;
        }
    }
}

3:异步消息处理机制。
其处理过程主要有四部分组成:(1)Message、(2)Handler、(3)MessageQueue、(4)Looper。
下面我们就来具体介绍:

(1)Message
是在线程间传递的消息,其内部携带少量信息,也可采 用 arg1和arg2携带整形数据,obj携带Object对象。

(2)Handler
用于发送和处理消息,发送消息一般采用Handler的 sendMessage()方法,而消息会最终到达 handleMessage()方法中。

(3)MessageQueue
为消息队列,用于存放所有通过Handler发送的消息,每个线程只有一个MessageQueue对象。

(4)Looper
为每个线程中的,队列MessageQueue管理者。调用Looper的loop()方法后,就会进入一个无限循环,每发现MessageQueue队列中存在消息,就会将其取出,并传递到handleMessage()方法中

4、AsyncTask
是一个需要创建子类去继承的抽象类,继承时需指定三个泛行参数,分别为(1)params:AsyncTask执行时需要传入的参数,可在后台任务中使用。(2)Progress:进度单位,显示任务进度。(3)Result:对任务结果进行返回
如:

class DownloadTask extends AsyncTask<Void,Integer,Boolean>{
  ···
}

而在该类中我们需要重写AsyncTask的方法。常用的有四个:
(1)onPreExecute()
后台任务执行前调用,进行界面的初始化操作,比如显示进度对话框
(2)onInBackground(Params…)
该方法在子线程中完成,用于处理所有的耗时任务,任务完成可使用return语句将执行结果返回,如果像将耗时任务进度反馈给主线程,可调用publishProgress(Params…)方法来完成
(3)onProgressUpdate(Progress…)
当后台任务调用publishProgress()方法后,该方法就会被调用,,该方法中携带的参数是后台任务中传递出来的,该方法可以对UI进行操作,利用参数中的数值对当前界面元素进行更新。
(4)onPostExecute(Result)
后台任务执行完毕并通过returen返回后,该方法就会被调用,可利用返回的数据进行UI操作,比如提醒任务执行的结果以及关闭进度条对话框,

启动该AsyncTask异步机制的方法为,new +子类+().execute();

二、服务的基本用法

创建服务的方法:
new --------Service ------Service

重写父类的三个方法:
(1)onCreate():服务创建时调用
(2)onStartCommand():服务启动时调用
(3)onDestroy():服务销毁时调用

服务为四大组建需要在AndroidMainifest.xml中注册。
我们新建一个ServiceTest项目,在java包中新建一个服务为MyService,在activty_main.xml中定义两个按钮,用于启动和停止服务:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:id="@+id/start_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="20dp"
        android:hint="启动服务"
         />
    <Button
        android:id="@+id/stop_service"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="停止服务"
        android:textSize="20dp"/>
</LinearLayout>

在主函数中处理两个按钮点击事件,通过Context类中的startService()和stopService()对服务进行启动和停止,如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService = findViewById(R.id.start_service);
        Button stopService = findViewById(R.id.stop_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start_service:
                Intent startIntent = new Intent(this,MyService.class);
                startService(startIntent);  //启动服务
                break;
            case R.id.stop_service:
                Intent stopIntent = new Intent(this,MyService.class);
                stopService(stopIntent);   //停止服务
                break;
                default:
                    break;
        }
    }
}

我们可以在MyService的任意位置调用stopSelf()让服务停下来。

那么怎么让服务去做什么呢?完成什么样的任务?
     我们需要onBinder()方法内构建我们的任务对象。例如,我们需要让后台去下载一个文件,我们需要构建一个Binder对象来下载,修改MyService中的内容:

·······································
private DownloadBinder mbinder = new DownloadBinder();
public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
       return mbinder;
    }    

class DownloadBinder extends Binder {
        public void startDownload(){
            Log.d("TAG","开始下载中...");
        }
        public void stopDownload(){
            Log.d("TAG","停止下载...");
        }
        public int getProgress(){
            Log.d("TAG"," 得到下载进度...");
            return 0;
        }
    }
      ··································

当活动与服务绑定后,调用服务里的Binder提供的方法,在MainActivity中实现:

······························
  private MyService.DownloadBinder downloadBinder;

  private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            downloadBinder = (MyService.DownloadBinder)service;
            downloadBinder.startDownload();
            downloadBinder.getProgress();
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };  

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button startService = findViewById(R.id.start_service);
        Button stopService = findViewById(R.id.stop_service);
        Button unbindService = findViewById(R.id.unbind_service);
        Button onbindService = findViewById(R.id.onbind_service);
        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        onbindService.setOnClickListener(this);
        unbindService.setOnClickListener(this);
    }
Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.start_service:
                Intent startIntent = new Intent(this,MyService.class);
                startService(startIntent);  //启动服务
                break;
            case R.id.stop_service:
                Intent stopIntent = new Intent(this,MyService.class);
                stopService(stopIntent);   //停止服务
                break;
            case R.id.onbind_service:
                Intent bindIntent = new Intent(this,MyService.class);
                bindService(bindIntent,connection,BIND_AUTO_CREATE);
                break;
            case R.id.unbind_service:
               unbindService(connection);
               break;
               default:
                   break;
        }
    }
    ·················

在oncreate()方法中添加一个后台通知,将MyService编程一个前台服务。如下所示:

 //服务创建时调用
   public void onCreate(){
        super.onCreate();
        Log.d(TAG,"服务创建中...");
        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);
    }

对于耗时操作中需要用到开启子线程和结束服务的方法,android提供了一个异步会自动停止的服务的类IntentService类。这里我们新建一个MyIntentService类:

public class MyIntentService extends IntentService {
   public MyIntentService() {
       super("MyIntentService");  //调用父类的有参构造函数
   }
   @Override
   protected void onHandleIntent(Intent intent) {
       //打印当前线程的id
       Log.d("MyIntentService","Thread id is " +Thread.currentThread().getId());
   }
   @Override
   public void onDestroy() {
       super.onDestroy();
       Log.d("MyIntentService","销毁执行中");
   }
}  

MainActivity中添加以下逻辑:

case R.id.start_intent_service:
              Log.d("MainActivity","Thread id is "+Thread.currentThread().getId());
              Intent intent = new Intent(this,MyIntentService.class);
              startService(intent);
              break;

运行后发现:
在这里插入图片描述
程序运行完成后,自动销毁。

发布了31 篇原创文章 · 获赞 20 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/souhanben5159/article/details/86671776