音乐播放器-MainContentActivity简析

很多时候我们写程序的时候经常用到mvc模式,我们可以在程序里面细心的品味这个模式,

当然也许程序写的view和controler是在一起写的,或者model和controler是在一起写的,

如果按照这个模式读代码会感觉很容易读,同时据说一个人同时一次最多了解到1w行代码,

对于小菜比而言这个数字也许只有1k,所以不能贪多,按照类区分模块一个模块一个模块的记忆,

会比一下子记忆很多容易许多。

/**
 * 
 */
package com.ldw.music.activity;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.Dialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.FragmentActivity;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.ldw.music.MusicApp;
import com.ldw.music.R;
import com.ldw.music.db.MusicInfoDao;
import com.ldw.music.fragment.MainFragment;
import com.ldw.music.fragment.MenuFragment;
import com.ldw.music.slidemenu.SlidingMenu;
import com.ldw.music.utils.MusicUtils;
import com.ldw.music.utils.SplashScreen;

/**
 * 主类,首次进入应用会到这里
 * 该类提供了首页MainFragment的显示和侧滑MenuFragment的显示
 * @author longdw(longdawei1988@gmail.com)
 *
 */
@SuppressLint("HandlerLeak")
public class MainContentActivity extends FragmentActivity implements IConstants {

	/**
	 * 主Activity做了3件事
	 * 1、弹出启动页,在上一篇和上上一篇已经介绍
	 * 2、初始化UI,使用了SlidingMenu(在该应用讲解的差不多的时候再谈这个应用广泛的开源库)
	 * 3、finish或者exit,moveTaskToBack该activity(设置闹钟的最终目的是结束该应用)
	 */
	//ALARM_CLOCK_BROADCAST在该Activity用了2次,一次设置闹钟,一次接受闹钟的提醒,
	public static final String ALARM_CLOCK_BROADCAST = "alarm_clock_broadcast";
	/**
	 * SlidingMenu
	 * 一个非常著名的开源库,该网址讲了它基本的用法
	 * http://blog.csdn.net/caiwenfeng_for_23/article/details/34411815
	 * 另外这个地址里面才是能直接用的demo
	 * http://download.csdn.net/detail/caiwenfeng_for_23/7548019
	 */
	public SlidingMenu mSlidingMenu;
	/**
	 * 通过该list判断能不能退出
	 */
	private List<OnBackListener> mBackListeners = new ArrayList<OnBackListener>();
	public MainFragment mMainFragment;

	private Handler mHandler;
	private MusicInfoDao mMusicDao;
	private SplashScreen mSplashScreen;
	private int mScreenWidth;
	
	public interface OnBackListener {
		public abstract void onBack();
	}

	@Override
	protected void onCreate(Bundle arg0) {
		super.onCreate(arg0);

		DisplayMetrics metric = new DisplayMetrics();
		getWindowManager().getDefaultDisplay().getMetrics(metric);
		mScreenWidth = metric.widthPixels;

		initSDCard();
		
		IntentFilter filter = new IntentFilter();
		filter.addAction(ALARM_CLOCK_BROADCAST);
		registerReceiver(mAlarmReceiver, filter);

		setContentView(R.layout.frame_main);
		mSplashScreen = new SplashScreen(this);
		mSplashScreen.show(R.drawable.image_splash_background,
				SplashScreen.SLIDE_LEFT);
		// set the Above View
		mMainFragment = new MainFragment();
		//设置了左侧的主fragment,关于片段也会专门讲述,比开源库简单些
		getSupportFragmentManager().beginTransaction()
				.replace(R.id.frame_main, mMainFragment).commit();

		// configure the SlidingMenu,参数都可以在上面给的网址找到
		mSlidingMenu = new SlidingMenu(this);
		mSlidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_MARGIN);
		//“Sets which side the SlidingMenu should appear on.”
		mSlidingMenu.setMode(SlidingMenu.RIGHT);
		mSlidingMenu.setShadowWidthRes(R.dimen.shadow_width);
		mSlidingMenu.setShadowDrawable(R.drawable.shadow);
		mSlidingMenu.setBehindOffsetRes(R.dimen.slidingmenu_offset);
		mSlidingMenu.setFadeDegree(0.35f);
		//布局控件都要让context管理,所以传入this
		mSlidingMenu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
		//R.layout.frame_menu该文件作为容器,打开该文件你发现里面除了根节点,就是跟节点的id
		mSlidingMenu.setMenu(R.layout.frame_menu);
		//事务的特点就是每次使用就得新begintransaction
		getSupportFragmentManager().beginTransaction()
				.replace(R.id.frame_menu, new MenuFragment()).commit();

