Android开发如何写出优雅的代码详解手机开发

很多时候我们去面试,人家总会问一个问题,你们公司开发一个app是如何进行技术选择的,app中涉及到了哪些开发模式,谈谈你对mvc、mvp和mvvm的区别。或许在这些问题上每个人有每个人的看法,在我看来把代码写清楚,用简单清晰的方式将要实现的功能写出来就可以了。

在去年的时候,我接手公司的移动开发部门,刚开始看代码的时候我是崩溃的,Android和ios的代码中,超过2000行的代码随处可见。在我以前的职业生涯中,这是不可想象的,除非你写的是系统代码,如果是业务上的代码为啥不可以抽象,为啥不可以分层呢,或者换一个写法。在那个项目中,大量的使用mvp,大量的为了抽象而抽象,就像后端的开发中先定义一个接口,然后自己去实现,对于这种写法,显得太啰嗦,会给后面的开发人员带来一定的误解。

所以在进行重构之前,我对app进行了梳理,比较老的聊天的功能我先不动,而上层的电商的实现上我做了一些基础模块的封装,而这些基础模块我考虑适量的引入开源库,而对于具体的业务模块我主要分为4层:模型层、接口层、核心层、界面层。模型层定义了所有的模型;接口层封装了服务器提供的API;核心层处理所有业务逻辑;界面层就处理界面的展示。最后按模块进行开发。
这里写图片描述
为了具体说明,下面看一个界面实例。

聊天功能实现

首先看一下最终的效果吧。
这里写图片描述
这里写图片描述
在这个界面中表情的实现是一个要点,在聊天系统中表情是特殊的文本,我们将表情发送出去另一端在接受到文本后怎么转换的呢?
例如微笑对应的图片为��,这里使用HashMap

