手机影音项目笔记(一)



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 + '\'' +
                '}';
    }
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值