从最早第一天上C语言课的时候,我老师就跟我们讲过,别啥玩意都写在main函数里面,把里面的东西分离出来封装一下,然后在main函数中调用。当时写的是算法题,其实只要能得出正确答案,并不用太过于在意代码的机构。可是如果写Android项目的话,动辄上万行代码,全写在四大组件里,其实没有任何问题,项目一样能跑的起来,不过那样的代码可维护性,拓展性,可读性都会非常烂。以前写过一个制作表情包的App,先开始项目的主要代码全部压在了Activity里面,也没怎么在意,后来觉得这项目写的太烂,又把代码重构了一遍,虽然项目的功能完全没有变,可是代码的逻辑和结构变得更加清晰,也更易于维护拓展了。因为项目的代码量比较大,而这篇博文主要想讲解的是代码优化,所以写了个简化版的作为讲解,去掉了原来项目里大部分的功能,只留些许的功能讲解其中数据和视图的分离。
左边的ListView单机可以添加图片进表情包,右边的ListView是可以选取某个图片进行操作,长按则删除,中间的是个控制面板,可以通过触碰对图片进行位置移动//原项目没这么丑,这是简化版的,各位看官担待。
先贴原先的代码 ,也就是没进行过优化前所有代码都积压在Activity的代码
item_layout.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp">
<ImageView
android:id="@+id/type_image"
android:layout_centerVertical="true"
android:layout_width="50dp"
android:layout_height="50dp" />
</RelativeLayout>
activity_main.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.cjm.simplefight.MainActivity">
<ImageView
android:id="@+id/fight_img"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal">
<ListView
android:id="@+id/ori_list"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<com.example.cjm.simplefight.MoveView
android:id="@+id/move_view"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
<ListView
android:id="@+id/img_list"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
public class ViewItem {
private Bitmap bitmap;
private int x;
private int y;
public Bitmap getBitmap() {
return bitmap;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
public class MoveView extends View {
/*
* 该控件为控制台中操控元素上下左右移动的控件
* 提供了一个接口
* 回调了手指在该控件的移动情况
* 这样就可以使元素进行相应的移动
* */
private int color=getResources().getColor(R.color.mycolor);
private float startX;
private float startY;
public interface MoveViewListener{
void move(float staX,float staY,float stoX,float stoY);
}
private MoveViewListener moveViewListener;
public void setMoveViewListener(MoveViewListener moveViewListener) {
this.moveViewListener = moveViewListener;
}
public MoveView(Context context) {
this(context, null);
}
public MoveView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MoveView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startX=event.getX();
startY=event.getY();
break;
case MotionEvent.ACTION_MOVE:
float stopX=event.getX();
float stopY=event.getY();
moveViewListener.move(startX,startY,stopX,stopY);
startX=stopX;
startY=stopY;
break;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(color);
}
}
public class ImgAdapter extends BaseAdapter{
private List<ViewItem> itemList;
private LayoutInflater inflater;
public ImgAdapter(Context context,List<ViewItem> itemList){
this.itemList=itemList;
inflater=LayoutInflater.from(context);
}
@Override
public int getCount() {
return itemList.size();
}
@Override
public Object getItem(int position) {
return itemList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
AdapterHolder holder=null;
ViewItem viewItem=itemList.get(position);
if(convertView==null){
holder=new AdapterHolder();
//当元素类别为图片时,加载图片的布局
convertView=inflater.inflate(R.layout.item_layout,parent,false);
holder.type_image=(ImageView)convertView.findViewById(R.id.type_image);
convertView.setTag(holder);
}else{
holder=(AdapterHolder)convertView.getTag();
}
holder.type_image.setImageBitmap(viewItem.getBitmap());
return convertView;
}
private final class AdapterHolder{
private ImageView type_image;
}
}
public class MainActivity extends Activity {
private int poi=-1;
private Bitmap picture;
private ImageView imageView;
private ListView ori_list;
private ListView img_list;
private List<ViewItem> oriItems;
private List<ViewItem> imgItems;
private ImgAdapter oriAdapter;
private ImgAdapter imgAdapter;
private MoveView moveView;
private int res[]={R.drawable.a10,R.drawable.a11,R.drawable.a12,R.drawable.a13,R.drawable.a14,R.drawable.a15};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitData();
InitView();
InitListener();
}
private void InitData(){
oriItems=new ArrayList<ViewItem>();
imgItems=new ArrayList<ViewItem>();
for(int i:res){
ViewItem item=new ViewItem();
item.setBitmap(BitmapFactory.decodeResource(getResources(),i));
oriItems.add(item);
}
}
private void InitView(){
oriAdapter=new ImgAdapter(this,oriItems);
imgAdapter=new ImgAdapter(this,imgItems);
imageView=(ImageView)findViewById(R.id.fight_img);
ori_list=(ListView)findViewById(R.id.ori_list);
img_list=(ListView)findViewById(R.id.img_list);
moveView=(MoveView)findViewById(R.id.move_view);
ori_list.setAdapter(oriAdapter);
img_list.setAdapter(imgAdapter);
}
private void InitListener(){
ori_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ViewItem item=oriItems.get(position);
ViewItem newItem=new ViewItem();
newItem.setX(30);
newItem.setY(30);
newItem.setBitmap(item.getBitmap());
imgItems.add(item);
imgAdapter.notifyDataSetChanged();
draw();
}
});
img_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
poi=position;
draw();
}
});
moveView.setMoveViewListener(new MoveView.MoveViewListener() {
@Override
public void move(float staX, float staY, float stoX, float stoY) {
Amove(staX,staY,stoX,stoY);
draw();
}
});
}
private void draw(){
picture = Bitmap.createBitmap(imageView.getWidth(), imageView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas(picture);
canvas.drawColor(Color.WHITE);
for(ViewItem item:imgItems) {
canvas.drawBitmap(item.getBitmap(), item.getX(), item.getY(), null);
}
if(poi!=-1){
ViewItem item=imgItems.get(poi);
Paint pc = new Paint();
pc.setStrokeWidth(5);
pc.setStyle(Paint.Style.STROKE);
canvas.drawRect(item.getX(), item.getY(), item.getX() + item.getBitmap().getWidth(),
item.getY() + item.getBitmap().getHeight(), pc);
}
imageView.setImageBitmap(picture);
}
private void Amove(float staX, float staY, float stoX, float stoY){
int moveX = (int) (stoX - staX);
int moveY = (int) (stoY - staY);
ViewItem item = imgItems.get(poi);
item.setX(item.getX() + moveX);
item.setY(item.getY() + moveY);
}
}
项目代码就这么多,主要的逻辑都在Activity里面了,非常不好维护,现在从MainActivity方法中把数据抽离出来封装成ViewController类,去控制数据,然后提供相应的public函数供MainActivity去调用,一方面使数据相对独立自制,MainActivity的代码也会变得简洁很多,只需要去生成相应的Data,View,Listener函数就可以了
下面是把MainActivity抽离出来的两个类
public class ViewController {
private List<ViewItem> itemList;
private Bitmap picture=null;
public ViewController(){
itemList=new ArrayList<ViewItem>();
}
public List<ViewItem> getList(){
return itemList;
}
public void addItem(ViewItem item){
itemList.add(item);
}
public void draw(ImageView imageView,int poi){
picture = Bitmap.createBitmap(imageView.getWidth(), imageView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas=new Canvas(picture);
canvas.drawColor(Color.WHITE);
for(ViewItem item:itemList) {
canvas.drawBitmap(item.getBitmap(), item.getX(), item.getY(), null);
}
if(poi!=-1){
ViewItem item=itemList.get(poi);
Paint pc = new Paint();
pc.setStrokeWidth(5);
pc.setStyle(Paint.Style.STROKE);
canvas.drawRect(item.getX(), item.getY(), item.getX() + item.getBitmap().getWidth(),
item.getY() + item.getBitmap().getHeight(), pc);
}
imageView.setImageBitmap(picture);
}
public void move(int poi,float staX, float staY, float stoX, float stoY){
int moveX = (int) (stoX - staX);
int moveY = (int) (stoY - staY);
ViewItem item = itemList.get(poi);
item.setX(item.getX() + moveX);
item.setY(item.getY() + moveY);
}
}
public class MainActivity extends Activity {
private int poi=-1;
private ImageView imageView;
private ListView ori_list;
private ListView img_list;
private List<ViewItem> oriItems;
private ImgAdapter oriAdapter;
private ImgAdapter imgAdapter;
private ViewController viewController;
private MoveView moveView;
private int res[]={R.drawable.a10,R.drawable.a11,R.drawable.a12,R.drawable.a13,R.drawable.a14,R.drawable.a15};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InitData();
InitView();
InitListener();
}
private void InitData(){
viewController=new ViewController();
oriItems=new ArrayList<ViewItem>();
for(int i:res){
ViewItem item=new ViewItem();
item.setBitmap(BitmapFactory.decodeResource(getResources(),i));
oriItems.add(item);
}
}
private void InitView(){
oriAdapter=new ImgAdapter(this,oriItems);
imgAdapter=new ImgAdapter(this,viewController.getList());
imageView=(ImageView)findViewById(R.id.fight_img);
ori_list=(ListView)findViewById(R.id.ori_list);
img_list=(ListView)findViewById(R.id.img_list);
moveView=(MoveView)findViewById(R.id.move_view);
ori_list.setAdapter(oriAdapter);
img_list.setAdapter(imgAdapter);
}
private void InitListener(){
ori_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ViewItem item=oriItems.get(position);
ViewItem newItem=new ViewItem();
newItem.setX(30);
newItem.setY(30);
newItem.setBitmap(item.getBitmap());
viewController.addItem(item);
imgAdapter.notifyDataSetChanged();
viewController.draw(imageView,poi);
}
});
img_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
poi=position;
viewController.draw(imageView,poi);
}
});
moveView.setMoveViewListener(new MoveView.MoveViewListener() {
@Override
public void move(float staX, float staY, float stoX, float stoY) {
viewController.move(poi,staX,staY,stoX,stoY);
viewController.draw(imageView,poi);
}
});
}
}
或许是因为这个项目其实也很小,看不出这种写法的优越之处,当一个Activity的代码量庞大的时候,会明显感觉到一个整合Activity中所用到的数据的类的好处。