• 上门洗车APP --- Androidclient开发 之 项目结构介绍


    上门洗车APP --- Androidclient开发 之 项目结构介绍


    前言

    尽管公司项目较紧,但还是抽空给大家继续更新。

        o_O"~ 欢迎大家的关注,非常高兴和大家共同学习。前面给大家分享了项目中的以下内容:

    上门洗车APP --- Androidclient开发 前言及业务简介

    上门洗车APP --- Androidclient开发 之 网络框架封装介绍(一)

    上门洗车APP --- Androidclient开发 之 网络框架封装介绍(二)



    之前有非常多朋友私信过来说想打包一份源代码学习。因为本项目也是还在开发中,进度不是非常快。后台那边的一系列接口须要调试,自己也是时间精力有限,还请朋友见谅。本篇博文给大家介绍项目的  总体文件夹结构界面开发、项目中所使用的  自己定义控件技术点 等,同一时候也会打包一份眼下最新的源代码供感兴趣的朋友学习。


    关于项目文件夹结构

    首先我们来看下项目的文件夹结构,给大家做一些简单的介绍:


                      


    因为文件夹过多,我们分了两张图展示。先对源代码包的管理进行介绍:

    org.gaochun.activity  -------> 管理Activity

    org.gaochun.adapter -------> 通用万能Adapter

    org.gaochun.android.http  -------> Android-Async-Http框架

    org.gaochun.android.http.manager  -------> 通用数据管理(常量、URL、网络请求 等)

    org.gaochun.android.http.network -------> 自己定义回调接口

    org.gaochun.android.http.request -------> 请求參数管理

    org.gaochun.model -------> 实体Bean管理

    org.gaochun.parser -------> 解析接口及抽象解析器管理

    org.gaochun.parser.impl -------> 解析器管理

    org.gaochun.receiver -------> 监听推送消息的Receiver

    org.gaochun.ui -------> 标题栏及Application管理

    org.gaochun.utils  -------> 经常使用工具类

    org.gaochun.widget -------> 自己定义控件管理(AlertDialog、圆形ImageView、带声音的Toast等)


    部分技术点

    有木有感觉层次还是比較清晰的呢?好了,不扯淡!给出了这些包中各自的职责后。相信朋友能够非常清晰的找到相应所须要了解的类。

    这里大致介绍两个包中的内容,org.gaochun.adapter 和 org.gaochun.widget 其它包在之前介绍网络框架中大致有提到,看例如以下两个包中的内容:

                

    一个是通用的Adapter和通用的ViewHolder缓存类。一个是自己定义的提示框、圆形ImageView、带声音的Toast 。


    有时候项目里面有好多好多ListView,记得曾经一种傻逼的做法是往 adapter 包中塞各种 OrderAdapter,HistoryAdapter,...... 然后每一个 adapter 都是 extends BaseAdapter,假设有一百个Adapter,我去,这他妈是个什么概念。。。。嘿嘿,后来学乖了哟。

    关于通用Adapter可參考:https://github.com/JoanZapata/base-adapter-helper


    CommonAdapter:

    package org.gaochun.adapter;
    
    import java.util.List;
    
    import android.content.Context;
    import android.util.Log;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    
    /**
     * 通用 Adapter
     * https://github.com/JoanZapata/base-adapter-helper
     * @param <T>
     */
    public abstract class CommonAdapter<T> extends BaseAdapter{
    
        protected LayoutInflater mInflater;
        protected Context mContext;
        protected List<T> mDatas;
        protected final int mItemLayoutId;
    
        /**
         * 初始化通用Adapter
         * @param context   上下文
         * @param mDatas    须要显示的数据集合
         * @param itemLayoutId  子布局文件
         */
        public CommonAdapter(Context context, List<T> mDatas, int itemLayoutId)
        {
            this.mContext = context;
            this.mInflater = LayoutInflater.from(mContext);
            this.mDatas = mDatas;
            this.mItemLayoutId = itemLayoutId;
        }
    
        @Override
        public int getCount()
        {
            return mDatas.size();
        }
    
        @Override
        public T getItem(int position)
        {
            return mDatas.get(position);
        }
    
        @Override
        public long getItemId(int position)
        {
            return position;
        }
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent)
        {
            //从ViewHolder中获取控件view。若为空则创建
            final ViewHolder viewHolder = getViewHolder(position, convertView,parent);
    
            Log.i("gao_chun", position+"");
            convert(viewHolder, getItem(position));
    
            return viewHolder.getConvertView();
    
    
        }
    
        /**
         * 抽取出getView中间改变的部分
         * @param helper    holder缓存对象
         * @param item      Bean对象
         */
        public abstract void convert(ViewHolder helper, T item);
    
    
        /**
         * 获得ViewHolder中的view
         * @param position
         * @param convertView
         * @param parent
         * @return
         */
        private ViewHolder getViewHolder(int position, View convertView,ViewGroup parent)
        {
            return ViewHolder.get(mContext, convertView, parent, mItemLayoutId,position);
        }
    
    }
    

    ViewHolder:

    package org.gaochun.adapter;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.util.SparseArray;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import com.nostra13.universalimageloader.core.ImageLoader;
    
    
    /**
     * 通用 ViewHolder 缓存类
     * @author gao_chun
     *
     */
    public class ViewHolder{
    
        private ImageLoader imageLoader = ImageLoader.getInstance();
    
        private final SparseArray<View> mViews;
        private int mPosition;
        private View mConvertView;
    
        private ViewHolder(Context context, ViewGroup parent, int layoutId,int position)
        {
            this.mPosition = position;
            this.mViews = new SparseArray<View>();
            mConvertView = LayoutInflater.from(context).inflate(layoutId, parent,false);
            mConvertView.setTag(this);   // setTag
        }
    
        /**
         * 拿到一个ViewHolder对象
         *
         * @param context
         * @param convertView
         * @param parent
         * @param layoutId
         * @param position
         * @return
         */
        public static ViewHolder get(Context context, View convertView,ViewGroup parent, int layoutId, int position)
        {
            if (convertView == null){
                //创建ViewHolder对象 ,并做View缓存
                return new ViewHolder(context, parent, layoutId, position);
            }
            return (ViewHolder)convertView.getTag();
        }
    
        public View getConvertView()
        {
            return mConvertView;
        }
    
    
        /**
         * 通过控件的Id获取对于的控件,假设没有则增加views
         *
         * @param viewId
         * @return
         */
        public <T extends View> T getView(int viewId){
    
            View view = mViews.get(viewId);
            if (view == null){
                view = mConvertView.findViewById(viewId);
                mViews.put(viewId, view);
            }
            return (T)view;
        }
    
    
        /**
         * 为TextView设置字符串
         *
         * @param viewId
         * @param text
         * @return
         */
        public ViewHolder setText(int viewId, String text)
        {
            TextView view = getView(viewId);
            view.setText(text);
            return this;
        }
    
    
        /**
         * 为ImageView设置图片
         *  setImageResource
         * @param viewId
         * @param drawableId
         * @return
         */
        public ViewHolder setImageResource(int viewId, int drawableId)
        {
            ImageView view = getView(viewId);
            view.setImageResource(drawableId);
            return this;
        }
    
        /**
         * 为ImageView设置图片
         *  setImageBitmap
         * @param viewId
         * @param drawableId
         * @return
         */
        public ViewHolder setImageBitmap(int viewId, Bitmap bm)
        {
            ImageView view = getView(viewId);
            view.setImageBitmap(bm);
            return this;
        }
    
        /**
         * 为ImageView设置图片
         *  setImageByUrl
         * @param viewId
         * @param drawableId
         * @return
         */
       /* public ViewHolder setImageByUrl(int viewId, String url)
        {
            ImageLoader.getInstance(3, Type.LIFO).loadImage(url,(ImageView) getView(viewId));
            return this;
        }*/
    
        public ViewHolder setImageByUrl(int viewId, String url){
            imageLoader.displayImage(url,(ImageView)getView(viewId));
            return this;
        }
    
        public int getPosition(){
    
            return mPosition;
        }
    
    }
    

    这里还要给大家推荐一个技巧:ListView中按钮监听器 设置 及 优化,有个须要注意的地方是 setTag 能够记录信息。


    以下是实现带声音的Toast控件类源代码,大家能够下载源代码了解学习:

    package org.gaochun.widget;
    
    import com.washcar.R;
    
    import android.content.Context;
    import android.media.MediaPlayer;
    import android.util.DisplayMetrics;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.TextView;
    import android.widget.Toast;
    
    /**
     * 自己定义声音提示 Toast控件
     * @version 0.1
     * @created gao_chun
     */
    public class SoundToast extends Toast{
    
    	private MediaPlayer mPlayer;
    	private boolean isSound;
    
    	public SoundToast(Context context){
    
    		this(context, false);
    	}
    
    	public SoundToast(Context context, boolean isSound){
    		super(context);
    
    		this.isSound = isSound;
    
    		mPlayer = MediaPlayer.create(context, R.raw.newdatatoast);
    		mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
    			@Override
    			public void onCompletion(MediaPlayer mp){
    				mp.release();   //释放资源
    			}
    		});
    	}
    
    	@Override
    	public void show()
    	{
    		super.show();
    		if (isSound){
    			mPlayer.start();
    		}
    	}
    
    
    	/**
    	 * 获取控件实例
    	 *
    	 * @param context
    	 * @param text  提示消息
    	 * @param isSound   是否播放声音
    	 * @param duration  时长
    	 * @return
    	 */
    	public static SoundToast show(Context context, CharSequence text, boolean isSound, int duration){
    
    		SoundToast result = new SoundToast(context, isSound);
    		LayoutInflater inflate = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    		DisplayMetrics dm = context.getResources().getDisplayMetrics();
    		View v = inflate.inflate(R.layout.layout_toast, null);	//载入Toast布局
    		v.setMinimumWidth(dm.widthPixels);  //设置控件最小宽度为手机屏幕宽度
    		TextView tv = (TextView) v.findViewById(R.id.tv_lable);
    		tv.setText(text);
    		result.setView(v);
    		result.setDuration(duration);// 设置 显示多长时间;
    		//result.setGravity(Gravity.CENTER,0,0);
    		return result;
    	}
    
    }
    

    注:语音提示播报功能已经实现,在接收到server推送的订单后自己主动播报。因为眼下方便測试,在首页点击 订单中 按钮便可看到效果。部分自己定义控件这里也只是多的介绍了。感兴趣的童鞋能够下载了研究研究,没准以后在自己项目中就用到了。关于语音播报,在讯飞平台注冊了ID,之前简介过一些使用方法:Android语音播报、后台播报、语音识别 。大家能够參考下。


    关于界面

    关于res文件夹下的界面,想了想,貌似也没有什么好说的了,仅仅须要掌握一些经常使用的布局技巧,熟练使用Android中的布局属性,基本上简单的界面没有什么太大的问题。因为使用了 dimens 做适配,仅仅须要将使用dp的地方,换成如:android:padding="@dimen/dimen_20_dip" 就能够了。如登录界面:



    <?xml version="1.0" encoding="utf-8"?

    > <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background" > <LinearLayout android:id="@+id/layout_table" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dimen_30_dip" android:orientation="vertical" > <include layout="@layout/layout_line_horizonal" /> <EditText android:id="@+id/edit_username" style="@style/text_16" android:layout_width="match_parent" android:layout_height="@dimen/dimen_75_dip" android:background="@color/white" android:hint="@string/text_hint_username" android:inputType="phone" android:maxLength="11" android:padding="@dimen/dimen_20_dip" android:textColorHint="@color/text_hint_color" /> <EditText android:id="@+id/edit_password" style="@style/text_16" android:layout_width="match_parent" android:layout_height="@dimen/dimen_75_dip" android:layout_marginTop="@dimen/row_margin" android:background="@color/white" android:hint="@string/text_hint_password" android:inputType="textPassword" android:padding="@dimen/dimen_20_dip" android:textColorHint="@color/text_hint_color" /> <include layout="@layout/layout_line_horizonal" /> </LinearLayout> <Button android:id="@+id/button_login" style="@style/text_white_18" android:layout_width="match_parent" android:layout_height="@dimen/dimen_60_dip" android:layout_below="@+id/layout_table" android:layout_marginTop="@dimen/dimen_65_dip" android:background="@drawable/button_selector" android:gravity="center" android:onClick="onClick" android:text="@string/text_login" /> </RelativeLayout>



    个人中心界面:



    <?

    xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background" > <RelativeLayout android:id="@+id/layout_top" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" > <RelativeLayout android:id="@+id/layout_table" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/person_bg" android:padding="@dimen/dimen_20_dip" > <org.gaochun.widget.RoundImageView android:id="@+id/iv_avatar" android:layout_width="@dimen/dimen_135_dip" android:layout_height="@dimen/dimen_135_dip" android:layout_marginLeft="@dimen/dimen_20_dip" android:layout_marginRight="@dimen/dimen_10_dip" android:scaleType="centerCrop" android:src="@drawable/gao_chun" /> <TextView android:id="@+id/tv_user_name" style="@style/text_white_16" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/dimen_60_dip" android:layout_marginTop="@dimen/dimen_30_dip" android:layout_toRightOf="@+id/iv_avatar" android:text="gao_chun" android:textStyle="bold" /> <TextView android:id="@+id/tv_user_money" style="@style/text_white_16" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tv_user_name" android:layout_marginLeft="@dimen/dimen_45_dip" android:layout_marginTop="@dimen/dimen_20_dip" android:layout_toRightOf="@+id/iv_avatar" android:text="剩余金额:12345" android:textStyle="bold" /> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/layout_table" android:orientation="horizontal" android:padding="@dimen/dimen_20_dip" > <TextView style="@style/text_16" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/dimen_25_dip" android:layout_weight="1" android:text="优评:2" /> <View android:layout_width="1px" android:layout_height="match_parent" android:layout_marginRight="@dimen/dimen_40_dip" android:background="@color/line_gray" /> <TextView style="@style/text_16" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="中评:4" /> <View android:layout_width="1px" android:layout_height="match_parent" android:layout_marginRight="@dimen/dimen_40_dip" android:background="@color/line_gray" /> <TextView style="@style/text_16" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="差评:0" /> </LinearLayout> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@+id/layout_top" android:layout_marginTop="@dimen/dimen_30_dip" android:orientation="vertical" > <View android:layout_width="match_parent" android:layout_height="1px" android:background="@color/line_gray" /> <TextView android:id="@+id/tv_my_order" style="@style/text_black_16" android:layout_width="match_parent" android:layout_height="@dimen/dimen_75_dip" android:background="@drawable/row_selector" android:clickable="true" android:drawableLeft="@drawable/person_order" android:drawablePadding="@dimen/dimen_40_dip" android:gravity="center_vertical" android:onClick="onClick" android:padding="@dimen/dimen_25_dip" android:text="@string/text_my_order" /> <TextView android:id="@+id/tv_my_vip" style="@style/text_black_16" android:layout_width="match_parent" android:layout_height="@dimen/dimen_75_dip" android:layout_marginTop="@dimen/row_margin" android:background="@drawable/row_selector" android:clickable="true" android:drawableLeft="@drawable/person_vip" android:drawablePadding="@dimen/dimen_40_dip" android:gravity="center_vertical" android:onClick="onClick" android:padding="@dimen/dimen_25_dip" android:text="@string/text_my_vip" /> <TextView android:id="@+id/tv_my_notify" style="@style/text_black_16" android:layout_width="match_parent" android:layout_height="@dimen/dimen_75_dip" android:layout_marginTop="@dimen/row_margin" android:background="@drawable/row_selector" android:clickable="true" android:drawableLeft="@drawable/person_inform" android:drawablePadding="@dimen/dimen_40_dip" android:gravity="center_vertical" android:onClick="onClick" android:padding="@dimen/dimen_25_dip" android:text="@string/text_my_information" /> <TextView android:id="@+id/tv_my_more" style="@style/text_black_16" android:layout_width="match_parent" android:layout_height="@dimen/dimen_75_dip" android:layout_marginTop="@dimen/row_margin" android:background="@drawable/row_selector" android:clickable="true" android:drawableLeft="@drawable/person_more" android:drawablePadding="@dimen/dimen_40_dip" android:gravity="center_vertical" android:onClick="onClick" android:padding="@dimen/dimen_25_dip" android:text="@string/text_more" /> <include layout="@layout/layout_line_horizonal" /> </LinearLayout> <Button android:id="@+id/button_submit" style="@style/text_white_18" android:layout_width="match_parent" android:layout_height="@dimen/dimen_65_dip" android:layout_alignParentBottom="true" android:layout_marginBottom="@dimen/dimen_40_dip" android:background="@drawable/button_selector" android:gravity="center" android:onClick="onClick" android:text="@string/text_exit" /> </RelativeLayout>


    关于其它技术点,日后总结了看有没有必要给大家再介绍下,先就到这里吧!


    源代码下载:http://download.csdn.net/download/gao_chun/8861137


    【注:转载注明gao_chun的BLOG http://blog.csdn.net/gao_chun/article/details/46711649


  • 相关阅读:
    嵌入式设备之web服务器
    动环监控的设备架构设计
    墓碑机制
    淘宝APP消息推送模型
    Service Mesh架构的持续演进 单体模块化 SOA 微服务 Service Mesh
    网关架构演进之路
    理解了云原生,才能正确迎接云时代的到来 | 技术前沿 百度智能云 2019-09-10
    策略模式 VS 状态模式
    权限管理机制支持多种访问控制模型。
    二维码生成服务架构的演进与思考
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5149334.html
Copyright © 2020-2023  润新知