public class EmojiParseUtils { 
private Pattern mPattern=null; 
//建议使用SparseArray 
public static HashMap<String, Integer> EMOTION_MAP = new HashMap<>(); 
static { 
EMOTION_MAP.put("[呵呵]", R.drawable.expression_01_45); 
EMOTION_MAP.put("[愁]", R.drawable.expression_02_45); 
EMOTION_MAP.put("[花心]", R.drawable.expression_03_45); 
EMOTION_MAP.put("[思考]", R.drawable.expression_04_45); 
EMOTION_MAP.put("[酷]", R.drawable.expression_05_45); 
EMOTION_MAP.put("[大哭]", R.drawable.expression_06_45); 
EMOTION_MAP.put("[卖萌]", R.drawable.expression_07_45); 
EMOTION_MAP.put("[闭嘴]", R.drawable.expression_08_45); 
EMOTION_MAP.put("[睡觉]", R.drawable.expression_09_45); 
EMOTION_MAP.put("[快哭了]", R.drawable.expression_10_45); 
EMOTION_MAP.put("[尴尬]", R.drawable.expression_11_45); 
EMOTION_MAP.put("[怒]", R.drawable.expression_12_45); 
EMOTION_MAP.put("[挤眼]", R.drawable.expression_13_45); 
EMOTION_MAP.put("[呲牙大笑]", R.drawable.expression_14_45); 
EMOTION_MAP.put("[惊讶]", R.drawable.expression_15_45); 
EMOTION_MAP.put("[挥泪]", R.drawable.expression_16_45); 
EMOTION_MAP.put("[爱你]", R.drawable.expression_17_45); 
EMOTION_MAP.put("[加我]", R.drawable.expression_18_45); 
EMOTION_MAP.put("[抓狂]", R.drawable.expression_19_45); 
EMOTION_MAP.put("[吐]", R.drawable.expression_20_45); 
EMOTION_MAP.put("[偷笑]", R.drawable.expression_21_45); 
EMOTION_MAP.put("[微笑]", R.drawable.expression_22_45); 
EMOTION_MAP.put("[没看见]", R.drawable.expression_23_45); 
EMOTION_MAP.put("[懒得理你]", R.drawable.expression_24_45); 
EMOTION_MAP.put("[馋嘴]", R.drawable.expression_25_45); 
EMOTION_MAP.put("[困]", R.drawable.expression_26_45); 
EMOTION_MAP.put("[惊恐]", R.drawable.expression_27_45); 
EMOTION_MAP.put("[汗]", R.drawable.expression_28_45); 
EMOTION_MAP.put("[哈哈]", R.drawable.expression_29_45); 
EMOTION_MAP.put("[加油]", R.drawable.expression_30_45); 
EMOTION_MAP.put("[奋斗]", R.drawable.expression_31_45); 
EMOTION_MAP.put("[怒骂]", R.drawable.expression_32_45); 
EMOTION_MAP.put("[疑问]", R.drawable.expression_33_45); 
EMOTION_MAP.put("[嘘]", R.drawable.expression_34_45); 
EMOTION_MAP.put("[晕]", R.drawable.expression_35_45); 
EMOTION_MAP.put("[哼]", R.drawable.expression_36_45); 
EMOTION_MAP.put("[哀]", R.drawable.expression_37_45); 
EMOTION_MAP.put("[奥特曼]", R.drawable.expression_38_45); 
EMOTION_MAP.put("[潜水]", R.drawable.expression_39_45); 
EMOTION_MAP.put("[拜拜]", R.drawable.expression_40_45); 
EMOTION_MAP.put("[太开心]", R.drawable.expression_41_45); 
EMOTION_MAP.put("[挖鼻屎]", R.drawable.expression_42_45); 
EMOTION_MAP.put("[鼓掌]", R.drawable.expression_43_45); 
EMOTION_MAP.put("[生病]", R.drawable.expression_44_45); 
EMOTION_MAP.put("[坏笑]", R.drawable.expression_45_45); 
EMOTION_MAP.put("[左哼哼]", R.drawable.expression_46_45); 
EMOTION_MAP.put("[捂脸]", R.drawable.expression_47_45); 
EMOTION_MAP.put("[压历大]", R.drawable.expression_48_45); 
EMOTION_MAP.put("[鄙视]", R.drawable.expression_49_45); 
EMOTION_MAP.put("[委屈]", R.drawable.expression_50_45); 
EMOTION_MAP.put("[钱]", R.drawable.expression_51_45); 
EMOTION_MAP.put("[阴险]", R.drawable.expression_52_45); 
EMOTION_MAP.put("[亲亲]", R.drawable.expression_53_45); 
EMOTION_MAP.put("[黑线]", R.drawable.expression_54_45); 
EMOTION_MAP.put("[可怜]", R.drawable.expression_55_45); 
EMOTION_MAP.put("[菜刀]", R.drawable.expression_56_45); 
EMOTION_MAP.put("[给力]", R.drawable.expression_57_45); 
EMOTION_MAP.put("[啤酒]", R.drawable.expression_58_45); 
EMOTION_MAP.put("[篮球]", R.drawable.expression_59_45); 
EMOTION_MAP.put("[乒乓球]", R.drawable.expression_60_45); 
EMOTION_MAP.put("[鸡蛋]", R.drawable.expression_61_45); 
EMOTION_MAP.put("[吃饭]", R.drawable.expression_62_45); 
EMOTION_MAP.put("[猪头]", R.drawable.expression_63_45); 
EMOTION_MAP.put("[玫瑰花]", R.drawable.expression_64_45); 
EMOTION_MAP.put("[凋谢]", R.drawable.expression_65_45); 
EMOTION_MAP.put("[香吻]", R.drawable.expression_66_45); 
EMOTION_MAP.put("[心]", R.drawable.expression_67_45); 
EMOTION_MAP.put("[伤心]", R.drawable.expression_68_45); 
EMOTION_MAP.put("[蛋糕]", R.drawable.expression_69_45); 
EMOTION_MAP.put("[闪电]", R.drawable.expression_70_45); 
EMOTION_MAP.put("[圣诞节]", R.drawable.expression_71_45); 
EMOTION_MAP.put("[高跟鞋]", R.drawable.expression_72_45); 
EMOTION_MAP.put("[足球]", R.drawable.expression_73_45); 
EMOTION_MAP.put("[兔子]", R.drawable.expression_74_45); 
EMOTION_MAP.put("[便便]", R.drawable.expression_75_45); 
EMOTION_MAP.put("[晚安]", R.drawable.expression_76_45); 
EMOTION_MAP.put("[太阳]", R.drawable.expression_77_45); 
EMOTION_MAP.put("[礼物]", R.drawable.expression_78_45); 
EMOTION_MAP.put("[花]", R.drawable.expression_79_45); 
EMOTION_MAP.put("[good]", R.drawable.expression_80_45); 
EMOTION_MAP.put("[弱]", R.drawable.expression_81_45); 
EMOTION_MAP.put("[握手]", R.drawable.expression_82_45); 
EMOTION_MAP.put("[耶]", R.drawable.expression_83_45); 
EMOTION_MAP.put("[抱拳]", R.drawable.expression_84_45); 
EMOTION_MAP.put("[来]", R.drawable.expression_85_45); 
EMOTION_MAP.put("[靠]", R.drawable.expression_86_45); 
EMOTION_MAP.put("[不要]", R.drawable.expression_87_45); 
EMOTION_MAP.put("[OK]", R.drawable.expression_88_45); 
EMOTION_MAP.put("[鞭炮]", R.drawable.expression_89_45); 
EMOTION_MAP.put("[红包]", R.drawable.expression_90_45); 
EMOTION_MAP.put("[发财]", R.drawable.expression_91_45); 
EMOTION_MAP.put("[话筒]", R.drawable.expression_92_45); 
EMOTION_MAP.put("[兵]", R.drawable.expression_93_45); 
EMOTION_MAP.put("[熊猫]", R.drawable.expression_94_45); 
EMOTION_MAP.put("[蜡烛]", R.drawable.expression_95_45); 
EMOTION_MAP.put("[德州]", R.drawable.expression_96_45); 
EMOTION_MAP.put("[恐龙]", R.drawable.expression_97_45); 
EMOTION_MAP.put("[吉他]", R.drawable.expression_98_45); 
EMOTION_MAP.put("[肥皂]", R.drawable.expression_99_45); 
EMOTION_MAP.put("[台球]", R.drawable.expression_100_45); 
EMOTION_MAP.put("[火箭]", R.drawable.expression_101_45); 
EMOTION_MAP.put("[左车头]", R.drawable.expression_102_45); 
EMOTION_MAP.put("[车厢]", R.drawable.expression_103_45); 
EMOTION_MAP.put("[右车头]", R.drawable.expression_104_45); 
EMOTION_MAP.put("[浮云]", R.drawable.expression_105_45); 
EMOTION_MAP.put("[星星]", R.drawable.expression_106_45); 
EMOTION_MAP.put("[钻石]", R.drawable.expression_107_45); 
EMOTION_MAP.put("[钻戒]", R.drawable.expression_108_45); 
EMOTION_MAP.put("[沙发]", R.drawable.expression_109_45); 
EMOTION_MAP.put("[卷纸]", R.drawable.expression_110_45); 
EMOTION_MAP.put("[药丸]", R.drawable.expression_111_45); 
EMOTION_MAP.put("[钟]", R.drawable.expression_112_45); 
EMOTION_MAP.put("[草泥马]", R.drawable.expression_113_45); 
EMOTION_MAP.put("[大姨妈]", R.drawable.expression_114_45); 
EMOTION_MAP.put("[鱼]", R.drawable.expression_115_45); 
} 
public static int getEmojiByName(String imgName) { 
Integer integer = EMOTION_MAP.get(imgName); 
return integer == null ? -1 : integer; 
} 
public static HashMap<String, Integer> getEmojiMap() { 
HashMap EmojiMap = EMOTION_MAP; 
return EmojiMap; 
} 
}

