Android—Service與Activity的交互

来源:http://www.cnblogs.com/yunfang/archive/2017/01/06/6258053.html
-Advertisement-
Play Games

service—Android的四大組件之一。人稱“後臺服務”指其本身的運行並不依賴於用戶可視的UI界面 實際開發中我們經常需要service和activity之間可以相互傳遞數據維持程式的運行。 先瞭解Service的生命周期吧。 新建一個類繼Service: 新建以上類並繼承Service後只會 ...


   service—Android的四大組件之一。人稱“後臺服務”指其本身的運行並不依賴於用戶可視的UI界面

   實際開發中我們經常需要service和activity之間可以相互傳遞數據維持程式的運行。

   先瞭解Service的生命周期吧。

新建一個類繼Service:

package com.example.myservicedemo.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

/**
 * 服務類(需要在項目清單文件中註冊服務)
 * 
 * @author lenovo
 *
 */
public class MyService extends Service {
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
    /**
     * 服務創建的時候調用
     */
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		System.out.println("=========onCreate======");
	}
    /**
     * 服務啟動的時候調用
     */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		System.out.println("=========onStartCommand======");
		return super.onStartCommand(intent, flags, startId);
	}
    /**
     * 服務銷毀的時候調用
     */
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		System.out.println("=========onDestroy======");
		super.onDestroy();
	}
}

 新建以上類並繼承Service後只會重寫onBind()方法,其他方法是我手動手寫,為了弄清楚Service的生命周期

 MainActivity中(設置兩個按鈕用來開始和停止服務):

package com.example.myservicedemo.ui;

import com.example.myservicedemo.R;
import com.example.myservicedemo.service.MyService;
import com.example.myservicedemo.service.MyService.DownLoadBinder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button btn_start = (Button) findViewById(R.id.btn_start);
		Button btn_stop = (Button) findViewById(R.id.btn_stop);
		btn_start.setOnClickListener(this);
		btn_stop.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		int id = v.getId();
		switch (id) {
		/*
		 * 開啟服務點擊事件
		 */
		case R.id.btn_start:
			Intent startIntent = new Intent(this, MyService.class);
			startService(startIntent);
			break;
		/*
		 * 停止服務點擊事件
		 */
		case R.id.btn_stop:
			Intent stopIntent = new Intent(this, MyService.class);
			stopService(stopIntent);
			break;

		default:
			break;
		}
	}

}

  切記android中的服務是需要在項目清單文件中註冊的(AndroidStudio可以自動,eclipse需要手動添加):

      <service android:name="服務類坐所在的包名.MyService"></service>

      此時運行程式,點擊開啟服務時候輸出是下圖:(我輸出多次onStartCommand()是因為我連續點擊了多次開啟服務按鈕)

   

  上圖可以看出服務第一次開啟時先是調用了onCreate()方法和onStartCommand()方法,多次點擊開始服務時只調用了onStartCommand()方法

   so:

   onCreate()方法是服務創建的時候調用的~

   onStartCommand()方法在每次啟動服務的時候都會調用~

   onDestory()方法在停止服務時候會調用~

   點擊停止服務後,輸出如圖:

 

 啟動服務還有一種方式是bindService();

 此時的MyService類要做改變:

package com.example.myservicedemo.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

/**
 * 服務類(需要在項目清單文件中註冊服務)
 * 
 * @author lenovo
 *
 */
public class MyService extends Service {
    private DownLoadBinder downLoadBinder=new DownLoadBinder();
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		System.out.println("=====onBind=====");
		return downLoadBinder;
	}
	/**
	 * 內部類繼承Binder
	 * @author lenovo
	 *
	 */
	public class DownLoadBinder extends Binder{
		public void startDownLoad(){
			System.out.println("=====startDownLoad()=====");
		}
		public void getProgress(){
			System.out.println("=====getProgress()=====");
		}
	}
    /**
     * 服務創建的時候調用
     */
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		System.out.println("=========onCreate======");
	}
    /**
     * 服務啟動的時候調用
     */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		System.out.println("=========onStartCommand======");
		return super.onStartCommand(intent, flags, startId);
	}
    /**
     * 服務銷毀的時候調用
     */
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		System.out.println("=========onDestroy======");
		super.onDestroy();
	}
}

  以上的代碼和第一次相比,一是多了一個內部類DownLoadBinder繼承IBinder並且聲明瞭兩個方法,二是將onBind方法的返回值改為了DownLoadBinder類型的變數

     activity bindService方法啟動服務時候一般是需要傳遞數據的,核心就在onBind()方法中,往下看

 MainActivity中加兩個按鈕:綁定服務和取消綁定服務

  

package com.example.myservicedemo.ui;

