1. 程式人生 > >安卓中 廣播 服務 及其簡單應用範圍的一些總結

安卓中 廣播 服務 及其簡單應用範圍的一些總結

1.廣播與廣播接收者

1.API

靜態註冊廣播接收者

清單檔案中配置:
<receiver android:name="包名.廣播接收者檔案" >
            <intent-filter android:priority="廣播攔截的優先順序(最大:2147483647)" >   
                <action android:name="廣播監聽的動作 可以是自定義的或者系統廣播" />
            </intent-filter>
         </receiver>

動態註冊廣播接收者

1.動態建立一個廣播接收者
        class MyReceiver extends BroadcastReceiver {
            @Override
            public void onReceive(Context context, Intent intent) {

                //收到廣播後 
                //1.可以觸發某些事件
                //2.從initen引數中獲取廣播發送的資料
            }
        };
2.對廣播接收者進行動態註冊
    Receiver = new MyReceiver();
        //設定filter資訊
        IntentFilter filter = new IntentFilter();
        filter.addAction("自定義的或者系統廣播");   //設定廣播監聽的動作
        //註冊
        registerReceiver(Receiver, filter);
3.取消註冊
unregisterReceiver(mReceiver);
        mReceiver = null;

自定義廣播發送(通過intent攜帶資料)

    Intent intent = new Intent();
        intent.putExtra("鍵", 要攜帶到接收者的資訊);
        intent.setAction("自定義廣播");            //設定廣播監聽的動作
        sendBroadcast(intent);

兩種廣播的區別

靜態註冊廣播接收者在程式的整個執行期間都會監聽。

動態註冊的廣播接收者可以控制在需要的時候開啟監聽,不需要的時候關閉監聽。通常可以將動態註冊廣播接收者放到一個服務中,服務開啟時註冊廣播,服務關閉時取消註冊。

2.例子

常見系統廣播

    //監聽系統啟動廣播
    <receiver android:name=".receiver.BootCompleteReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    //監聽簡訊
       <receiver android:name=".receiver.SmsReceiver" >
            <intent-filter android:priority="2147483647" >
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />
            </intent-filter>
        </receiver>
    //獲取管理員許可權  MyAdminReceiver需要實現但是不用寫內容
    <receiver
            android:name=".receiver.MyAdminReceiver"
            android:description="@string/sample_device_admin_description"
            android:label="@string/sample_device_admin"
            android:permission="android.permission.BIND_DEVICE_ADMIN" >
            <meta-data
                android:name="android.app.device_admin"
                android:resource="@xml/device_admin_sample" />

            <intent-filter>
                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
            </intent-filter>
        </receiver>
    //監聽建立快捷方式
      <receiver android:name=".receiver.MyWidget" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/process_widget_provider" />
        </receiver>
    //監聽殺死所有程序
       <receiver android:name=".receiver.KillProcess">
             <intent-filter>
                <action android:name="com.example.mobilesafe.KILLALLPROCESS" />
            </intent-filter>
        </receiver>

動態註冊廣播接收者(一般在服務中動態註冊 重要)

適用情況: 廣播接收者監聽事件變化,有變化後就返回給服務,服務通過返回Bind或者寫SharePrecefence等方法傳出資料。

具體運用舉例:

1.開啟電話監聽,監聽來電去電 ,例如 黑名單,歸屬地查詢等

2.程式加鎖 ,監聽當前棧頂程式是否被加鎖

3.實時定位 ,不斷讀取當前定位資訊

4.鎖屏事件 ,監聽到鎖屏後可以做一些清理工作

5.和桌面上的Widget通訊

兩種註冊型別的區別:
靜態註冊是當程式關閉後,如果有廣播發過來,還能啟動程式
動態註冊的生命週期跟程式的生命週期是一樣的,程式關閉後動態註冊的廣播是不能在接收到廣播的


動態註冊的優點:在Android的廣播機制中,動態註冊的優先順序高於靜態註冊的優先順序,因此在必要情況下,我們需要動態註冊廣播接收器。
靜態註冊的有點:動態註冊廣播接收器還有一個優點就是當用來註冊廣播的Activity關閉後,廣播也就失效了,同時反映了靜態註冊廣播的一個優勢,就是無需擔心廣播接收器是否關閉,只要裝置處於開啟狀態,廣播接收器就能接收。

  操作頻繁的廣播事件,如果只是在清單配置檔案配置,是不生效的。需要使用程式碼註冊才能生效;

 步驟:
