Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲

Services

編輯:關於Android編程

A Service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component can start a service and it will continue to run in the background even if the user switches to another application. Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC). For example, a service might handle network transactions, play music, perform file I/O, or interact with a content provider, all from the background.

服務後台長時間運行,無界面,組件可以綁定一個服務與它交互

A service can essentially take two forms:

Started

A service is “started” when an application component (such as an activity) starts it by calling startService(). Once started, a service can run in the background indefinitely(無限期地), even if the component that started it is destroyed. Usually, a started service performs a single operation and does not return a result to the caller. For example, it might download or upload a file over the network. When the operation is done, the service should stop itself.

Bound

A service is “bound” when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC). A bound service runs only as long as another application component is bound to it. Multiple components can bind to the service at once, but when all of them unbind, the service is destroyed.


服務通過startService開啟,將一直在後台運行,服務一般不返回值,在後台完成任務,最好關閉服務 服務是“綁定”當一個應用程序組件綁定到它通過調用bindService(),綁定服務提供了一個客戶機-服務器接口,允許組件與服務交互,多個組件可以綁定到服務,但是當他們解開,服務被摧毀。

Caution: A service runs in the main thread of its hosting process—the service does not create its own thread and does not run in a separate process (unless you specify otherwise). This means that, if your service is going to do any CPU intensive work or blocking operations (such as MP3 playback or networking), you should create a new thread within the service to do that work. By using a separate thread, you will reduce the risk of Application Not Responding (ANR) errors and the application’s main thread can remain dedicated to user interaction with your activities.


警告:一個服務運行在主線程的托管進程(服務不創建自己的線程和不運行在一個單獨的進程(除非您指定)。這意味著,如果你的服務要做任何CPU密集型工作或阻塞操作(如MP3播放或網絡),您應該創建一個新線程內的服務工作。通過使用一個單獨的線程,你會減少應用程序沒有響應的風險(ANR)錯誤和應用程序的主線程可以繼續致力於用戶交互活動。


Service生命周期圖

服務的生命周期

startService開啟服務

startService開啟服務示例

public class DemoService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    //必須要重寫的方法
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

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

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


}
 //開啟服務
    public void click1(View view) {
        Intent intent = new Intent(this,DemoService.class);
        startService(intent);

    }
    //關閉服務
    public void click2(View view) {
        Intent intent = new Intent(this,DemoService.class);
        stopService(intent);

    }


  ...
  
      
      ...
  
onCreate–onStartCommand onCreate在在第一次創建時執行,多次開啟服務,只會開啟onStartCommand 方法 服務開啟後,會長期執行,直到用戶手工停止

bindService開啟服務

目的是為了調用服務裡的方法

   //點擊按鈕 綁定服務 開啟服務的第二種方式
    public void click3(View view) {
        Intent intent = new Intent(this,DemoService.class);
        //連接到demoservice 這個服務
        conn = new Myconn();
        bindService(intent, conn,BIND_AUTO_CREATE);

    }
     @Override
    protected void onDestroy() {
        //當activity銷毀時要解綁服務
        unbindService(conn);
        super.onDestroy();
    }


    //定義一個類來監視服務的狀態
    private class Myconn implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            System.out.println("onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            System.out.println("onServiceDisconnected");
        }
    }

第一次點擊按鈕時會執行服務的onCreate方法和onBind方法 當onBind方法返回為null時,onServerConnected方法是不執行的 第二次點擊bind服務時,服務沒有響應 bind方式開啟的服務,activity和service同生共死 服務不能多次解綁,多次解綁會有異常 通過bind方式開啟服務,服務不能在設置裡找到 相當於是一個隱形的服務

bindService示例

BanZhengService .java

public class BanZhengService  extends Service{
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }
    public  void banZheng(int money) {
        if(money>1000){
            Toast.makeText(getApplicationContext(),"我是領導 把證給你辦了",Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(getApplicationContext(),"就這點錢 還想辦事...",Toast.LENGTH_LONG).show();
        }
    }
    //定義中間人ibinder
    public class MyBinder extends Binder {
        public void callbanZheng(int money){
            //調用辦證的方法
            banZheng(money);
        }
    }
}