import com.example.myservicedemo.R;
import com.example.myservicedemo.service.MyService;
import com.example.myservicedemo.service.MyService.DownLoadBinder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {
    private MyService.DownLoadBinder downLoadBinder;
    private MyService myService;  //我們自己的service  
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button btn_start = (Button) findViewById(R.id.btn_start);
		Button btn_stop = (Button) findViewById(R.id.btn_stop);
		Button btn_bind = (Button) findViewById(R.id.btn_bind);
		Button btn_unbind = (Button) findViewById(R.id.btn_unbind);
		btn_start.setOnClickListener(this);
		btn_stop.setOnClickListener(this);
		btn_bind.setOnClickListener(this);
		btn_unbind.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		int id = v.getId();
		switch (id) {
		/*
		 * 開啟服務點擊事件
		 */
		case R.id.btn_start:
			Intent startIntent = new Intent(this, MyService.class);
			startService(startIntent);
			break;
		/*
		 * 停止服務點擊事件
		 */
		case R.id.btn_stop:
			Intent stopIntent = new Intent(this, MyService.class);
			stopService(stopIntent);
			break;
		/*
		 * 綁定服務點擊事件
		 */
		case R.id.btn_bind:
			Intent bindIntent = new Intent(this, MyService.class);
			bindService(bindIntent, connection, BIND_AUTO_CREATE);
			break;
		/*
		 * 解除綁定服務點擊事件
		 */
		case R.id.btn_unbind:
            unbindService(connection);
			break;

		default:
			break;
		}
	}
	private ServiceConnection connection=new ServiceConnection() {
		/**
		 * 服務解除綁定時候調用
		 */
		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			
		}
		/**
		 * 綁定服務的時候調用
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			//myService=((DownLoadBinder) service).
			downLoadBinder=(DownLoadBinder) service;
			/*
			 * 調用DownLoadBinder的方法實現參數的傳遞
			 */
			downLoadBinder.startDownLoad();
			downLoadBinder.getProgress();
		}
	};

}

  運行後點擊綁定服務後輸出如下:

     

     說明成功綁定了服務且傳遞了數據,點擊解除綁定服務時候ondestory()方法輸出

    不過這種方法好像只能傳遞一次數據,,,,不爽,,,,比如後臺在實時更新東西,activity需要實時獲取呢???

    查找資料大多是以下幾種方式:

   1.使用介面回調方式,activity實現相應的介面,service通過介面進行回調,比較靈活

   2.使用廣播

    這篇博客主要介紹第一種方法,為什麼不介紹第二種???——不願意介紹,不喜歡。

    使用介面回調方式的MyService和MainActivity代碼我是備註詳細之後才粘貼的,大家可以看註釋

    MyService代碼:

    

package com.example.myservicedemo.service;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;

/**
 * 服務類(需要在項目清單文件中註冊服務)
 * 
 * @author lenovo
 *
 */
public class MyService extends Service {
    private DownLoadBinder downLoadBinder=new DownLoadBinder();
    /**
	 * 回調
	 */
	private Callback callback;
	/**
	 * Timer實時更新數據的
	 */
	private Timer mTimer=new Timer();
	/**
	 * 
	 */
	private int num;
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		System.out.println("=====onBind=====");
		return downLoadBinder;
	}

	/**
	 * 內部類繼承Binder
	 * @author lenovo
	 *
	 */
	public class DownLoadBinder extends Binder{
		/**
		 * 聲明方法返回值是MyService本身
		 * @return
		 */
		public MyService getService() {
			return MyService.this;
		}
	}
    /**
     * 服務創建的時候調用
     */
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		/*
		 * 執行Timer 2000毫秒後執行,5000毫秒執行一次
		 */
		mTimer.schedule(task, 0, 1000);
	}
	
	/**
	 * 提供介面回調方法
	 * @param callback
	 */
	public void setCallback(Callback callback) {
		this.callback = callback;
	}
	
	/**
	 * 
	 */
	TimerTask task = new TimerTask(){

		@Override
		public void run() {
			// TODO Auto-generated method stub
			num++;
			if(callback!=null){
				/*
				 * 得到最新數據
				 */
				callback.getNum(num);
			}
			
		}
		
	};
	
	
	/**
	 * 回調介面
	 * 
	 * @author lenovo
	 *
	 */
	public static interface Callback {
		/**
		 * 得到實時更新的數據
		 * 
		 * @return
		 */
		void getNum(int num);
	}
    /**
     * 服務銷毀的時候調用
     */
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		System.out.println("=========onDestroy======");
		/**
		 * 停止Timer
		 */
		mTimer.cancel();
		super.onDestroy();
	}
}

  MainActivity代碼:

package com.example.myservicedemo.ui;