1:// 監聽螢幕開關
        // 1、得到廣播接收者的物件
        ScreenBroadCastReceiver screenReceiver = new ScreenBroadCastReceiver();
        // 2、建立一個intentFilter物件
        IntentFilter filter = new IntentFilter();
        // 3、註冊接收的事件型別
        filter.addAction("android.intent.action.SCREEN_ON");
        filter.addAction("android.intent.action.SCREEN_OFF");
        // 4、註冊廣播接收者
        this.registerReceiver(screenReceiver, filter);

     例2.// 註冊監聽去電的廣播
        mReceiver = new OutCallReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);
        registerReceiver(mReceiver, filter);


        以上兩例需要我們自己實現廣播接收者,下面這個例子中系統為我們實現了回撥方法

    例3. //來電話
        mListener = new MyPhoneStateListener();
        mTM.listen(mListener, PhoneStateListener.LISTEN_CALL_STATE);// 監聽來電狀態
        class MyPhoneStateListener extends PhoneStateListener {
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
            case TelephonyManager.CALL_STATE_RINGING:// 電話玲響

                break;
            case TelephonyManager.CALL_STATE_IDLE:// 通話結束

                break;
            default:
                break;
            }
            super.onCallStateChanged(state, incomingNumber);
        }
    }

    例4.//設定快捷方式

            Intent intent = new Intent(
                    "com.android.launcher.action.INSTALL_SHORTCUT");

            // 設定快捷方式的圖示
            intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, BitmapFactory
                    .decodeResource(getResources(), R.drawable.home_tools));

            // 設定快捷方式名稱
            intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "黑馬小衛士");

            //不允許重複
            intent.putExtra("duplicate", false);

            // 動作,跳轉主頁面
            Intent actionIntent = new Intent();
            actionIntent.setClass(this,MainActivity.class);
            //actionIntent.setAction("com.example.mobilesafe.MAIN");// 通過action啟動主頁面,需要在清單檔案配置action
            //actionIntent.addCategory(Intent.CATEGORY_DEFAULT);// 必須配置categroy
            intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, actionIntent);

            // 傳送廣播
            sendBroadcast(intent);

2.服務

2.1 API

註冊一個服務

清單檔案
    <service android:name=".service.MyService" />

    public class MyService extends Service {

    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    //建立服務的時候呼叫
    @Override
    public void onCreate() {
        System.out.println("*****onCreate******");
        super.onCreate();
    }

    //啟動server    每次start都會呼叫一次
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        System.out.println("*****onStartCommand******");
        return super.onStartCommand(intent, flags, startId);
    }

    //手動停止程式後會終止服務,會呼叫onDestroy()方法
    @Override
    public void onDestroy() {
        System.out.println("*****onDestroy******");
        super.onDestroy();
    }
    }

開啟一個服務

    1.啟動
        //使用Intent
        Intent intent = new Intent(當前Activity.this, MyService.class);
        startService(intent);
        stopService(intent);

    2.使用bind讓其他元件獲取服務提供的資料
        //使用Intent
        Intent intent = new Intent(當前Activity.this, MyService.class);
        bindService(intent, conn, BIND_AUTO_CREATE);
        unbindService(conn);

注意事項

bindService繫結服務、unBindService解除繫結的服務;
服務是在被繫結的時候被建立,呼叫oncreate、onbind方法;
服務只能被繫結一次;
服務只能被解除一次,接觸繫結的時候呼叫onUnbind、onDestrory方法,如果多次解除繫結會丟擲異常;


推薦的方式(啟用順序):

1.startService:開啟並建立一個服務,服務長期執行在後臺;
2.bindService:繫結服務,可以呼叫服務裡面的方法;
3.unBindService:解除服務,停止服務裡面的方法;
4.stopService:停止服務,銷燬服務物件;

獲取服務中的資料(與服務通訊)

