1. 程式人生 > >Android中的通知和自定義通知佈局

Android中的通知和自定義通知佈局

Android中的通知(Notification)是Android中的重要一部分,應用程式通過通知來提醒使用者或者向用戶傳達資訊,下面讓我們來看一下怎麼在我們的程式中使用通知和自定義通知的佈局。

首先我們來看一下怎麼向通知欄中傳送一個通知。由於各個版本的Android在通知方面都有一些改動,所以很難找到一個標準的建立及使用通知的方法,但是程式設計出來總歸是給使用者使用的,那麼我們可以採用相容性最好的那個API來建立通知:我們可以使用NotificationCompat 這個類來進行通知的建立及設定屬性,具體步驟如下:

1、獲取系統的通知管理服務,通過:

(NotificationManager)getSystemService(
Context
.NOTIFICATION_SERVICE)

方法來獲取,注意要強制轉換型別。

2、建立我們需要的通知並且設定對應屬性:

Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("通知1") // 建立通知的標題
        .setContentText("這是第一個通知") // 建立通知的內容
        .setSmallIcon(R.drawable.small_icon) // 建立通知的小圖示                
        .setLargeIcon
(BitmapFactory. decodeResource(getResources(), R.drawable.ic_launcher)) // 建立通知的大圖示 /* * 首先,無論是使用自定義檢視還是系統提供的檢視,上面4的屬性一定要設定,不然這個通知顯示不出來 */

3、呼叫通知管理服務的notify方法傳送通知

我們依然通過一個例子來看一下:
新建一個Android工程:
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" >
<Button android:id="@+id/button1NotifyNotification" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="傳送第一種通知" /> <Button android:id="@+id/button2NotifyNotification" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="傳送第二種通知"/> </LinearLayout>

佈局中的兩個按鈕分別用來發送系統佈局的通知和我們自定義佈局的通知,接下來是我們自定義的通知佈局,新建一個佈局檔案notification.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/notificationLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFFAADD"
    android:orientation="horizontal" >

    <ImageView 
        android:id="@+id/notificationImageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/music"/>
    <TextView 
        android:id="@+id/notificationTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="正在播放:"/>
    <Button
        android:id="@+id/notificationButton1" 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/pause" />
    <Button 
        android:id="@+id/notificatinoButton2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/next"/>

</LinearLayout>

這個佈局中我們採用橫向佈局,用來模擬一個音樂播放器的橫欄,兩個按鈕分別對應 播放/暫停,下一曲 。
那麼接下來是MainActivity.java:

import java.io.File;
import android.net.Uri;
import android.os.Bundle;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.support.v4.app.NotificationCompat;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.RemoteViews;

public class MainActivity extends Activity {

    private NotificationManager notificationManager = null;
    private Button button = null;
    private MyBroadcastReceiver myBroadcastReceiver = null;
    public static final String button1StateJudge = "button1StateJudge";

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

        notificationManager = (NotificationManager) 
                getSystemService(Context.NOTIFICATION_SERVICE); // 獲取系統提供的通知管理服務

        button = (Button) findViewById(R.id.button1NotifyNotification);
        button.setOnClickListener(listener);
        button = (Button) findViewById(R.id.button2NotifyNotification);
        button.setOnClickListener(listener);