当接受到表情时候我们只需要通过文字匹配就行:

public SpannableString getEmotionContent(final Context context, final TextView tv, String source) { 
SpannableString spannableString = new SpannableString(source); 
Resources res = context.getResources(); 
String regexEmotion = "//[([/u4e00-/u9fa5//w])+//]"; 
Pattern patternEmotion = Pattern.compile(regexEmotion); 
Matcher matcherEmotion = patternEmotion.matcher(spannableString); 
while (matcherEmotion.find()) { 
String key = matcherEmotion.group(); 
int start = matcherEmotion.start(); 
Integer imgRes = EmojiParseUtils.getEmojiByName(key); 
if (imgRes != null) { 
// 压缩表情图片 
int size = (int) tv.getTextSize() * 13 / 10; 
Bitmap bitmap = BitmapFactory.decodeResource(res, imgRes); 
Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true); 
ImageSpan span = new ImageSpan(context, scaleBitmap); 
spannableString.setSpan(span, start, start + key.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
} 
} 
return spannableString; 
} 

接下来我们需要对表情进行简单的封装,这个界面主要实现的是表情的滑动和指示器。

public class EmojiFragment extends Fragment { 
@BindView(R.id.viewPager) 
ViewPager viewPager; 
@BindView(R.id.indicatorView) 
IndicatorView indicatorView; 
private View view = null; 
private EmojiPagerAdapter pagerAdapter=null; 
private List<GridView> eViews = new ArrayList<>(); 
private List<String> eNames = new ArrayList<>(); 
private int screenWidth,spacing,itemWidth,gridViewH; 
private int prePagerPosition=0; 
@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
view = inflater.inflate(R.layout.gragment_chat_emoji, container, false); 
ButterKnife.bind(this, view); 
init(); 
return view; 
} 
private void init() { 
initParam(); 
initEmojiView(); 
initIndicator(screenWidth, gridViewH, eViews); 
} 
private void initParam() { 
screenWidth = UIUtils.getScreenWidth(getActivity()); 
spacing = UIUtils.dp2px(getActivity(),10); 
itemWidth = (screenWidth - spacing * 8) / 7; 
gridViewH = itemWidth * 3 + spacing * 3; 
} 
//绘制一个3行7列的View,每20个表情作为一组,同时添加到ViewPager对应的view集合中 
private void initEmojiView() { 
for (String emojiName : EmojiParseUtils.getEmojiMap().keySet()) { 
eNames.add(emojiName); 
if (eNames.size() == 20) { 
GridView gv = initEmotionGridView(eNames, screenWidth, spacing, itemWidth, gridViewH); 
eViews.add(gv); 
eNames = new ArrayList<>(); 
} 
} 
// 判断最后是否有不足20个表情,中间补空 
if (eNames.size() > 0&&eNames.size()<20) { 
for (int i=0;i<24-eNames.size();i++){ 
eNames.add(""); 
} 
GridView grid = initEmotionGridView(eNames, screenWidth, spacing, itemWidth, gridViewH); 
eViews.add(grid); 
} 
pagerAdapter = new EmojiPagerAdapter(eViews); 
viewPager.setAdapter(pagerAdapter); 
} 
//表情指示器 
private void initIndicator(int screenWidth, int gvHeight, List<GridView> eViews) { 
indicatorView.initIndicator(eViews.size()); 
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(screenWidth, gvHeight); 
viewPager.setLayoutParams(params); 
viewPager.addOnPageChangeListener(new SimpleViewPagerListener(){ 
@Override 
public void onPageSelected(int position) { 
indicatorView.indicatorView(prePagerPosition,position); 
prePagerPosition=position; 
} 
}); 
} 
private GridView initEmotionGridView(List<String> emotionNames, int gvWidth, int padding, int itemWidth, int gvHeight) { 
GridView gridView = new GridView(getActivity()); 
gridView.setNumColumns(7); 
gridView.setPadding(padding, padding, padding, padding); 
gridView.setHorizontalSpacing(padding); 
gridView.setVerticalSpacing(padding/2); 
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(gvWidth, gvHeight); 
gridView.setLayoutParams(params); 
// 给GridView设置表情图片 
EmojiGridAdapter adapter = new EmojiGridAdapter(getActivity(), emotionNames, itemWidth); 
gridView.setAdapter(adapter); 
gridView.setOnItemClickListener(EmojiUtils.getInstance().getOnItemClickListener(getActivity())); 
return gridView; 
} 
}

