突然想起一个叫树的东西,没错,就是那个树,世界上任何数据结构都可以用图表示,而树作为图的一个重要组成部分,或者我们能够分析的部分(毕竟图这东西不够抽象),已经应用在各个领域,毕竟这个世界是由数据组成的。
然后这里为什么要说道树呢,这就是这个app解析博客的数据结构,我们从程序启动界面开始,就进入了这个“树”,那是一个节点,或者是根节点,然后我们解析的过程就是遍历这个树的各个节点,至于树的遍历,什么前序遍历、中序遍历、后序遍历是遍历的一种抽象形式,我们也是逐次从根节点到各个叶子节点遍历,比如说,程序启动后进入的主界面是根节点,那么主界面的叶子节点先达到哪里呢?就是本文要讲述的MainFragment,它不是唯一的叶子,还有一个叶子,是MenuFragment,显然menufragment要简单的多,我们打开程序左滑,就看到了menufragment,毕竟MainFragment这个节点的东西多,我们就多篇文章介绍。
从这个地方开始mainFragment就开始了,
mMainFragment = new MainFragment();
//设置了左侧的主fragment,关于片段也会专门讲述,比开源库简单些
getSupportFragmentManager().beginTransaction()
.replace(R.id.frame_main, mMainFragment).commit();
/**
*
*/
package com.ldw.music.fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.ldw.music.MusicApp;
import com.ldw.music.R;
import com.ldw.music.activity.IConstants;
import com.ldw.music.aidl.IMediaService;
import com.ldw.music.db.AlbumInfoDao;
import com.ldw.music.db.ArtistInfoDao;
import com.ldw.music.db.FavoriteInfoDao;
import com.ldw.music.db.FolderInfoDao;
import com.ldw.music.db.MusicInfoDao;
import com.ldw.music.interfaces.IOnServiceConnectComplete;
import com.ldw.music.model.MusicInfo;
import com.ldw.music.service.ServiceManager;
import com.ldw.music.uimanager.MainBottomUIManager;
import com.ldw.music.uimanager.SlidingDrawerManager;
import com.ldw.music.uimanager.UIManager;
import com.ldw.music.uimanager.UIManager.OnRefreshListener;
import com.ldw.music.utils.MusicTimer;
/**
* 首页内容 该类展示了软件的几大模块 另外要注意嵌套的两层ViewPager
*
* @author longdw(longdawei1988@gmail.com)
*
*/
public class MainFragment extends Fragment implements IConstants,
IOnServiceConnectComplete, OnRefreshListener, OnTouchListener {
private GridView mGridView;
private MyGridViewAdapter mAdapter;
protected IMediaService mService;
private MusicInfoDao mMusicDao;
private FolderInfoDao mFolderDao;
private ArtistInfoDao mArtistDao;
private AlbumInfoDao mAlbumDao;
private FavoriteInfoDao mFavoriteDao;
public UIManager mUIManager;
private MusicTimer mMusicTimer;
private MusicPlayBroadcast mPlayBroadcast;
private MainBottomUIManager mBottomUIManager;
private SlidingDrawerManager mSdm;
private RelativeLayout mBottomLayout, mMainLayout;
private Bitmap defaultArtwork;
private ServiceManager mServiceManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMusicDao = new MusicInfoDao(getActivity());
mFolderDao = new FolderInfoDao(getActivity());
mArtistDao = new ArtistInfoDao(getActivity());
mAlbumDao = new AlbumInfoDao(getActivity());
mFavoriteDao = new FavoriteInfoDao(getActivity());
mServiceManager = MusicApp.mServiceManager;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 这是首先要看的位置,view的inflater好懂,最后一个false是必须的,false表示只继承父类的layoutParams
// true:并且root存在,将xml挂载到root下,返回root,false:返回xml的跟布局,第二个参数只是为了创建正确的第一个参数的根布局的layoutParams
View view = inflater.inflate(R.layout.frame_main1, container, false);
//gridView就是那5个选项,我的音乐、文件夹...
mGridView = (GridView) view.findViewById(R.id.gridview);
mAdapter = new MyGridViewAdapter();
//全部布局
mMainLayout = (RelativeLayout) view.findViewById(R.id.main_layout);
mMainLayout.setOnTouchListener(this);
//播放控制器
mBottomLayout = (RelativeLayout) view.findViewById(R.id.bottomLayout);
//service待会解释,这里进入后是bind方式启动service
MusicApp.mServiceManager.connectService();
//该类实现了IOnServiceConnectComplete,这里传入this当服务启动成功后可以调用该类实现了的接口的方法
MusicApp.mServiceManager.setOnServiceConnectComplete(this);
mGridView.setAdapter(mAdapter);
//用来管理viewpager
mUIManager = new UIManager(getActivity(), view);
mUIManager.setOnRefreshListener(this);//
//抽屉,控制歌词字幕的显示,
mSdm = new SlidingDrawerManager(getActivity(), mServiceManager, view);
mBottomUIManager = new MainBottomUIManager(getActivity(), view);
mMusicTimer = new MusicTimer(mSdm.mHandler, mBottomUIManager.mHandler);
mSdm.setMusicTimer(mMusicTimer);
//该广播通过传入的数据控制播放和ui
mPlayBroadcast = new MusicPlayBroadcast();
IntentFilter filter = new IntentFilter(BROADCAST_NAME);
filter.addAction(BROADCAST_NAME);
getActivity().registerReceiver(mPlayBroadcast, filter);
return view;
}
//给gridview设置数据
private class MyGridViewAdapter extends BaseAdapter {
private int[] drawable = new int[] { R.drawable.icon_local_music,
R.drawable.icon_favorites, R.drawable.icon_folder_plus,
R.drawable.icon_artist_plus, R.drawable.icon_album_plus };
private String[] name = new String[] { "我的音乐", "我的最爱", "文件夹", "歌手",
"专辑" };
private int musicNum = 0, artistNum = 0, albumNum = 0, folderNum = 0,
favoriteNum = 0;
@Override
public int getCount() {
return 5;
}
@Override
public Object getItem(int arg0) {
return null;
}
@Override
public long getItemId(int position) {
return position;
}
public void setNum(int music_num, int artist_num, int album_num,
int folder_num, int favorite_num) {
musicNum = music_num;
artistNum = artist_num;
albumNum = album_num;
folderNum = folder_num;
favoriteNum = favorite_num;
notifyDataSetChanged();
}
@Override
public View getView(final int position, View convertView,
ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = getActivity().getLayoutInflater().inflate(
R.layout.main_gridview_item, null);
holder.iv = (ImageView) convertView
.findViewById(R.id.gridview_item_iv);
holder.nameTv = (TextView) convertView
.findViewById(R.id.gridview_item_name);
holder.numTv = (TextView) convertView
.findViewById(R.id.gridview_item_num);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
switch (position) {
case 0:// 我的音乐
holder.numTv.setText(musicNum + "");
break;
case 1:// 我的最爱
holder.numTv.setText(favoriteNum + "");
break;
case 2:// 文件夹
holder.numTv.setText(folderNum + "");
break;
case 3:// 歌手
holder.numTv.setText(artistNum + "");
break;
case 4:// 专辑
holder.numTv.setText(albumNum + "");
break;
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int from = -1;
switch (position) {
case 0:// 我的音乐
from = START_FROM_LOCAL;
break;
case 1:// 我的最爱
from = START_FROM_FAVORITE;
break;
case 2:// 文件夹
from = START_FROM_FOLDER;
break;
case 3:// 歌手
from = START_FROM_ARTIST;
break;
case 4:// 专辑
from = START_FROM_ALBUM;
break;
}
mUIManager.setContentType(from);
}
});
holder.iv.setImageResource(drawable[position]);
holder.nameTv.setText(name[position]);
return convertView;
}
private class ViewHolder {
ImageView iv;
TextView nameTv, numTv;
}
}
@Override
public void onServiceConnectComplete(IMediaService service) {
// service绑定成功会执行到这里
refreshNum();
}
public void refreshNum() {
int musicCount = mMusicDao.getDataCount();
int artistCount = mArtistDao.getDataCount();
int albumCount = mAlbumDao.getDataCount();
int folderCount = mFolderDao.getDataCount();
int favoriteCount = mFavoriteDao.getDataCount();
mAdapter.setNum(musicCount, artistCount, albumCount, folderCount,
favoriteCount);
}
//播放控制
private class MusicPlayBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(BROADCAST_NAME)) {
MusicInfo music = new MusicInfo();
int playState = intent.getIntExtra(PLAY_STATE_NAME, MPS_NOFILE);
int curPlayIndex = intent.getIntExtra(PLAY_MUSIC_INDEX, -1);
Bundle bundle = intent.getBundleExtra(MusicInfo.KEY_MUSIC);
if (bundle != null) {
music = bundle.getParcelable(MusicInfo.KEY_MUSIC);
}
switch (playState) {
case MPS_INVALID:// 考虑后面加上如果文件不可播放直接跳到下一首
mMusicTimer.stopTimer();
mSdm.refreshUI(0, music.duration, music);
mSdm.showPlay(true);
mBottomUIManager.refreshUI(0, music.duration, music);
mBottomUIManager.showPlay(true);
break;
case MPS_PAUSE:
mMusicTimer.stopTimer();
mSdm.refreshUI(mServiceManager.position(), music.duration,
music);
mSdm.showPlay(true);
mBottomUIManager.refreshUI(mServiceManager.position(),
music.duration, music);
mBottomUIManager.showPlay(true);
mServiceManager.cancelNotification();
break;
case MPS_PLAYING:
mMusicTimer.startTimer();
mSdm.refreshUI(mServiceManager.position(), music.duration,
music);
mSdm.showPlay(false);
mBottomUIManager.refreshUI(mServiceManager.position(),
music.duration, music);
mBottomUIManager.showPlay(false);
break;
case MPS_PREPARE:
mMusicTimer.stopTimer();
mSdm.refreshUI(0, music.duration, music);
mSdm.showPlay(true);
mBottomUIManager.refreshUI(0, music.duration, music);
mBottomUIManager.showPlay(true);
// 读取歌词文件
mSdm.loadLyric(music);
break;
}
}
}
}
@Override
public void onRefresh() {
refreshNum();
}
int oldY = 0;
//显示歌词
@Override
public boolean onTouch(View v, MotionEvent event) {
int bottomTop = mBottomLayout.getTop();
System.out.println(bottomTop);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
oldY = (int) event.getY();
if (oldY > bottomTop) {
mSdm.open();
}
}
return true;
}
}
贴到这里,发现其实读代码真的困难的地方是不知道该怎么读,许多时候从树的根部往下读,当多个叶子在同一排的时候(兄弟叶子)就会造成正在读一部分代码的时候需要在读不完的时候就去读另一个,这跟单线程的程序的执行是一样的,不断的进栈和出栈,难点在于,我们读的程序不是单线程,并且线程之间还交互,这就需要考虑时间先后,数据的耦合,比如broadReceiver,service,handler等需要和其他线程交互。