        init(); // 註冊廣播
    }

    private void init()
    {
        myBroadcastReceiver = new MyBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter(MyBroadcastReceiver.ACTION_1);
        intentFilter.addAction(MyBroadcastReceiver.ACTION_2);
        registerReceiver(myBroadcastReceiver, intentFilter);
    }

    private View.OnClickListener listener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            switch(v.getId())
            {
            case R.id.button1NotifyNotification:
                notifyFirstNotification();
                break;
            case R.id.button2NotifyNotification:
                notifySecondNotification();
                break;
            }
        }
    };

    private void notifyFirstNotification()
    {
        Intent intent = new Intent(this, SecondActivity.class);
        /*
         * 呼叫PendingIntent的靜態放法建立一個 PendingIntent物件用於點選通知之後執行的操作,
         * PendingIntent可以理解為延時的Intent,在這裡即為點選通知之後執行的Intent
         * 這裡呼叫getActivity(Context context, int requestCode, Intent intent, int flag)方法
         * 表示這個PendingIntent物件啟動的是Activity,類似的還有getService方法、getBroadcast方法
         */
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 0);

        Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("通知1") // 建立通知的標題
        .setContentText("這是第一個通知") // 建立通知的內容
        .setSmallIcon(R.drawable.small_icon) // 建立通知的小圖示
        .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_launcher)) // 建立通知的大圖示
        /*
         * 首先,無論你是使用自定義檢視還是系統提供的檢視,上面4的屬性一定要設定,不然這個通知顯示不出來
         */
        .setWhen(System.currentTimeMillis()) // 設定通知顯示的時間
        .setContentIntent(pi) // 設定點選通知之後啟動的內容,這個內容由方法中的引數:PendingIntent物件決定
        .setPriority(NotificationCompat.PRIORITY_MAX) // 設定通知的優先順序
        .setAutoCancel(true) // 設定點選通知之後通知是否消失
        .setSound(Uri.fromFile(new File("/system/media/audio/ringtones/Luna.ogg"))) // 設定聲音
        /*
         * 設定震動,用一個 long 的陣列來表示震動狀態,這裡表示的是先震動1秒、靜止1秒、再震動1秒,這裡以毫秒為單位
         * 如果要設定先震動1秒,然後停止0.5秒,再震動2秒則可設定陣列為:long[]{1000, 500, 2000}。
         * 別忘了在AndroidManifest配置檔案中申請震動的許可權
         */
        .setVibrate(new long[]{1000, 0, 1000})
        /*
         * 設定手機的LED燈為藍色並且燈亮2秒,熄滅1秒,達到燈閃爍的效果,不過這些效果在模擬器上是看不到的,
         * 需要將程式安裝在真機上才能看到對應效果,如果不想設定這些通知提示效果,
         * 可以直接設定:setDefaults(Notification.DEFAULT_ALL);
         * 意味將通知的提示效果設定為系統的預設提示效果
         */
        .setLights(Color.BLUE, 2000, 1000)
        .build(); // 建立通知(每個通知必須要呼叫這個方法來建立)
        /*
         * 使用從系統服務獲得的通知管理器傳送通知,第一個引數是通知的id,不同的通知應該有不同的id,
         * 這樣當我們要取消哪條通知的時候我們呼叫notificationManager(通知管理器).cancel(int id)
         * 方法並傳入傳送通知時的對應id就可以了。在這裡如果我們要取消這條通知,
         * 我們呼叫notificationManager.cancel(1);就可以了
         * 第二個引數是要傳送的通知物件
         */
        notificationManager.notify(1, notification); 
    }

    private void notifySecondNotification()
    {
        Intent button1I = new Intent("PressPauseOrPlayButton");

        PendingIntent button1PI = PendingIntent.getBroadcast(this, 0, button1I, 0);
        Intent button2I = new Intent("PressNextButton");
        PendingIntent button2PI = PendingIntent.getBroadcast(this, 0, button2I, 0);
        /*
         * 通知佈局如果使用自定義佈局檔案中的話要通過RemoteViews類來實現,
         * 其實無論是使用系統提供的佈局還是自定義佈局,都是通過RemoteViews類實現,如果使用系統提供的佈局,
         * 系統會預設提供一個RemoteViews物件。如果使用自定義佈局的話這個RemoteViews物件需要我們自己建立,
         * 並且加入我們需要的對應的控制元件事件處理,然後通過setContent(RemoteViews remoteViews)方法傳參實現
         */
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
        /*
         * 對於自定義佈局檔案中的控制元件通過RemoteViews類的物件進行事件處理
         */
        remoteViews.setOnClickPendingIntent(R.id.notificationButton1, button1PI);
        remoteViews.setOnClickPendingIntent(R.id.notificatinoButton2, button2PI);

        Notification notification = new NotificationCompat.Builder(this)
        .setContentTitle("通知2") // 建立通知的標題
        .setContentText("這是第二個通知") // 建立通知的內容
        .setSmallIcon(R.drawable.small_icon) // 建立通知的小圖示
        .setLargeIcon(BitmapFactory.decodeResource(getResources(),
                R.drawable.ic_launcher)) // 建立通知的大圖示
        /*
         * 是使用自定義檢視還是系統提供的檢視,上面4的屬性一定要設定,不然這個通知顯示不出來
         */
        .setDefaults(Notification.DEFAULT_ALL)  // 設定通知提醒方式為系統預設的提醒方式
        .setContent(remoteViews) // 通過設定RemoteViews物件來設定通知的佈局,這裡我們設定為自定義佈局
        .build(); // 建立通知(每個通知必須要呼叫這個方法來建立)

        notificationManager.notify(2, notification); // 傳送通知

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public void onDestroy()
    {
        super.onDestroy();
        unregisterReceiver(myBroadcastReceiver); // 登出廣播
    }
}

