RemoteViews一 仿qq音樂自定義通知欄實現快捷切換歌曲

lantier發表於2018-01-23
RemoteViews一 仿qq音樂自定義通知欄實現快捷切換歌曲

歡迎關注我的公眾號:

歡迎關注我的公眾號
RemoteViews一 仿qq音樂自定義通知欄實現快捷切換歌曲

定義:RemoteViews表示一種view結構,它可以在其他程式中顯示,由於它在其它程式中,為了能夠更新它的介面,RemoteViews提供了一組基礎的操作用於更新它的介面。

本文大概需要5分鐘,從以下三方面講解。文章底部有總結,急性子可以直接看總結,快速掌握知識點。

  1. 一、成果展示
  2. 二、程式碼講解
  3. 三、總結
一、成果展示

仿照qq音樂通知欄切換歌曲(缺圖,只能以文字代替)

remoteviews

點選下一曲後,執行相應的程式碼(以相應Toast代替)

pause

後臺啟動相應的service執行切換歌曲和暫停等邏輯

log

二、程式碼講解

package android.com.remoteviews;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.RemoteViews;

import static android.R.string.no;

public class MainActivity extends AppCompatActivity {

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

    private void initRemoteViews () {
        Notification notification = new Notification();
        notification.icon = R.mipmap.ic_launcher;
        notification.tickerText = "remoteviewTest";
        notification.when = System.currentTimeMillis();
        notification.flags = Notification.FLAG_AUTO_CANCEL;
        Intent intent = new Intent(this, SecondActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_remoteviews);
        remoteViews.setTextViewText(R.id.tv_remote, "曖昧");
        remoteViews.setImageViewResource(R.id.iv_remote,R.mipmap.ic_launcher);
        Intent changeService = new Intent(this, ChangeService.class);
        changeService.putExtra("data","下一曲");
        PendingIntent changeIntent = PendingIntent.getService(this, 1, changeService, PendingIntent.FLAG_UPDATE_CURRENT);
        changeService.putExtra("data","暫停");
        PendingIntent pauseIntent = PendingIntent.getService(this, 2, changeService, PendingIntent.FLAG_UPDATE_CURRENT);

        remoteViews.setOnClickPendingIntent(R.id.tv_pause,pauseIntent);
        remoteViews.setOnClickPendingIntent(R.id.tv_next,changeIntent);
        PendingIntent clickIntent = PendingIntent.getActivity(this, 1, new Intent(this, ThirdActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.iv_remote,clickIntent);
        notification.contentView = remoteViews;
        notification.contentIntent = pendingIntent;
        NotificationManager notifacationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notifacationManager.notify(2,notification);
    }
}
複製程式碼

上面是核心程式碼,以下會分塊講解: 首先需要notification,設定引數,icon應該是每一首歌曲對應的圖片

Notification notification = new Notification();
        notification.icon = R.mipmap.ic_launcher;
        notification.tickerText = "remoteviewTest";
        notification.when = System.currentTimeMillis();
        notification.flags = Notification.FLAG_AUTO_CANCEL;
複製程式碼

然後構造出PendingIntent

Intent intent = new Intent(this, SecondActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
複製程式碼

再然後,構造出remoteviews,它有兩個引數,一個是包名,另一個是佈局的id,這裡我寫了一個簡單的展示在通知欄的佈局。 注意了,remoteview設定文字和圖片資源都沒有findViewById,只能通過這種set方法,將對應的id和資源傳進去。(這裡先說用法,remoteview機制的原理在後面講解)

RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.layout_remoteviews);
        remoteViews.setTextViewText(R.id.tv_remote, "曖昧");
        remoteViews.setImageViewResource(R.id.iv_remote,R.mipmap.ic_launcher);
複製程式碼

佈局的程式碼如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/iv_remote"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher_round"/>
    <TextView
        android:id="@+id/tv_remote"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="i am a apple"/>


    <TextView
        android:id="@+id/tv_pause"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="暫停"/>
    <TextView
        android:id="@+id/tv_next"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="下一曲"/>

    <TextView
        android:id="@+id/tv_close"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:text="關閉"/>


</LinearLayout>
複製程式碼

這裡要澄清以下,不是非要用textview,而是我沒有圖,只能用文字代替,等以後又圖了做個好看的哈哈。

下面說下remoteview上面點選事件,同理沒有直接設定點選事件的方法(進它的原始碼瞅一眼就知道為啥了),還是隻能傳進去penddingIntent,由於qq音樂點選通知欄按鈕直接切換歌曲,介面不發生變化所以,這塊的penddingIntent用的PendingIntent.getService。當然,點選整個通知欄要跳到qq音樂主介面的話,就是底下PendingIntent.getActivity了。 有一點,PendingIntent兩個如果requescode一樣,只是extras不一樣會被認為是同一個peddingInetent。原因是,區分PenddingIntent是由內部intent和requescode,而內部intent區分是由componentName和intent-filter,ectras不參與Intent的匹配過程。 如果notify方法的id是常量,那麼不管PenddingIntent是否匹配,後面的通知會直接替換前面的通知。

Intent changeService = new Intent(this, ChangeService.class);
        changeService.putExtra("data","下一曲");
        PendingIntent changeIntent = PendingIntent.getService(this, 1, changeService, PendingIntent.FLAG_UPDATE_CURRENT);
        changeService.putExtra("data","暫停");
        PendingIntent pauseIntent = PendingIntent.getService(this, 2, changeService, PendingIntent.FLAG_UPDATE_CURRENT);

        remoteViews.setOnClickPendingIntent(R.id.tv_pause,pauseIntent);
        remoteViews.setOnClickPendingIntent(R.id.tv_next,changeIntent);
        PendingIntent clickIntent = PendingIntent.getActivity(this, 1, new Intent(this, ThirdActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
        remoteViews.setOnClickPendingIntent(R.id.iv_remote,clickIntent);
複製程式碼

最後將自定義的remoteviews設定給notification的contentview 並且獲取系統NotificationManager,通過notifacationManager.notify方法 將自定義的通知工具欄發出,展示在通知欄中國呢。

notification.contentView = remoteViews;
        notification.contentIntent = pendingIntent;
        NotificationManager notifacationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notifacationManager.notify(2,notification);
複製程式碼

最後,本文只是仿照qq通知欄操作介面將remoteview的使用講解一下,並不是一個播放器,再次強調,不是在做播放器。 我這麼想的,如果要做qq音樂的播放器通知更新,應該service裡面去更新notinication的介面,比如,收到點選下一曲的penddingIntent,service去播放下一首歌曲,同時更新remoteview的介面(歌曲名字和歌曲對應的圖片) 對於qq音樂的其他操作,比如點選通知欄進入qq音樂主介面,就是notification的pendingIntent,它是由PenddingIntent.getActivity獲取的。其他與qq音樂相關的先不管了,本文只提與remoteview有關的東西。

三、總結

  1. RemoteViews構造方法接受一個包名,一個layout的id;
  2. RemoteViews設定圖片資源和文字資源接受id和資源;
  3. 沒有直接方法設定點選事件,只能通過PenddingIntent相關方法實現;
  4. 將RemoteViews設定在notification中,通過NotificationManager的notify方法實現。
  5. 注意點:notify方法的id,penddingIntent的requestCode能用來區分PenddingIntent是不是同一個。

後記,RemoteViews還有一個最重要的使用就是桌面小部件(AppWidgetProvider),下一篇會寫一個類似天氣的桌面部件,並完成RemoteViews的原理講解。

我的csdn部落格 歡迎關注我的微信公眾號:

微信公眾號

相關文章