Android开发,别把Java当Javascript

   Android开发中,匿名类的应用使得开发更加灵活,而匿名类的滥用却让程序变得杂乱无章、难以维护。程序员都是喜欢偷懒的,我们常常看到一个Activity类中布满了匿名类,有Thread、有Handler、有Adapter、有各种Listener以及给匿名类传递数据的final变量,给人的感觉就像随地大小便,很不文明。

      Java毕竟不是Javascript,没有闭包和没有匿名函数,把面向对象设计的语言用函数式编程的思想来写是很牵强的。下面贴一段JS代码:

  MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
    if(err) throw err;

    db.dropDatabase(function(err, done) {

      db.createCollection('test_custom_key', function(err, collection) {

        collection.insert({'a':1}, function(err, docs) {

          collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}).toArray(function(err, items) {
            console.dir(items);
            // Let's close the db
            db.close();
          });
        });
      });
    });
  });

      得益于JS的闭包、匿名函数、函数即变量等特性,JS开发者可以将函数嵌套发挥到令人叹为观止的地步,而且即使套了很多层,也不会显得很臃肿。你能想想如果Java套这么多层会是什么效果吗?或许编辑器都显示不下最长的缩进了,但能多Android开发者就好这口,来看个例子:

public class MyActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ((ListView) findViewById(R.id.listview)).setAdapter(new BaseAdapter() {

            @Override
            public View getView(int arg0, View arg1, ViewGroup arg2) {
                if (arg1 == null) {
                    arg1 = LayoutInflater.from(MyActivity.this).inflate(
                            R.id.feed, arg2, false);
                }

                arg1.findViewById(R.id.subject).setOnClickListener(
                        new OnClickListener() {

                            @Override
                            public void onClick(View v) {
                                final Handler handler = new Handler(
                                        new Callback() {

                                            @Override
                                            public boolean handleMessage(
                                                    Message msg) {
                                                // 此处省略50行
                                                return false;
                                            }
                                        });

                                new Thread(new Runnable() {

                                    @Override
                                    public void run() {
                                        // 此处省略100行
                                        handler.sendEmptyMessage(0);
                                    }
                                }).start();
                            }
                        });

                return arg1;
            }

            // 。。。。。。
        });
    }
}

       这是个真实的例子,其中很多习惯很多安卓开发者也有。这个onCreate函数竟然有近千行代码,已经完全丧失可读性了。如果你走了有人来接替你的活儿,看到这样的代码他一定会把你骂死。

 

      下面我就Android开发中常见的匿名类给出自己的替代方案,仅供参考,错误之处还请指证。

用继承接口代替匿名类

     这种方式适合各种Listener,这里以OnClickListener为例作说明。绑定事件一般是在onCreate时完成的,所以在onCreate中可能会有很多个OnClickListener的匿名类,比如:

findViewById(R.id.button).setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View arg0) {
          // ....
    }
});

     这时onCreate方法就会变得冗长,而且包含很多不应该出现在onCreate中的处理逻辑,如果我们让Activity去实现OnClickListener,将所有点击处理的listener都设为这个activity,在onClick中再根据view.getId()来分支处理,程序的结构就会紧凑很多:

public class DummyActivity extends Activity implements OnClickListener {
      //.....

      @Override
      protected void onCreate(Bundle savedInstanceState) {
             for(int id : in new int[] { R.id.button }) {
                  findViewById(id).setOnClickListener(this);
             }
      }

      @Override
      public void onClick(View arg0) {
            switch(arg0.getId()) {
            case R.id.button:
                   // ......
                   break;
            }
      }
}

       包括onLongClickListener等针对单一View的Listener都可以通过让Activity继承接口的方式来操作。如果是针对列表项的ItemListener,建议让Adapter去继承接口。

用子类代替匿名类

       如果一个Activity中有AdapterView的子类,如ListView、GridView,就会设置相应的Adapter,除了最简单的情形可以用SimpleAdapter、ArrayAdapter直接映射,很多情况都都需要继承BaseAdapter之类后重写一些方法,逻辑比较简单时用内部类不失为可取办法。例如很多人喜欢在onCreate中这么写:

((ListView)findViewById(R.id.listView)).setAdapter(new BaseAdapter() {
   @Override
   public View getView(int arg0, View arg1, ViewGroup arg2) {
       //......
   }
    //......
});

 为了不在onCreate参杂不相关的逻辑,保持代码结构合理,你可以尝试这样处理:

public class DummyActivity extends Activity {
      //.....

      @Override
      protected void onCreate(Bundle savedInstanceState) {
             ((ListView)findViewById(R.id.listView)).setAdapter(new MyAdapter(....));
      }

      private static class MyAdapter extends Base Adapter{
            MyAdapter(...) {
                  .......
            }
            
            @Override
        public View getView(int arg0, View arg1, ViewGroup arg2) {
                     .........
               }
      }
}

     至于static与否则取决于你是否要用到动态成员变量了,这种方式使得参数传递也更加方便:只需通过构造函数传入,不必通过final关键字。

用外部类代替匿名类

      对于Adapter这类逻辑简单的类可以用内部类处理,如果涉及到更加复杂的逻辑,比如数据处理、I/O、数据库操作等,建议用外部类使各个类的业务属性尽可能单一。比如Thread类,跟Activity类相关度本来就很低,为了偷懒非得硬生生塞进Activity中显然是不合适的,无论是匿名类还是子类的形式,这里就不举具体例子了。至于外部类的命名,如果想不到合适的名字,可考虑前缀命名,比如现在有一个DummyActivity,之前在里面塞了一个MyThread,那提出来再叫MyThread显然不合适,就以前缀命名的方式改为DummyActivityThread就一目了然了。

 

小结

      Javascript是门很优秀的语言,拥有函数式编程的诸多特性,合理的灵活嵌套可以使代码紧凑而优雅,而Java是一门严格面向对象的语言,匿名类嵌套的滥用会让你的程序臃肿混乱,建议不要把Java写成了Javascript的风格,那样你会很难维护。

posted @ 2013-12-31 14:22  云济术  阅读(1724)  评论(6编辑  收藏  举报