Android桌面小部件AppWidget:音乐播放器桌面控制部件Widget(3)



Android桌面小部件AppWidget:音乐播放器桌面控制部件Widget(3)


Android桌面小部件AppWidget比较常用的场景就是音乐播放器,音乐播放器虽然通常在后台播放,但需要在桌面提供一个可以控制播放状态的APP widget,为用户提供播放、暂停、停止音乐播放器的功能。
在附录文章1、2的基础上,本文以一个简单的例子加以说明,如何通过桌面小部件实现音乐播放器的播放、停止。简单期间,本例只提供对音乐播放器的两种控制功能:播放和停止。播放,进入后台service播放给定的音乐mp3文件;停止,则直接stopService关闭播放服务即可。
为此,需要在桌面的小部件布局中增加两个按钮,这两个按钮暂时就以Android系统默认的播放(@android:drawable/ic_media_play)和暂停(@android:drawable/ic_media_pause)图片作为按钮使用。当按了播放按钮后,就开始启动后台服务播放mp3音乐文件(暂时以我放置在SDCard根目录下名为zhangphil.mp3的音乐文件为音频源文件);当按了停止按钮后,就stopService,即停止播放。
和附录文章1,2相比,本例不需要更新桌面小部件的表现形式,仅需要处理由桌面小部件传导过来的点击事件,这些响应点击事件,均放置在onReceive里面处理。

(1)

在Androidmanifest.xml里面定义的widget:

 <receiver android:name="zhangphil.widget.AppWidget" >
           
            <intent-filter>
                <action android:name="action_play" />
            </intent-filter>
            
            <intent-filter>
                <action android:name="action_stop" />
            </intent-filter>
            
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/appwidget" />
            
        </receiver>


涉及到res/xml目录下的appwidget.xml代码文件:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/appwidget_layout"
    android:minHeight="20dip"
    android:minWidth="300dip"
    android:previewImage="@drawable/ic_launcher"
    android:resizeMode="horizontal|vertical"
    android:updatePeriodMillis="0"
    android:widgetCategory="home_screen" >

</appwidget-provider>


(2)service播放音乐。也在Androidmanifest.xml里面定义:

<service android:name="zhangphil.widget.MyService" >
        </service>

(3)核心关键的AppWidget.java代码文件:

package zhangphil.widget;


import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;

public class AppWidget extends AppWidgetProvider {

	@Override
	public void onReceive(Context context, Intent intent) {
		super.onReceive(context, intent);
		// Log.d(this.getClass().getName(), "onReceive");

		if (intent == null)
			return;

		String action = intent.getAction();

		// 停止播放
		if (action.equals(Constants.ACTION_STOP)) {
			Intent serviceIntent = new Intent(context, MyService.class);
			context.stopService(serviceIntent);
		}

		// 点击了按钮,启动一个后台服务播放
		if (action.equals(Constants.ACTION_PLAY)) {
			Intent serviceIntent = new Intent(context, MyService.class);
			context.startService(serviceIntent);
		}
	}

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
		Log.d(this.getClass().getName(), "onUpdate");

		RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);

		// 播放图片作为按钮,绑定播放事件
		Intent intentPlay = new Intent(Constants.ACTION_PLAY);
		PendingIntent pendingIntentPlay = PendingIntent.getBroadcast(context, Constants.REQUEST_CODE_PLAY, intentPlay,
				PendingIntent.FLAG_UPDATE_CURRENT);
		remoteViews.setOnClickPendingIntent(R.id.play, pendingIntentPlay);

		// 停止图片作为按钮,绑定停止事件
		Intent intentStop = new Intent(Constants.ACTION_STOP);
		PendingIntent pendingIntentStop = PendingIntent.getBroadcast(context, Constants.REQUEST_CODE_STOP, intentStop,
				PendingIntent.FLAG_UPDATE_CURRENT);
		remoteViews.setOnClickPendingIntent(R.id.stop, pendingIntentStop);

		// 更新AppWidget
		appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
	}

	/**
	 * 删除AppWidget
	 */
	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		super.onDeleted(context, appWidgetIds);
		Log.d(this.getClass().getName(), "onDeleted");
	}

	@Override
	public void onDisabled(Context context) {
		super.onDisabled(context);
		Log.d(this.getClass().getName(), "onDisabled");
	}

	/**
	 * AppWidget首次创建调用
	 */
	@Override
	public void onEnabled(Context context) {
		super.onEnabled(context);
		Log.d(this.getClass().getName(), "onEnabled");
	}
}

AppWidget.java里面RemoteViews用到的布局文件appwidget_layout.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="wrap_content"
    android:background="#33000000"
    android:orientation="horizontal" >

    <ImageView
        android:id="@+id/play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_media_play" >
    </ImageView>

    <ImageView
        android:id="@+id/stop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@android:drawable/ic_media_pause" >
    </ImageView>

</LinearLayout>


