01、 抽取BaseActivity
抽取BaseActivity的好处:
l 处理共同操作(避免代码重复,提高代码可维护性)
l 代码规范(方便阅读代码,方便理解代码,阅读代码的时间占85%)
l 可以提供常用变量、方法(方便调用,避免代码重复)
public abstract class BaseActivity extends FragmentActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
initView();
initListener();
initData();
registerCommonBtn();//注册返回按钮监听
}
// 在多个界面都有的点击按钮,可以在这个方法注册监听
private void registerCommonBtn() {
View view = findViewById(R.id.back);
if (view != null){
view.setOnClickListener(this);
}
}
/** 返回当前 Activity 使用的布局id*/
protected abstract int getLayoutId();
/** 只允许执行 findViewById 操作*/
protected abstract void initView() ;
/** 执行注册监听、Adapter、广播,等解耦的操作*/
protected abstract void initListener();
/** 获取数据,初始化界面*/
protected abstract void initData();
/** 在 BaseActiviy 没有处理的点击事件,都在这个方法处理 */
protected abstract void processClick(View v);
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.back://所有返回按钮的id名称都要设置为back
finish();
break;
default:
processClick(v);
break;
}
}
/** 显示一个内容为 msg 的吐司*/
protected void toast(String msg){
Toast.makeText(BaseActivity.this, msg, Toast.LENGTH_SHORT).show();
}
/** 打印一个等级为 error 的日志*/
protected void logE(String msg) {
LogUtils.e(getClass(), msg);
}
}
baseFragment
public abstract class BaseFragment extends Fragment implements View.OnClickListener{
private View root;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
root = inflater.inflate(getLayoutId(),null);
initView();
initListener();
initData();
registerCommonBtn();
return root;
}
// 在多个界面都有的点击按钮,可以在这个方法注册监听
private void registerCommonBtn() {
View view = findViewById(R.id.back);
if (view != null){
view.setOnClickListener(this);
}
}
/** 在当前Fragment使用的布局里查找控件*/
protected View findViewById(int id) {
return root.findViewById(id);
}
/** 返回当前 Activity 使用的布局id*/
protected abstract int getLayoutId();
/** 只允许执行 findViewById 操作*/
protected abstract void initView() ;
/** 执行注册监听、Adapter、广播,等解耦的操作*/
protected abstract void initListener();
/** 获取数据,初始化界面*/
protected abstract void initData();
/** 在 BaseActiviy 没有处理的点击事件,都在这个方法处理 */
protected abstract void processClick(View v);
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.back:
getFragmentManager().popBackStack();
break;
default:
processClick(v);
break;
}
}
/** 显示一个内容为 msg 的吐司*/
protected void toast(String msg){
Toast.makeText(getActivity(), msg, Toast.LENGTH_SHORT).show();
}
/** 打印一个等级为 error 的日志*/
protected void logE(String msg) {
LogUtils.e(getClass(), msg);
}
}
MainActivity
这里用到一个ViewCompat类
l ViewCompat它是v4支付库的一个类,可以向下兼容到android 1.6,api4,这个类是为了向下兼容3.0版本出来的那些属性动画
l ViewCompat的直接动画方法,无动画过渡效果 ViewCompat.setTranslationX(view, value);
l ViewCompat.animate()的动画方法,有动画过渡效果ViewCompat.animate().translationY()
public class MainActivity extends BaseActivity {
private TextView tv_video;
private TextView tv_audio;
private View indicate;
private ViewPager viewPager;
private List<Fragment> fragmentList;
private MainPagerAdapter mAdapter;
/**
* 返回当前 Activity 使用的布局id
*/
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
/**
* 只允许执行 findViewById 操作
*/
@Override
protected void initView() {
tv_video = (TextView) findViewById(R.id.main_tv_video);
tv_audio = (TextView) findViewById(R.id.main_tv_audio);
indicate = findViewById(R.id.main_indicate);
viewPager = (ViewPager) findViewById(R.id.main_viewpager);
}
/**
* 执行注册监听、Adapter、广播,等解耦的操作
*/
@Override
protected void initListener() {
tv_video.setOnClickListener(this);
tv_audio.setOnClickListener(this);
fragmentList = new ArrayList<>();
mAdapter = new MainPagerAdapter(getSupportFragmentManager(), fragmentList);
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new OnMainPageChangeListener());
}
/**
* 获取数据,初始化界面
*/
@Override
protected void initData() {
fragmentList.add(new VideoListFragment());
fragmentList.add(new AudioListFragment());
mAdapter.notifyDataSetChanged();
// 高亮视频标签
updateTabs(0);
// 初始化指示器宽度
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
indicate.getLayoutParams().width = screenWidth / fragmentList.size();
indicate.requestLayout();
}
/**
* 在 BaseActiviy 没有处理的点击事件,都在这个方法处理
*
* @param v
*/
@Override
protected void processClick(View v) {
switch (v.getId()){
case R.id.main_tv_video:
viewPager.setCurrentItem(0);
break;
case R.id.main_tv_audio:
viewPager.setCurrentItem(1);
break;
}
}
// 根据选择的position位置,修改所有标题的高亮和缩放状态
private void updateTabs(int position) {
updateTab(position, 0, tv_video);
updateTab(position, 1, tv_audio);
}
// 根据 position 是否等于要比较的 position ,修改tab 的颜色和大小
private void updateTab(int position, int tabPosition, TextView tab) {
if (position == tabPosition){
tab.setTextColor(getResources().getColor(R.color.green));
ViewCompat.animate(tab).scaleX(1.2f).scaleY(1.2f).setDuration(500).start();
}else {
tab.setTextColor(getResources().getColor(R.color.halfwhite));
ViewCompat.animate(tab).scaleX(0.9f).scaleY(0.9f).setDuration(500).start();
}
}
private class OnMainPageChangeListener implements ViewPager.OnPageChangeListener {
@Override
// 在界面滚动时被调用
// position 当前选中的页面
// positionOffset 当前页面的偏移百分比
// positionOffsetPixels 当前页面偏移的像素值
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// logE("OnMainPageChangeListener.onPageScrolled,position="+position+";positionOffset="+positionOffset+":positionOffsetPixels="+positionOffsetPixels);
// 指示器移动到的位置 = 起始位置 + 偏移位置
// 起始位置 = position * 指示器宽度
// 偏移位置 = 屏幕偏移的百分比 * 指示器宽度
// 偏移位置
float offsetX = positionOffset * indicate.getWidth();
// 起始位置
int startX = position * indicate.getWidth();
// 指示器移动到的位置
float translationX = startX + offsetX;
// 移动指示器
ViewCompat.setTranslationX(indicate, translationX);
}
@Override
// 当选中的界面发生变化时被调用
public void onPageSelected(int position) {
// logE("OnMainPageChangeListener.onPageSelected,position="+position);
// 将被选中的标题修改为高亮颜色并放大,没选中的则变暗并缩小
updateTabs(position);
}
@Override
// 当界面滚动状态改变时被调用
public void onPageScrollStateChanged(int state) {
// logE("OnMainPageChangeListener.onPageScrollStateChanged,state="+state);
}
}
}
MainPagerAdapter
public class MainPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
public MainPagerAdapter(FragmentManager fm, List<Fragment> fragmentList) {
super(fm);
this.fragmentList = fragmentList;
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
}
VideoPlayerActivity
查询数据库并展示的时候可以用CursorAdapter 他继承 BaseAdapter
里面封装了getCount() 和getItem()和getView()方法 只需要重写getView()里的两个抽象方法newView()和bindView().
查询数据库用到了系统提供的一个类 异步查询数据库AsyncQueryHandler
public class VideoListFragment extends BaseFragment {
private ListView listView;
private VideoListAdapter mAdapter;
@Override
protected int getLayoutId() {
return R.layout.fragment_video_list;
}
@Override
protected void initView() {
listView = (ListView) findViewById(R.id.listview);
}
@Override
protected void initListener() {
mAdapter = new VideoListAdapter(getActivity(), null);
listView.setAdapter(mAdapter);
listView.setOnItemClickListener(new OnVideoItemClickListener());
}
@Override
protected void initData() {
// 查询视频数据
ContentResolver resolver = getActivity().getContentResolver();
// Cursor cursor = resolver.query(Media.EXTERNAL_CONTENT_URI, new String[]{Media._ID/*"uid as _id"*/, Media.DURATION, Media.TITLE, Media.SIZE, Media.DATA}, null, null, null);
// CursorUtils.printCursor(cursor);
// mAdapter.swapCursor(cursor);
AsyncQueryHandler asyncQueryHandler = new MyAsyncQueryHandler(resolver);
// token 可以用于区分不同类型的查询
// cookie 要使用 cursor数据的对象
asyncQueryHandler.startQuery( 0, mAdapter ,Media.EXTERNAL_CONTENT_URI, new String[]{Media._ID/*"uid as _id"*/, Media.DURATION, Media.TITLE, Media.SIZE, Media.DATA}, null, null, null);
}
@Override
protected void processClick(View v) {
}
private class OnVideoItemClickListener implements AdapterView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// 获取被选中的视频数据
Cursor cursor = (Cursor) mAdapter.getItem(position);
VideoItem item = VideoItem.parserCursor(cursor);//解析cursor
// 打开播放界面
Intent intent = new Intent(getActivity(), VideoPlayerActivity.class);
intent.putExtra("videoItem",item);//将一个序列化的对象传递过去
startActivity(intent);
}
}
}
public class MyAsyncQueryHandler extends AsyncQueryHandler {//这个类时异步处理查询数据库的
private static final String TAG = "MyAsyncQueryHandler";
public MyAsyncQueryHandler(ContentResolver cr) {
super(cr);
}
@Override
// 当子线程查询结束之后,会调用这个方法将 cursor传递过来
protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
LogUtils.e(TAG,"MyAsyncQueryHandler.onQueryComplete,");
CursorAdapter adapter = (CursorAdapter) cookie;
adapter.swapCursor(cursor);//跟新列表数据
}
}
cursorAdapter
<span style="font-size:24px;">public class VideoListAdapter extends CursorAdapter {
public VideoListAdapter(Context context, Cursor c) {
super(context, c);
}
public VideoListAdapter(Context context, Cursor c, boolean autoRequery) {
super(context, c, autoRequery);
}
public VideoListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
}
@Override
// 创建新的View,并初始化ViewHolder
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = View.inflate(context, R.layout.video_item,null);
ViewHolder holder = new ViewHolder();
holder.tv_title = (TextView) view.findViewById(R.id.video_item_tv_title);
holder.tv_duration = (TextView) view.findViewById(R.id.video_item_tv_duration);
holder.tv_size = (TextView) view.findViewById(R.id.video_item_tv_size);
view.setTag(holder);
return view;
}
@Override
// 填充界面。cursor已经被移动到要获取数据的行
public void bindView(View view, Context context, Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
// 获取数据
String title = cursor.getString(cursor.getColumnIndex(Media.TITLE));
int duration = cursor.getInt(cursor.getColumnIndex(Media.DURATION));
long size = cursor.getLong(cursor.getColumnIndex(Media.SIZE));
// 填充内容
holder.tv_title.setText(title);
holder.tv_duration.setText(StringUtils.formatTime(duration));
holder.tv_size.setText(Formatter.formatFileSize(context,size));;
}
private class ViewHolder{
TextView tv_title,tv_duration,tv_size;
}
}</span>
解析cursor后得到的bean对象
public class VideoItem implements Serializable{
private String title;
private int duration;
private long size;
private String path;
// 解析 cursor 当前行的数据
public static VideoItem parserCursor(Cursor cursor){
VideoItem item = new VideoItem();
// 健壮性检查
if (cursor==null||cursor.getCount()==0){
return item;
}
item.title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
item.duration = cursor.getInt(cursor.getColumnIndex(MediaStore.Video.Media.DURATION));
item.size = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.SIZE));
item.path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
return item;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
@Override
public String toString() {
return "VideoItem{" +
"title='" + title + '\'' +
", duration=" + duration +
", size=" + size +
", path='" + path + '\'' +
'}';
}
}