配置service


MainActivity.java

public class MainActivity extends AppCompatActivity {

    private MyConn conn;
    private BanZhengService.MyBinder myBinder;

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

        Intent intent= new Intent(this,BanZhengService.class);
        conn = new MyConn();
        bindService(intent,conn,BIND_AUTO_CREATE);
    }
    public void click(View view) {
        myBinder.callbanZheng(100000);
    }

    @Override
    protected void onDestroy() {
        //解綁服務
        unbindService(conn);
        super.onDestroy();
    }

    //監視服務的狀態
    public  class MyConn implements ServiceConnection{

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            myBinder = (BanZhengService.MyBinder) iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    }
}

在BanZhengService裡定義中間人MyBinder,定義一個方法調用service裡的方法
這裡寫圖片描述

bindService示例2

DemoService.java

public class DemoService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new MyBinder();
    }

    public void banZheng(int money) {
        if (money > 1000) {
            Toast.makeText(getApplicationContext(), "我是領導 把證給你辦了", Toast.LENGTH_LONG).show();
        } else {
            Toast.makeText(getApplicationContext(), "就這點錢 還想辦事...", Toast.LENGTH_LONG).show();
        }
    }

    public void playMajing() {
        System.out.println("陪領導打麻將");
    }

    public void 洗桑拿() {
        System.out.println("陪領導洗桑拿");
    }

    //定義中間人ibinder
    public class MyBinder extends Binder implements Iservice {

        public void callbanZheng(int money) {
            //調用辦證的方法
            banZheng(money);
        }

        public void callPlayMajing() {
            playMajing();
        }

        public void callXiSanNa() {
            洗桑拿();
        }
    }
}

Iservice.java

public interface Iservice {

    //把領導想暴露的方法
    public void callbanZheng(int money);
}

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private MyConn conn;
    private Iservice myBinder;

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

        Intent intent = new Intent(this, DemoService.class);
        conn = new MyConn();
        bindService(intent, conn, BIND_AUTO_CREATE);
    }

    public void click(View view) {
        myBinder.callbanZheng(100000);
        //只有領導才能調桑拿
        //myBinder.callPlayMajing();
        // myBinder.callXiSanNa();
    }

    @Override
    protected void onDestroy() {
        //解綁服務
        unbindService(conn);
        super.onDestroy();
    }

    //監視服務的狀態
    private class MyConn implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            myBinder = (Iservice) iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    }
}

IntentService

服務中的代碼都是默認運行在主線程當中的,如果直接在服務裡去處理一些耗時的邏輯,就很容易出現ANR(Application Not Responding)的情況。
所以這個時候就需要用到Android多線程編程的技術了,我們應該在服務的每個具體的方法裡開啟一個子線程,然後在這裡去處理那些耗時的邏輯。因此,一個比較標准的服務就可以寫成如下形式:

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    //開啟一個子線程
     new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 處理具體的邏輯
            }  
        }).start();
        return super.onStartCommand(intent, flags, startId);
    }

}

但是,這種服務一旦啟動之後,就會一直處於運行狀態,必須調用stopService()或者stopSelf()方法才能讓服務停止下來。所以,如果想要實現讓一個服務在執行完畢後自動停止的功能,就可以這樣寫:

public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        new Thread(new Runnable() {  
            @Override  
            public void run() {  
                // 處理具體的邏輯
                stopSelf();
            }

        return super.onStartCommand(intent, flags, startId);
    }

}

雖說這種寫法並不復雜,但是總會有一些程序員忘記開啟線程,或者忘記調用stopSelf()方法。為了可以簡單地創建一個異步的、會自動停止的服務,Android專門提供了一個IntentService類,這個類就很好地解決了前面所提到的兩種尴尬,下面我們就來看一下它的用法。

public class MyIntentService extends IntentService {
    public MyIntentService() {
        super("MyIntentService");
        // 調用父類的有參構造函數
    }

   /* public MyIntentService(String name) {
        super(name);
    }*/

    @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", "onDestroy executed");
    }
}

