音乐播放器-MainContentActivity简析

来源:互联网 发布:floyd算法求解过程 编辑:程序博客网 时间:2024/04/29 19:14

很多时候我们写程序的时候经常用到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();}@Overrideprotected 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 ViewmMainFragment = 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管理,所以传入thismSlidingMenu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);//R.layout.frame_menu该文件作为容器,打开该文件你发现里面除了根节点,就是跟节点的idmSlidingMenu.setMenu(R.layout.frame_menu);//事务的特点就是每次使用就得新begintransactiongetSupportFragmentManager().beginTransaction().replace(R.id.frame_menu, new MenuFragment()).commit();mMusicDao = new MusicInfoDao(this);mHandler = new Handler() {@Overridepublic 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() {@Overridepublic 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@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void onReceive(Context context, Intent intent) {//退出程序finish();}};@Overridepublic 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 0
原创粉丝点击