上门洗车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】
上门洗车APP --- Androidclient开发 之 项目结构介绍的更多相关文章
- 上门洗车APP --- Androidclient开发 之 网络框架封装介绍(二)
上门洗车APP --- Androidclient开发 之 网络框架封装介绍(二) 前几篇博文中给大家介绍了一下APP中的基本业务及开发本项目使用的网络架构: 上门洗车APP --- Androidc ...
- AngularJS+Ionic开发-2.项目结构介绍
使用上篇博客<开发环境搭建>中的命令创建完成IonicHelloWorld项目,在VSCode中的左侧,显示该项目的结构信息,如下图所示: 1 .sourcesmaps文件夹 调试状态的j ...
- 家庭洗车APP --- Androidclient开展 之 网络框架包介绍(一)
家庭洗车APP --- Android客户端开发 之 网络框架包介绍(一) 上篇文章中给大家简单介绍了一些业务.上门洗车APP --- Android客户端开发 前言及业务简单介绍,本篇文章给大家介绍 ...
- 上门洗车App 竟然是块大肥肉!
http://www.leiphone.com/k-xiche-app-idea.html 打车App.租车App.防违规App我们见得多,但洗车App你一定没听过,之前在一次创业路演上碰到一个做上门 ...
- .NET Core实战项目之CMS 第十三章 开发篇-在MVC项目结构介绍及应用第三方UI
作为后端开发的我来说,前端表示真心玩不转,你如果让我微调一个位置的样式的话还行,但是让我写一个很漂亮的后台的话,真心做不到,所以我一般会选择套用一些开源UI模板来进行系统UI的设计.那如何套用呢?今天 ...
- SpringBoot项目结构介绍
一项目结构介绍 springboot框架本身对项目结构并没有特别的要求,但是按照最佳的项目结构可以帮助我们减少可能遇到的错误问题.结构如下: (1)应用主类SpringbootApplication应 ...
- 微信小程序开发01 --- 微信小程序项目结构介绍
一.微信小程序简单介绍: 微信官方介绍微信小程序是一个不需要下载安装就可使用(呵呵,JS代码不用下载吗?展示的UI不用下载吗?)的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用. ...
- Vuejs+elementUI框架开发的项目结构及文件关系
项目结构|----- build #webpack编译相关文件目录,一般不用动 |----- config #配置目录| |------ dev.env.js #开发环境变量| |-- ...
- 二十四、【开源】EFW框架Winform前端开发之项目结构说明和调试方法
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...
随机推荐
- javascript创建类的6种方式
javascript创建类的7种方式 一 使用字面量创建 1.1 示例 var obj={}; 1.2 使用场景 比较适用于临时构建一个对象,且不关注该对象的类型,只用于临时封装一次数据,且不适合代码 ...
- Android菜鸟的成长笔记(10)——使用Bundle在Activity之间传值
原文:[置顶] Android菜鸟的成长笔记(10)——使用Bundle在Activity之间传值 前面我们了解了如何启动一个Activity,一个Activity在启动另外一个Activity的时候 ...
- COCOS2D-X之帧动画的一种实现Demo
这个Demo主要是实现帧动画,建议游戏中少用帧动画.废话少说直接上代码. 一.我们直接在COCOS2D-X自带的HelloCpp的工程中添加代码即可.我们在初始化中添加如下代码并附上图片资源. CCS ...
- ANDROID 中设计模式的採用--创建型模式
所谓模式就是在某一情景下解决某个问题的固定解决方式. 全部的创建型模式都是用作对象的创建或实例化的解决方式. 1 简单工厂模式 创建对象的最简单方法是使用new来创建一个对象,假设仅仅创建一种固 ...
- xcode6 cocos2dx开玩笑git和github学习记录
1. git Xcode4开始,它一直Git作为一个内置的源代码控制(Source Control)工具,所以对于新项目的用途git要管理非常方便.在新建项目向导.可以直接选择Git作为源控制工具.项 ...
- ios html5 设定PhoneGap开发环境
怎么样IOS平台搭建PhoneGap开发环境(PhoneGap2.5) (2013-03-13 14:44:51) 标签: c=blog&q=it&by=tag" targe ...
- 与内存有关的那些事儿(数组分配空间不够,导致缓冲区溢出,从而strcpy会出现异常)
这日,我写下如下代码:#include <iostream>int main(void){ char *p = new char[5]; char *t = new char[5]; st ...
- Spark中的Scheduler
Spark中的Scheduler scheduler分成两个类型.一个是TaskScheduler与事实上现,一个是DAGScheduler. TaskScheduler:主要负责各stage中传入的 ...
- 旧发票要保留SIRET等信息,或者整个PDF
查看旧发票时,每次都实时生成发票是不行的,因为公司的SIRET居然会是变的!!
- nohup sort -k1 -n -t$'\t' ./bigfile.16 -o./test/bigfile.16.ok &
nohup sort -k1 -n -t$'\t' ./bigfile.16 -o./test/bigfile.16.ok &