MyService中

        //這個函式用於返回資料
        public IBinder onBind(Intent intent) 
        {
            return new MyBind();     //返回到前臺的物件,包含要執行的service中的方法
        }

        //繼承Binder類,這是因為要返回一個實現IBinder型別介面的
        public class MyBind extends Binder
        {
            public void callPaly() {
                paly();
            }
        }

    客戶端

        //繫結服務
        bindService(intent, new MyServiceConnection(), BIND_AUTO_CREATE);

        //獲取服務返回的資料
        class MyServiceConnection implements ServiceConnection
        {

            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //返回服務中包含要呼叫方法的類
                serverRet = (MyBind) service;
            }

        @Override
            public void onServiceDisconnected(ComponentName name) {
        }

aidl 獲取其他程序服務的資訊

3.內容提供者

3.1API

1.內容解釋者  

作用: 用來解析內容觀察者提供的資料庫資訊
ContentResolver contentResolver = getContentResolver();
    //getContentResolver();是上下文中攜帶的方法,用於處理內容提供者提供的訪問方式。

    尋找哪個內容提供者需要用通過uri,uri路徑分文 "主機名"+"具體要操作的資料"   其中"主機名"在提供資料庫程式的清單檔案中定義,"具體要操作的資料"在這個程式的原始碼中(一般檔名有provide字樣),
    我們可以通過查詢"UriMatcher"函式搜尋相關的資訊。

    Uri uri = Uri.parse("content://.../");    //指定查詢哪個應用下資料庫的哪個表

    Cursor cursor = contentResolver.query(uri, ... ...);

    2.內容觀察者

     //註冊內容觀察者
     getContentResolver().registerContentObserver(uri, true, new MyObeserver(new Handler()));

    //收到通知後回撥其中的方法
    class MyObeserver extends ContentObserver
    {
        public MyObeserver(Handler handler) {
            super(handler);
        }   
        //發現監視路徑下的資料庫發生變化就會呼叫此方法         
        @Override
        public void onChange(boolean selfChange) {          
            super.onChange(selfChange);
        }
    }

    //在資料庫操作中發出訊號,通知觀察者

        // 通知觀察者,資料發生變化了
        Context.getContentResolver().notifyChange(Uri.parse("content://..."),null);

3.2應用場合舉例

1.查詢聯絡人資料庫

2.查詢簡訊資料庫

3.音樂檔案

自定義的資料庫我們直接使用SQLiteOpenHelper進行查詢

4.意圖 的一些應用場合和分類

隱式意圖

開啟其他應用
    安裝程式
                /**
                 * 使用隱式題圖安裝指定路徑下的apk
                 * @param path
                 */
                private void installApk(String path)
                {
                    File file = new File(path);
                    Intent intent = new Intent();
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.setAction(android.content.Intent.ACTION_VIEW);
                    intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
                    //startActivity(intent);
                    startActivityForResult(intent, 0);
                }

        解除安裝程式
                /**
                 * 解除安裝應用
                 */
                private void uninstall(String packageName) {
                    // 跳轉到解除安裝頁面
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.addCategory(Intent.CATEGORY_DEFAULT);
                    intent.setData(Uri.parse("package:" + packageName));
                    startActivityForResult(intent, 0);
                }

        清理快取
                // 清理單個檔案快取
                // 跳轉到系統設定頁面
                Intent intent = new Intent();
                intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                intent.setData(Uri.parse("package:" + info.packageName));
                intent.addCategory(Intent.CATEGORY_DEFAULT);
                startActivity(intent);

       打電話

                Intent intent = new Intent(Intent.ACTION_DIAL);
                intent.setAction(Intent.ACTION_DIAL);
                intent.setData(Uri.parse("tel:"+number));
                startActivity(intent);

顯式意圖

...

傳送廣播

    例子見第一章

開啟服務

    例子見第二章

帶返回值的開啟新的Activity

1.A頁面跳轉到B:

Intent intent = new Intent(AActivity.this, BActivity.class);   

    //  如果需要返回資料,用此方法傳送intent    第二個引數為傳送碼
    startActivityForResult(intent, 2);

2.B頁面傳送資料給A,B頁面關閉:

Intent intent = new Intent();
    intent.putExtra("...", ...);    
    setResult(2, intent);

    finish();

3.A頁面接收B傳來的資料:

在A頁面的類中複寫以下方法,通過傳送碼或者返回碼判斷接收到資料的流向

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if(resultCode == 1)
        {
            ... 
        }else if(resultCode == 2){
            ...
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

這裡寫程式碼片