(4)service后台服务MyService.java,该部分代码将负责在后台播放或者停止音播放:

package zhangphil.widget;

import java.io.File;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.IBinder;

public class MyService extends Service {

	// 播放器
	private MediaPlayer mMediaPlayer;

	// 音频文件
	private File audioFile;

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

		mMediaPlayer = new MediaPlayer();

		// 根目录
		File sdcard = Environment.getExternalStorageDirectory();
		audioFile = new File(sdcard, "zhangphil.mp3");
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// 重置
		mMediaPlayer.reset();

		// 设置播放器的声音源
		try {
			mMediaPlayer.setDataSource(audioFile.getAbsolutePath());
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 也可以从一个静态资源文件中加载音频数据源
		// mMediaPlayer.create(this, R.raw.xxx);

		if (!mMediaPlayer.isPlaying()) {
			try {
				mMediaPlayer.prepare();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			mMediaPlayer.start();

			// 如果设置循环true,那么将循环播放
			// mMediaPlayer.setLooping(true);
		}
		
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		mMediaPlayer.stop();
		mMediaPlayer.release();
		mMediaPlayer = null;
	}

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

(5)定义的公共静态变量Constants.java:

package zhangphil.widget;

public class Constants {
	public static final String ACTION_PLAY = "action_play";
	public static final String ACTION_STOP = "action_stop";
	public static final int REQUEST_CODE_PLAY = 0xd05;
	public static final int REQUEST_CODE_STOP = 0xd06;
}



代码运行结果如图所示:


附录文章:
1,《Android桌面小部件AppWidget(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/50457355
2,《Android桌面小部件AppWidget(2)》链接地址:http://blog.csdn.net/zhangphil/article/details/50461944

是一款具有众多功能和精美设计的 Android 最佳音乐播放器。这款内置顶级质量均衡器的 mp3 播放器将您的音乐聆听体验提升到一个新的水平。这款带eq和高音量应用程序的 mp3 播放器可让您以最佳的声音和最小的使用量播放音乐,而无需消耗电池。是 Android 系统默认音乐播放器的完美替代品。 是离线本地 mp3 播放器应用程序。它不支持在线音乐下载或音乐流。但它可让您在一个地方轻松管理所有离线音乐,浏览快速搜索并支持以所有音乐格式播放。其时尚,强大和快速的音乐播放器,占用的内存少,并提供完美的音乐体验。它是Android上最有用的eq音乐播放器。 精彩功能: 时装设计,30多个最佳音乐主题可替换的背景图片。从图库中选择您自己的图片。华丽的免费背景皮肤。自定义大量的颜色。 强大的节拍均衡器,通过10个惊人的预设,5个频段,低音增强器,音乐虚拟器和3D混响效果调整等来增强您的音乐体验。 内置Mp3剪切器,铃声制作器轻松剪切音频歌曲的最佳部分并将其另存为铃声/警报/通知/音乐文件等。 支持所有音乐文件格式-MP3,MP4,WAV,M4A,FLAC ,3GP,OGC等。 按专辑,艺术家,播放列表,流派,文件夹等浏览和播放音乐。 播放列表自动/手动备份-切勿松动您的播放列表。 支持歌词的音乐播放器(嵌入歌词)。 耳机/蓝牙支持。 音乐持续时间过滤器。 智能睡眠定时器。 智能摇来更改歌曲。 同时支持纵向/横向模式。 背景图片-选择您自己的图片。 内置免费的JAudio Tag编辑器支持。 窗口小部件支持(4×4,4×2,4×1,4×1) 播放带有重新排序的队列-轻松添加曲目并向上/向下拖动以进行排序。 借助“建议的仪表板”,您可以在一处智能地跟踪所有听力。 智能自动播放列表-最近播放/播放次数最多/历史记录完全支持播放列表并随时随地构建自己的播放列表。 标记“收藏歌曲”选项。 从多个播放器设计中选择。 强大的搜索功能-可以快速搜索歌曲,艺术家,专辑等。 漂亮的锁屏控件具有全屏专辑封面支持(启用/禁用)。 Last.fm集成自动获取艺术家信息,例如艺术家作品或传记。 Last.fm Scrobber支持。 强大的Mp3切割器和铃声切割器。 文件夹支持-按文件夹播放歌曲。 派对随机播放音乐-随机播放所有曲目。 天才拖动以对播放列表和播放队列进行排序。 立即播放屏幕滑动以更改歌曲 轻松自定义最佳主题-浅色/深色/黑色/彩色/图片主题。 下载丢失的专辑封面和艺术家图像。 可穿戴的支持。 完美的健身音乐应用程序。 以随机播放,重复播放,循环播放和顺序播放歌曲。 易于导航和简约设计。 节拍指南找到您所有的歌曲和音乐。 最好的免费音乐离线应用和媒体播放器。 轻松分享歌曲。 通知控制-从通知控制跟踪。 超过35种语言支持。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangphil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值