然后是一个指示器,根据表情的大小和每页显示的个数计算出指示器的位置。

public class IndicatorView extends LinearLayout { 
private Context mContext=null; 
private ArrayList<View> dotViews =new ArrayList<>(); 
private int size = 6; 
private int marginSize=15; 
private int pointSize ; 
private int marginLeft; 
private LayoutParams layoutParams=null; 
public IndicatorView(Context context) { 
this(context,null); 
} 
public IndicatorView(Context context, AttributeSet attrs) { 
this(context, attrs, 0); 
} 
public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) { 
super(context, attrs, defStyleAttr); 
mContext=context; 
init(); 
} 
private void init() { 
pointSize= UIUtils.dp2px(mContext,size); 
marginLeft=UIUtils.dp2px(mContext,marginSize); 
} 
public void initIndicator(int count){ 
removeAllViews(); 
for (int i = 0 ; i<count ; i++){ 
View view = new View(mContext); 
layoutParams = new LayoutParams(pointSize,pointSize); 
if(i!=0) 
layoutParams.leftMargin = marginLeft; 
view.setLayoutParams(layoutParams); 
if (i == 0){ 
view.setBackgroundResource(R.drawable.point_white); 
}else{ 
view.setBackgroundResource(R.drawable.point_gray); 
} 
dotViews.add(view); 
addView(view); 
} 
} 
public void indicatorView(int start,int next){ 
if(start < 0 || next < 0 || next == start){ 
start = next = 0; 
} 
final View ViewStrat =  dotViews.get(start); 
final View ViewNext =  dotViews.get(next); 
ViewNext.setBackgroundResource(R.drawable.point_white); 
ViewStrat.setBackgroundResource(R.drawable.point_gray); 
} 
}

附:相关源码

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/5659.html

(0)
上一篇 2021年7月17日
下一篇 2021年7月17日

相关推荐

发表回复

登录后才能评论