import com.example.myservicedemo.R;
import com.example.myservicedemo.service.MyService;
import com.example.myservicedemo.service.MyService.Callback;
import com.example.myservicedemo.service.MyService.DownLoadBinder;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity implements OnClickListener {
    private MyService.DownLoadBinder downLoadBinder;
   // private MyService myService;  //我們自己的service  
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Button btn_start = (Button) findViewById(R.id.btn_start);
		Button btn_stop = (Button) findViewById(R.id.btn_stop);
		Button btn_bind = (Button) findViewById(R.id.btn_bind);
		Button btn_unbind = (Button) findViewById(R.id.btn_unbind);
		btn_start.setOnClickListener(this);
		btn_stop.setOnClickListener(this);
		btn_bind.setOnClickListener(this);
		btn_unbind.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		int id = v.getId();
		switch (id) {
		/*
		 * 開啟服務點擊事件
		 */
		case R.id.btn_start:
			Intent startIntent = new Intent(this, MyService.class);
			startService(startIntent);
			break;
		/*
		 * 停止服務點擊事件
		 */
		case R.id.btn_stop:
			Intent stopIntent = new Intent(this, MyService.class);
			stopService(stopIntent);
			break;
		/*
		 * 綁定服務點擊事件
		 */
		case R.id.btn_bind:
			Intent bindIntent = new Intent(this, MyService.class);
			bindService(bindIntent, connection, BIND_AUTO_CREATE);
			break;
		/*
		 * 解除綁定服務點擊事件
		 */
		case R.id.btn_unbind:
            unbindService(connection);
			break;

		default:
			break;
		}
	}
	private ServiceConnection connection=new ServiceConnection() {
		/**
		 * 服務解除綁定時候調用
		 */
		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			
		}
		/**
		 * 綁定服務的時候調用
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			downLoadBinder = (DownLoadBinder) service;
			MyService service2 = downLoadBinder.getService();
			/**
			 * 實現回調,得到實時刷新的數據
			 */
			service2.setCallback(new Callback() {
				
				@Override
				public void getNum(int num) {
					// TODO Auto-generated method stub
					System.out.println("====num===="+num);
				}
			});
		}
	};

}

  運行後的結果應該輸出如圖就對了(輸出隨service中num的數量而更新):

    

   期間遇到的問題:

   bindService後無效,MyService類中的onBind()方法沒有被調用

   解決:這種情況下你的Activity應該是繼承了TabBarActivity,綁定服務的時候調用寫這種形式:

   this.getApplicationContext().bindService(intent, mConnection, BIND_AUTO_CREATE);

   最近幾天用到,總結一下,希望可以為大家帶來幫助,有錯誤還請大神指正。

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、Node.js本質上是js的運行環境。 二、可以解析js代碼(沒有瀏覽器安全級的限制); 提供系統級的API:1、文件的讀寫 2、進程的管理 3、網路通信 三、可以關註的四個網站: 1、https://nodejs.org/en/(官網) 2、https://www.npmjs.com/ 3、h ...
  • 1、背景圖片中部放大、縮小 ...
  • border-image-source 屬性設置邊框的圖片的路徑[none | <image>] border-image-slice 屬性圖片邊框向內偏移[ <number> | <percentage> ](1,4) ?fill border-image-width 屬性設置圖片邊框的寬度[ < ...
  • border-radius 屬性設置邊框的園角 可能的值:像素,百分比 擴展延伸 html代碼 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 css代碼 結果 ...
  • 函數本身就是一段JavaScript代碼,定義一次但可能被調用任意次。如果函數掛載在一個對象上,作為對象的一個屬性,通常這種函數被稱作對象的方法。用於初始化一個新創建的對象的函數被稱作構造函數。 相對於其他面向對象語言,在JavaScript中的函數是特殊的,函數即是對象。JavaScript可以把 ...
  • 該文為閱讀高級程式設計(第三本)p144-p164的理解與總結! 接受指導與批評。 對於我,我一直是使用字面量的方式創建對象,然而體繫上的創建對象的方法卻並不局限於此。 創建對象的方法 1 工廠模式: 定義工廠函數創建並返回包含特定屬性的對象, 2 構造函數模式: 先貼出代碼 2.1 new Per ...
  • 本系列將從以下三個方面對Tinker進行源碼解析: 轉載請標明本文來源:http://www.cnblogs.com/yyangblog/p/6252855.html更多內容歡迎star作者的github:https://github.com/LaurenceYang/article如果發現本文有什 ...
  • 地址 MD5 https://dl-ssl.google.com/android/repository/android_m2repository_r08.zip 8C8EC4C731B7F55E6467914871AB8802 https://dl-ssl.google.com/android/re ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...