show code block

2017年8月20日 星期日

Android元件 — Service 服務

前言:

這是拿來做大量運算和下載的地方。
並且不阻塞你前台的線程。
可以用來做異步download
通常更新app或是網路下載都可以寫在這邊,就算Line或是微信突然跳出來,點到離開app,也不用擔心下載被中斷導致出錯。

此篇參考:
http://givemepass.blogspot.tw/2015/11/bindservice.html
http://www.cnblogs.com/yejiurui/p/3429451.html
http://xnfood.com.tw/android/


程式碼:

https://developer.android.com/guide/components/services.html?hl=zh-tw
這裡已經有中文版的android介紹。
稍微區分一下startService 和 bindService有什麼區別。

bindService 的生命週期是和activity綁在一起的。
你呼叫他之後,只要呼叫他的activity被消滅後,他也會隨之關閉。
這邊有一個Service和activity溝通的橋樑 ServiceConnection

startService 是支持後台運行的,你首次運行startService的那一剎那,只要不手動關閉(或是記憶體不足被系統砍掉),就會一直運行下去。
適合長時間監控手機的app,像是小米手環之類的。




先從startService開始吧

先寫一個自己的Service 並且extands Service
我命名為 CountService.java這邊寫一個計時Thread到開啟Service內讓他倒數。
等等看Log就可以知道他到底有無在運作。
然後寫一個boolean來控制是否進入倒數處,如果onDestory這個Service,可以完美的停止倒數。

public class CountService extends Service {
    boolean threadDisable;
    int count;

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


    public void onCreate() {
        super.onCreate();
        new Thread(new Runnable() {
            public void run() {
                while (!threadDisable) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {

                    }
                    count++;
                    Log.v("CountService", "Count is = " + count);
                }
            }
        }).start();
    }

    public void onDestroy() {
        this.threadDisable = true;
        super.onDestroy();
    }

    public int getConunt() {
        return count;
    }

    class ServiceBinder extends Binder {
        public CountService getService() {
            return CountService.this;
        }
    }
}

 
然後在AndroidManifest.xml內註冊自己的Service


開始使用它吧!

我們來拉個activity_main.xml的畫面
activity_main.xml
<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"
    tools:context=".MainActivity" 
    android:orientation="vertical"    
    >

 <Button
 android:id="@+id/startServerButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="開啟Service"
 />
<Button
 android:id="@+id/sutdownServerButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="關閉Service"
 />
<Button
 android:id="@+id/startBindServerButton"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="開啟bindService activity"
 />

</LinearLayout>
 

然後在MainActivity.java內調用Service
public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    Button startServiceButton;// 開啟startService
    Button shutDownServiceButton;// 關閉
    Button startBindServiceButton;// 開啟bindService

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

        initView();
        initListener();
    }


    public void initView() {
        startServiceButton = (Button) findViewById(R.id.startServerButton);
        startBindServiceButton = (Button) findViewById(R.id.startBindServerButton);
        shutDownServiceButton = (Button) findViewById(R.id.sutdownServerButton);
    }

    public void initListener() {
        startServiceButton.setOnClickListener(startService);
        shutDownServiceButton.setOnClickListener(shutdownService);
        startBindServiceButton.setOnClickListener(startBinderService);
    }


    public Button.OnClickListener startService = new Button.OnClickListener() {
        public void onClick(View view) {

            Intent intent = new Intent(MainActivity.this,
                    CountService.class);
            startService(intent);
            Log.v(TAG, "start Service");
        }
    };


    public Button.OnClickListener shutdownService = new Button.OnClickListener() {
        public void onClick(View view) {
            Intent intent = new Intent(MainActivity.this,
                    CountService.class);
            stopService(intent);
            Log.v(TAG, "shutDown serveice");
        }
    };


    public Button.OnClickListener startBinderService = new Button.OnClickListener() {
        public void onClick(View view) {
          
            Log.v(TAG, "還未實作");
        }
    };
}
 
此時你按下『開啟Service』的按鈕應該就可以開始動作了。
這時候你可以看一下Log

開始startService囉!!

之後先來測試一下當我把app直接滑到後,Service是否存活。

你把app關閉後,可以看到Log還是繼續在倒數的。

如果你想關閉,就在打開app按下『關閉Service』按鈕就行了。




然後我們來實作一下bindService

為了方便測試,我們另外創了一個Activity,讓bindService和那個Activity作綁定

bindService和startService最大的差異就是多了一個ServiceConnection做綁定。
這邊一進入activity就開始運作,一離開activity就停止。
 必須調用它。
bind_activity.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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="啟動bindService" />
</LinearLayout>
 
bindTestActivity.java
public class bindTestActivity extends Activity {

    CountService countService;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.bind_activity);


        Intent intent = new Intent(bindTestActivity.this, CountService.class);
        /** 開啟Service */
        bindService(intent, conn, Context.BIND_AUTO_CREATE);

    }


    //BindService和activity 的溝通方式
    private ServiceConnection conn = new ServiceConnection() {
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            countService = ((CountService.ServiceBinder) service).getService();

        }

        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            countService = null;
        }

    };

    protected void onDestroy() {
        super.onDestroy();
        this.unbindService(conn);
        Log.v("BindService", "離開activity時,關掉BindService");
    }
}
 


這時候可以試試看效果囉。
打開app點擊『開啟bindService activity』看Log就可以看到在計數。
離開activity就會停止計數。





Demo:
https://drive.google.com/open?id=0Byk75IYx-dKXeUZJWno1Qks1X0E



2 則留言:

  1. Tritanium dioxide in food - Titanium Art Institute
    Food babyliss pro titanium straightener for Taste: Tritanium is titanium exhaust tubing one of the most titanium trim hair cutter popular table sauces. They have titanium blue high-end titanium white wheels heat, and they are well blended with a richly-flavory,

    回覆刪除

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...