MainActivity.java的程式碼就有點多了,總體思路是對佈局檔案中的兩個按鈕進行事件處理,定義 notifyFirstNotification() 方法和 notifySecondNotification() 方法分別用於建立系統提供佈局的通知和自定義佈局的通知,並且傳送通知。首先,notifyFirstNotification方法就是傳送一個系統佈局的通知,單擊之後會啟動一個Activity物件:SecondActivity.java,程式碼中有詳細的註釋,這裡不再重複,下面給出SecondActivity.java的程式碼:

import android.app.Activity;
import android.os.Bundle;
import android.view.Gravity;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;

public class SecondActivity extends Activity {

    LinearLayout layout = null;
    TextView textView = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        layout = new LinearLayout(this);
        layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT));
        layout.setGravity(Gravity.CENTER_HORIZONTAL);
        layout.setOrientation(LinearLayout.VERTICAL);
        setContentView(layout);

        textView = new TextView(this);
        textView.setText("通過點選通知啟動的Activity");
        layout.addView(textView, new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));


    }

}

這個Activity我們用的是程式碼來建立佈局一個線性佈局中包含一個TextView控制元件。別忘了在AndroidManifest.xml佈局檔案中註冊SecondActivity:

<activity 
    android:name="SecondActivity"
    android:label="第二個Activity">
</activity>

我們接著來看notifySecondNotification方法,在這個方法中我們實現的是一個自定義佈局的通知,我們注意到在onCreate方法中我們還動態註冊了一個廣播,如果對於廣播不熟悉的小夥伴可以參考一下這篇博文:
http://blog.csdn.net/hacker_zhidian/article/details/54773259
言歸正傳,這個廣播幹什麼用的呢:在自定義通知佈局中我們要對兩個按鈕進行事件處理,在自定義通知佈局中,我們必須使用RemoteViews的物件來對佈局檔案中的兩個按鈕進行事件處理,而 RemoteViews的兩個處理單擊事件的方法都必須要傳入PendingIntent 物件,PendingIntent物件必須通過Intent物件來構造(具體見程式碼註釋),那麼這樣只能通過Activity、Broadcast、Service(它們都是通過Intent啟動或者和Intent有關聯)來響應按鈕的單擊事件。這樣的話思路就清晰了,我們這裡通過一個Broadcast來處理按鈕單擊事件,因此我們需要使用BroadcastReceiver物件來接收廣播,那麼接下來是MyBroadcastReceiver.java:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyBroadcastReceiver extends BroadcastReceiver {

    public static final String ACTION_1 = "PressPauseOrPlayButton";
    public static final String ACTION_2 = "PressNextButton";

    @Override
    public void onReceive(Context context, Intent intent)
    {
        String action = intent.getAction();
        String toastStr = "你點選了";
        if(action.equals(ACTION_1))
        {
            Toast.makeText(context, toastStr + "播放/暫停按鈕", Toast.LENGTH_SHORT).show();
        }
        else if(action.equals(ACTION_2))
        {
            Toast.makeText(context, toastStr + "下一曲按鈕", Toast.LENGTH_SHORT).show();
        }
    }
}

在這段程式碼中我們定義了一個類MyBroadcastReceiver繼承於BroadCastReceiver,並且實現了它的抽象方法用於對按鈕的點選進行相應的處理,這裡只是簡單地提示,值得注意的是:不應該在onReceive方法中進行耗時的操作,一般來說如果廣播接收器的onReceive方法執行超過了10秒,系統就會認為這個應用沒有響應。
Ok,下面是執行結果:
這裡寫圖片描述
單擊“傳送第一種通知”按鈕:
這裡寫圖片描述
單擊這個通知:
這裡寫圖片描述
接下來單擊“傳送第二種通知”按鈕:
這裡寫圖片描述
這裡圖片是隨便找的,不太美觀,大家多多諒解。分別單擊通知中的兩個按鈕:
這裡寫圖片描述
這裡寫圖片描述

Nice,我們成功的自定義了屬於我們自己的通知

如果部落格中有什麼不正確的地方,還請多多指點
謝謝觀看。。。