開啟MyIntentService

 public void click5(View view) {
        // 打印主線程的id
        Log.d("MainActivity", "Thread id is " + Thread.currentThread(). getId());
        Intent intentService = new Intent(this, MyIntentService.class);
        startService(intentService);
    }

這裡寫圖片描述
可以看到,不僅MyIntentService和MainActivity所在的線程id不一樣,而且onDestroy()方法也得到了執行,說明MyIntentService在運行完畢後確實自動停止了。這就是集開啟線程和自動停止於一身IntentService.<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMiBpZD0="混合方式開啟服務">混合方式開啟服務

我們知道,通過startservice開啟服務,服務會一直運行下去,除非自己stopservice;而bindservice開啟服務,可以調用服務裡的方法,但服務的生命周期和activity是綁定的,同生共死;可是我想服務長期運行,又想調用服務裡的方法,這就需要混合方式開啟服務

開啟流程
- 先調用startService方法開啟服務,讓服務長期運行
- 調用bindService方法開啟服務 ,去獲取中間人對象
關閉流程
- unbindService 解綁服務
- stopService 關閉服務

混合方式開啟服務示例


MainActivity.java

public class MainActivity extends AppCompatActivity {

    private IService iService;
    private Myconn conn;

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

        //混合開啟服務
        //先調用startService 目的是可以保證服務在後台長期運行
        Intent intent = new Intent(this,MusicService.class);
        startService(intent);
        //調用bindservice 目的是獲取我們定義的中jian人對象 就可以間接的調用服務
        conn = new Myconn();
        bindService(intent, conn,BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        //當activity銷毀的時候 解綁服務 不報紅色日志
        unbindService(conn);
        super.onDestroy();
    }

    public void click1(View view) {
    //播放
        iService.callplayMusic();
    }
    public void click2(View view) {
    //暫停
        iService.callpauseMusic();
    }
    public void click3(View view) {
    //繼續播放
        iService.callreplayMusic();
    }

    private class Myconn implements ServiceConnection {
        //當服務連接成功
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            //獲取我們定義的中間人Ibinder
            iService = (IService) iBinder;

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    }
}

MusicService.java

public class MusicService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        //把我們定義的中間人返回
        return new MyBinder();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        /**
         * 開啟一個線程,驗證後台服務是否一直運行
         */
        final Handler handler = new Handler();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // TODO Auto-generated method stub
                //要做的事情
                Log.d("MusicService", new Date().toString());
                //每隔十秒執行一次
                handler.postDelayed(this, 10000);
            }
        };
        //兩秒後執行
        handler.postDelayed(runnable, 2000);

        return super.onStartCommand(intent, flags, startId);
    }

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

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

    public void playMusic() {
        Toast.makeText(getApplication(), "音樂播放了", Toast.LENGTH_SHORT).show();
        System.out.println("音樂播放了");
    }

    public void pauseMusic() {
        Toast.makeText(getApplicationContext(), "音樂暫停了", Toast.LENGTH_SHORT).show();
        System.out.println("音樂暫停了");
    }

    public void replayMusic() {
        Toast.makeText(getApplicationContext(), "音樂繼續播放了", Toast.LENGTH_SHORT).show();
        System.out.println("音樂繼續播放了");
    }

    //定義service和activity的中間人對象(Ibinder)
    private class MyBinder extends Binder implements IService {

        @Override
        public void callplayMusic() {
            playMusic();
        }

        @Override
        public void callpauseMusic() {
            pauseMusic();
        }

        @Override
        public void callreplayMusic() {
            replayMusic();
        }
    }
}

IService.java

public interface IService {
    //在接口裡暴露方法
    public void callplayMusic();
    public void callpauseMusic();
    public void callreplayMusic();
}

這樣就可以調用service裡的方法了
即使把應用程序關閉後,也會定時打印出時間,說明service還在後台運行,只要不把進程關閉,service就會一直運行下去

通過廣播開啟服務

四大組件可以互相聯系,共同為應用程序服務
當接收到特定廣播的時候,如果有需求的話,可以開啟服務來相應的操作,這也是開啟服務的一種方式.

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        //把服務開啟
        Intent intent1= new Intent(context,PhoneService.class);
        context.startService(intent1);
        System.out.println("開啟服務");
    }
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved