美文网首页我爱编程
GooglePlay开发笔记

GooglePlay开发笔记

作者: kim_liu | 来源:发表于2018-05-27 14:04 被阅读76次
    1. 页签使用PagerTab。使用PagerTab时,setOnPageChangeListener需要绑定在pageTab上。否则会出现滑动异常。(why?)

    2.在ViewPager中添加Fragment,使用FragmentPagerAdapter。getSupportFragmentManager()只有在FragmentActivity中才可调用,AppCompatActivity是继承于FragmentActivity的。

    3.使用string.xml中的数组时,使用代码

    context.getResources().getStringArray(R.array.arrayname);

    4.使用工厂模式,创建Fragment。

    通过position去创建Fragment,创建好的fragment放入Map中,要使用的时候不需要重新创建,只需要拿出来使用即可。代码如下:

     //通过position创建Fragment,然后将创建的Fragment装到Map中。
        private static ArrayMap<Integer,BaseFragment> map = new ArrayMap<>();
        public static BaseFragment createFragment(int position){
            BaseFragment baseFragment = map.get(position);
            if(baseFragment==null){
                switch (position){
                    case 0:
                        baseFragment = new HomeFragment();
                        break;
                    case 1:
                        baseFragment = new AppFragment();
                        break;
                    case 2:
                        baseFragment = new GameFragment();
                        break;
                    case 3:
                        baseFragment = new SubjectFragment();
                        break;
                    case 4:
                        baseFragment = new RecommendFragment();
                        break;
                    case 5:
                        baseFragment = new CategoryFragment();
                        break;
                    case 6:
                        baseFragment = new HotFragment();
                        break;
                }
                map.put(position,baseFragment);
            }
            return baseFragment;
        }
    

    5.主题问题。

    如果项目的BaseActivity继承了AppCompatActivity,那么项目的主题一定要是Theme.AppCompat的。否则就会崩溃。

    6.在BaseFragment中有这样的逻辑,根据网络情况显示不同的页面,加载失败,数据为空,加载中,加载成功,这几种情况显示的页面不同。

    思路: 创建一个FrameLayout,命名为LoadingView,往这个LoadingView中添加4个页面, 分别是errorView,loadingView,emptyView,successView,根据网络情况的不同显示不同的页面。successView的情况特殊一点,为了避免资源浪费,就是只有在加载成功情况下才会去创建successView。而每个子类加载成功的页面不同,所以createSuccessView()要写成抽象方法,供子类重写。
    在BaseFragment中使用LoadingView:

    public abstract class BaseFragment extends Fragment {
    
        private LoadingView loadingView;
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            loadingView = new LoadingView(UIUtils.getContext()){
    
                @Override
                public View createSuccessView() {
                    return fragmentCreateSuccessView();
                }
            };
            return loadingView;
        }
    
        public abstract View fragmentCreateSuccessView();
    
    }
    

    其中抽象方法:fragmentCreateSuccessView()是供子类重写的。

    7.自定义进度条。

    两张图片叠加使用drawable文件的根节点是:layer-list ,再在其中添加动画。使用,在ProgressBar中添加属性:android:indeterminateDrawable 将drawable文件赋值给该属性即可。

    7.1 设置动画属性文件

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--此标签表示几张图片叠加-->
        <!--第一张图片-->
    <item>
        <rotate
            android:drawable="@drawable/spinner_big_inner"
            android:fromDegrees="0"
            android:toDegrees="720"
            android:pivotY="50%"
            android:pivotX="50%"/>
    </item>
        <!--第二张图片-->
        <item>
            <rotate
                android:drawable="@drawable/spinner_big_outer"
                android:fromDegrees="720"
                android:toDegrees="0"
                android:pivotX="50%"
                android:pivotY="50%"/>
        </item>
    </layer-list>
    

    7.2 使用

     <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:indeterminateDrawable="@drawable/custom_loading"/>
    

    8.获取当前类名

    getClass().getSimpleName();
    

    9.ListView的封装
    9.1 封装BaseHolder

    /**
     * Created by kimliu on 2018/5/27.
     * ListView 中 ViewHolder的父类
     *
     * 在ListView的Adapter中 getView()中要使用到ViewHolder
     * 而ViewHolder的作用,是用来
     * 1.初始化Item 布局文件
     * 2.findViewById 找到布局文件中的控件
     * 3.打一个tag
     * 4.根据数据,更新UI 也就是把数据填充到UI中
     *
     * 因此 封装的BaseHolder 就必须完成这四步,无法确定的 比如初始化Item布局文件,
     * 就写一个抽象方法,交给子类去做
     */
    
    public abstract class BaseHolder<T> {
    
        private  View mRootView;
        private T data;//Item对应的数据
    
        /**
         * 在构造方法中就initView
         */
        public BaseHolder(){
            mRootView = initView();
            mRootView.setTag(this);//3.给View设置Tag
        }
    
        /**
         * 1.初始化Item布局文件
         * 2. findViewById 找到布局中的控件
         *  这两步父类无法实现,需要交给子类去实现
         * @return
         */
    
        public abstract View initView();
    
        /**
         * 外界拿到布局对象的方法
         */
        public View getRootView(){
            return mRootView;
        }
    
    
        /**
         * 4.刷新界面,将数据设置给控件
         * 这个方法在各个子类中的实现也各不相同,因此也需要交由子类去完成
         */
        public abstract void refreshView(T data);
    
    
        /**
         * 外界将数据传递进来的方法
         */
        public void setData(T data){
            this.data = data;
            //一拿到data 立即用上
            refreshView(data);
        }
        
        public T getData(){
            return data;
        }
    
    }
    

    9.2 封装BaseAdapter

    /**
     * Created by kimliu on 2018/5/27.
     * ListView 的 Adapter 的封装
     *
     */
    
    public abstract class MyBaseAdapter<T> extends BaseAdapter {
    
    
        private ArrayList<T> data;
        public void setData(ArrayList<T> data){
            this.data = data;
        }
    
    
        @Override
        public int getCount() {
            return data.size();
        }
    
        @Override
        public T getItem(int position) {
            return data.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            BaseHolder holder ;
            if(convertView == null){
                //此时如果添加new 出一个需要的Holder 那么 initView 和 findViewById 都完成了
                //但是我们并不知道需要的Holder是什么类型的,因此可以交给子类完成
                //创建抽象方法,由子类重写
                holder = getHolder();
    
            }else {
                holder = (BaseHolder) convertView.getTag();
            } 
    
            holder.setData(getItem(position));//设置数据
            return holder.getRootView();
        }
        public abstract BaseHolder<T> getHolder();
    }
    

    9.3 封装之后的使用,只需要new 出需要的Holder 继承BaseHolder 在子类的initView中进行 inflate 和 findViewById的操作,在refreshView中进行data的赋值即可。

    如:Adapter

     class HomeAdapter extends MyBaseAdapter<String>{
    
            @Override
            public BaseHolder<String> getHolder() {
                return new HomeHolder();
            }
        }
    

    ViewHolder:

    /**
     * Created by kimliu on 2018/5/27.
     */
    
    public class HomeHolder extends BaseHolder<String> {
    
        private TextView textView;
    
        @Override
        public View initView() {
            textView = new TextView(UIUtils.getContext());
            return textView;
        }
    
        @Override
        public void refreshView(String data) {
            textView.setText(data);
        }
    }
    

    这是最基础的ListView的封装。

    10.封装加载更多ListView。
    思路:展示两种布局,第一种 普通布局,第二种,加载更多布局。加载更多布局是在position == getCount()-1时显示。
    10.1.在MyBaseAdapter中添加两个方法,这两个方法是ListView显示不同布局必须要重写的两个方法:

    /**
     * 返回要加载的布局类型,有几种就返回几种
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        if(position == getCount()-1){
            //最后一个 加载更多类型
            return TYPE_MORE;
        }else{
            return getType();
        }
    
    }
    
    /**
     * 子类可能不止有普通类型 还有可能有别的类型,这里提供一个可以更改的入口
     *
     * 不写成抽象方法,子类如果有更多的类型就重写,没有就直接返回普通类型
     * @return
     */
    public  int getType(){
        return TYPE_NOMAL;
    }
    
    /**
     * 将来子类也可重写该方法 返回有几种type
     * @return
     */
    @Override
    public int getViewTypeCount() {
        return 2;
    }
    

    10.2. 在getView()中 根据Type设置布局,当type为TYPE_MORE时,设置加载更多布局,其它设置普通布局。

    if(getItemViewType(position) == TYPE_MORE){
        //是加载更多类型
        holder = new MoreHolder();
    }else{
    
        //此时如果添加new 出一个需要的Holder 那么 initView 和 findViewById 都完成了
        //但是我们并不知道需要的Holder是什么类型的,因此可以交给子类完成
        //创建抽象方法,由子类重写
        holder = getHolder();
    }
    

    10.3. 加载更多布局,要根据状态去刷新界面。
    加载更多有几种状态:1.可以加载更多,2.加载失败 3.不需要加载更多 根据这几种状态去刷新界面。
    可以在MoreHolder的构造方法中传入一个boolean类型的值,如果为true 则为可以加载更多 如果为false 则为不需要加载更多的状态 那么就可以setData(int) 在MoreHolder中setData,设置的是int类型的状态,因为BaseHolder是根据传入的值去刷新界面的,而MoreHolder是根据状态刷新界面,所以这里MoreHolder的泛型就为Integer。

    public class MoreHolder extends BaseHolder<Integer> {
    
    
        public static final int LOAD_MORE_MORE = 0;
        public static final int LOAD_MORE_ERROR = 1;
        public static final int LOAD_MORE_NONE = 2;
        private LinearLayout ll_more;
        private TextView tv_error;
    
    
        public MoreHolder(boolean hasMore) {
            setData(hasMore?LOAD_MORE_MORE:LOAD_MORE_NONE);
    
        }
    
        @Override
        public View initView() {
            View view = KimliuUtils.inflate(UIUtils.getContext(), R.layout.item_more);
            ll_more = view.findViewById(R.id.ll_more);
            tv_error = view.findViewById(R.id.tv_error);
            return view;
        }
    
        @Override
        public void refreshView(Integer data) {
            switch (data){
                case LOAD_MORE_MORE:
                    //加载更多
                    ll_more.setVisibility(View.VISIBLE);
                    tv_error.setVisibility(View.GONE);
                    break;
                case LOAD_MORE_ERROR:
                    //加载失败
                    ll_more.setVisibility(View.GONE);
                    tv_error.setVisibility(View.VISIBLE);
                    break;
                case LOAD_MORE_NONE:
                    //不需要加载更多
                    ll_more.setVisibility(View.GONE);
                    tv_error.setVisibility(View.GONE);
                    break;
    
            }
    
        }
    

    10.4.界面已经写完了,现在就要开始加载数据了。
    10.4.1 在MyBaseAdapter中写一个方法 onLoadMore()加载更多,具体代码中已注释

     private boolean isLoadMore = false;
        public void onLoadMore(final MoreHolder moreHolder){
            if(!isLoadMore){
                //只有当isLoadMore为false才会进来
                new Thread(){
                    @Override
                    public void run() {
                        isLoadMore = true;
                        //开启一个子线程,进行数据的加载
                        moreList = loadMore();
    
                        UIUtils.runOnUIThread(new Runnable() {
                            @Override
                            public void run() {
                                //根据moreList去刷新界面,刷新界面需要在主线程中去完成
                                if(moreList!=null){
                                    if(moreList.size() < limtNum()){
                                        //每一页为limtNum条数据,如果 < limtNum()了,说明到最后一页了
                                        moreHolder.setData(MoreHolder.LOAD_MORE_NONE);
                                        Toast.makeText(UIUtils.getContext(),
                                                "没有更多数据了", Toast.LENGTH_SHORT)
                                                .show();
                                    }else {
                                        // 还有更多数据
                                        moreHolder.setData(MoreHolder.LOAD_MORE_MORE);
                                    }
    
                                    //根据加载更多的结果去刷新页面
                                    // 将更多数据追加到当前集合中
                                    data.addAll(moreList);
                                    // 刷新界面
                                    MyBaseAdapter.this.notifyDataSetChanged();
    
                                }else{
                                    //如果moreList 为空,说明加载失败
                                    moreHolder.setData(MoreHolder.LOAD_MORE_ERROR);
                                }
    
                                //加载完毕,将isLoadMore改为false
                                isLoadMore = false;
                            }
                        });
    
    
                    }
                }.start();
            }
    
        }
    
        /**
         * 如果每页显示的条数不为20 那么子类重写
         * @return
         */
        public int limtNum(){
            return 20;
        }
    
    
        /**
         * 每个子类加载更多的情况不同,所有交由子类重写
         * @return
         */
        public abstract ArrayList<T> loadMore();
    

    加载更多的方法已经写好,我们在什么时候调用呢?
    10.4.2 调用加载更多的方法,我们需要在加载更多布局显示的时候调用onLoadMore(),对ListView来说,item显示的时候,一定会调用getView方法,在getView方法中判断Type 如果Type == TYPE_MORE,说明此时需要加载更多,同时我们需要进一步的判断,加载更多布局此时的状态,如果状态为LOAD_MORE_MORE,才会去加载更多。

    if(getItemViewType(position) == TYPE_NOMAL){
                holder.setData(getItem(position));//设置数据
            }else{
                //当ListView的Item显示时,必定会调getView方法,
               //因此,当getItemViewType(position) == TYPE_MORE
                //时,也就是加载更多布局显示的时候,我们需要调用//
            //onLoadMore(),而此时的holder 正是moreHolder
                MoreHolder moreHolder = (MoreHolder) holder;
                if(moreHolder.getData() == MoreHolder.LOAD_MORE_MORE){
                    //当moreHolder状态为可以加载更多时,才去加载更多
                    onLoadMore(moreHolder);
                }
            }
    

    相关文章

      网友评论

        本文标题:GooglePlay开发笔记

        本文链接:https://www.haomeiwen.com/subject/zspbjftx.html