		mMusicDao = new MusicInfoDao(this);

		mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				mSplashScreen.removeSplashScreen();
			}
		};

		getData();
	}
	/**
	 * 正如开始所说该Activity3个功能,第三个就是结束该activity
	 */
	private void initSDCard() {
		IntentFilter intentFilter = new IntentFilter();
		intentFilter.setPriority(1000);// 设置最高优先级
		intentFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);// sd卡被插入,且已经挂载
		intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);// sd卡存在,但还没有挂载
		intentFilter.addAction(Intent.ACTION_MEDIA_REMOVED);// sd卡被移除
		intentFilter.addAction(Intent.ACTION_MEDIA_SHARED);// sd卡作为
															// USB大容量存储被共享,挂载被解除
		intentFilter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);// sd卡已经从sd卡插槽拔出,但是挂载点还没解除
		// intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);// 开始扫描
		// intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);// 扫描完成
		intentFilter.addDataScheme("file");
		registerReceiver(sdCardReceiver, intentFilter);// 注册监听函数
	}

	private void getData() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				if (mMusicDao.hasData()) {
					// 如果有数据就等三秒跳转
					mHandler.sendMessageDelayed(mHandler.obtainMessage(), 3000);
				} else {
					//如果没数据初始化后再进入,时间非常短
					/**
					 * 进入方法后我们知道其实没做什么必须要做的,
					 * 下面的4行代码可以删掉
					 */
					MusicUtils.queryMusic(MainContentActivity.this,
							START_FROM_LOCAL);
					MusicUtils.queryAlbums(MainContentActivity.this);
					MusicUtils.queryArtist(MainContentActivity.this);
					MusicUtils.queryFolder(MainContentActivity.this);
					mHandler.sendEmptyMessage(1);
				}
			}
		}).start();
	}

	public void registerBackListener(OnBackListener listener) {
		if (!mBackListeners.contains(listener)) {
			mBackListeners.add(listener);
		}
	}

	public void unRegisterBackListener(OnBackListener listener) {
		mBackListeners.remove(listener);
	}
	//通过返回键moveTaskToBack
	@Override
	public void onBackPressed() {
		if (mSlidingMenu.isMenuShowing()) {
			mSlidingMenu.showContent();
		} else {
			if (mBackListeners.size() == 0) {
				// super.onBackPressed();
				// 在activity中调用 moveTaskToBack (boolean nonRoot)方法即可将activity
				// 退到后台,注意不是finish()退出。
				// 参数为false代表只有当前activity是task根,指应用启动的第一个activity时,才有效;
				moveTaskToBack(true);
			}
			for (OnBackListener listener : mBackListeners) {
				listener.onBack();
			}
		}
	}
/**
 * 如果没有sd卡就没有音乐,以前的手机会把音乐等大文件放到sd卡上,现在的rom已经很大,已经取代了sd卡的位置,
 * android会检查target sdk,如果apk的target sdk版本小于android手机的版本,系统会自动适配以前的模式,不影响程序的运行
 * 这就是程序的向后兼容性
 */
	private final BroadcastReceiver sdCardReceiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals("android.intent.action.MEDIA_REMOVED")// 各种未挂载状态
					|| action.equals("android.intent.action.MEDIA_UNMOUNTED")
					|| action.equals("android.intent.action.MEDIA_BAD_REMOVAL")
					|| action.equals("android.intent.action.MEDIA_SHARED")) {
				finish();
				Toast.makeText(MainContentActivity.this, "SD卡以外拔出,本地数据没法初始化!",
						Toast.LENGTH_SHORT).show();
			}
		}
	};
	//显示自定义的dialog
	//双击showSleepDialog选中,Ctrl+Alt+H,show call hierarchy,点击下面控制台旁边call hierarchy 的onClick方法,然后就知道哪里调用该方法了,自定义dialog有多钟方式,大多数都需要infalter来找到view,进而通过view.findViwById找到该空间,对该控件进行监控或者进行设置
	public void showSleepDialog() {

		if (MusicApp.mIsSleepClockSetting) {
			cancleSleepClock();
			Toast.makeText(getApplicationContext(), "已取睡眠模式!",
					Toast.LENGTH_SHORT).show();
			return;
		}

		View view = View.inflate(this, R.layout.sleep_time, null);
		final Dialog dialog = new Dialog(this, R.style.lrc_dialog);
		dialog.setContentView(view);
		//摸dialog的外面不能取消
		dialog.setCanceledOnTouchOutside(false);

		Window dialogWindow = dialog.getWindow();
		WindowManager.LayoutParams lp = dialogWindow.getAttributes();
		dialogWindow.setGravity(Gravity.CENTER);
		// lp.x = 100; // 新位置X坐标
		// lp.y = 100; // 新位置Y坐标
		lp.width = (int) (mScreenWidth * 0.7); // 宽度
		// lp.height = 400; // 高度

		// 当Window的Attributes改变时系统会调用此函数,可以直接调用以应用上面对窗口参数的更改,也可以用setAttributes
		// dialog.onWindowAttributesChanged(lp);
		dialogWindow.setAttributes(lp);

		dialog.show();

		final Button cancleBtn = (Button) view.findViewById(R.id.cancle_btn);
		final Button okBtn = (Button) view.findViewById(R.id.ok_btn);
		final EditText timeEt = (EditText) view.findViewById(R.id.time_et);
		OnClickListener listener = new OnClickListener() {

			@Override
			public void onClick(View v) {
				if (v == cancleBtn) {
					dialog.dismiss();
				} else if (v == okBtn) {
					String timeS = timeEt.getText().toString();
					if (TextUtils.isEmpty(timeS)
							|| Integer.parseInt(timeS) == 0) {
						Toast.makeText(getApplicationContext(), "输入无效!",
								Toast.LENGTH_SHORT).show();
						return;
					}
					setSleepClock(timeS);
					dialog.dismiss();
				}
			}
		};

		cancleBtn.setOnClickListener(listener);
		okBtn.setOnClickListener(listener);
	}

	/**
	 * 设置睡眠闹钟
	 * 
	 * @param timeS
	 */
	private void setSleepClock(String timeS) {
		Intent intent = new Intent(ALARM_CLOCK_BROADCAST);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(
				MainContentActivity.this, 0, intent, 0);
		// 设置time时间之后退出程序
		int time = Integer.parseInt(timeS);
		long longTime = time * 60 * 1000L;
		AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
		am.set(AlarmManager.RTC, System.currentTimeMillis() + longTime,
				pendingIntent);
		MusicApp.mIsSleepClockSetting = true;
		Toast.makeText(getApplicationContext(), "将在"+timeS+"分钟后退出软件", Toast.LENGTH_SHORT)
				.show();
	}

	/**
	 * 取消睡眠闹钟
	 */
	private void cancleSleepClock() {
		Intent intent = new Intent(ALARM_CLOCK_BROADCAST);
		PendingIntent pendingIntent = PendingIntent.getBroadcast(
				MainContentActivity.this, 0, intent, 0);
		AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
		am.cancel(pendingIntent);
		MusicApp.mIsSleepClockSetting = false;
	}
	
	private BroadcastReceiver mAlarmReceiver = new BroadcastReceiver() {

		@Override
		public void onReceive(Context context, Intent intent) {
			//退出程序
			finish();
		}

	};

	@Override
	public void onDestroy() {
		super.onDestroy();
		unregisterReceiver(sdCardReceiver);
		unregisterReceiver(mAlarmReceiver);
		MusicApp.mServiceManager.exit();
		MusicApp.mServiceManager = null;
		MusicUtils.clearCache();
		cancleSleepClock();
		System.exit(0);//exit和finish是不同的,详情百度“如何退出一个android应用”
	}

}

其实这个Activity里面许多东西都是值得,继续深究的,比如:自定义dialog的几种方法,结束掉应用或者Activity的方法,开源库SlidingMenu的几种用法等

关于Dao层将在下一节讲述



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值