开源地址:https://github.com/excilys/androidannotations
官网:http://androidannotations.org/
下载地址:https://github.com/excilys/androidannotations/wiki/Download
下载下来发现有多种情况下的,编译项目;
eclipse ,gradle,maven环境下;这里主要总结的是在eclipse和gradle编译环境下处理的项目
eclipse环境下配置:
1:配置自动编译注解的环境:(其实这里的配置环境跟ButterKniffe一样配置的)
在默认的情况下,ADT Eclipse项目的Preference中,Java Compiler下没有Annotation Processing;因为要使用开源 androidannotations 注解,发现eclipse没有Annotation Processin
解决办法:
需要配置插件:http://download.eclipse.org/releases/juno
第一步:先打开Help菜单,点击Install New Software
第二步,选择安装Juno:
第三步,在下面的列表中找到Programming Languages节点并展开,找到Eclipse Java Development Tools,勾选上,剩下的安装步骤你懂的,安装完了会要求自动重启Eclipse,重启后就有Annotation Processing啦。
重启后发现就会发现那个配置,
压缩包里包含两个jar文件:androidannotations-x.x.x.jar和androidannotations-api-x.x.x.jar,另外还有个examples文件夹
- androidannotations-x.x.x.jar是用来提供给java的注解处理插件
- androidannotations-api-x.x.x.jar是给android工程使用的包
下面用实例里带的HelloWorldEclipse演示如何使用
1. 在eclipse里导入实例工程HelloWorldEclipse
2. 修改HelloWorldEclipse中的lib文件夹为libs,并把androidannotations-api-x.x.x.jar放入目录,回到Eclipse里刷新工程,androidannotations-api-x.x.x.jar被自动引入到了build path
3. 新建一个compilers文件夹,将androidannotations-x.x.x.jar拷贝进来待用
4. 打开工程属性,在Java Build Path-library中的androidannotations-3.1-api.jar删除
5. 打开过程属性,在Java compiler-Annotation Processing中启用Annotation Processing
6. 打开过程属性,在Java compiler-Annotation Processing-Factory path中,先删除之前的androidannotations-3.1-api.jar,在把androidannotations-x.x.x.jar(在之前添加的compilers文件夹里)添加进来
7. Eclipse会提示重新编译,选择yes,编译成功!注意有时这里不怎么好使,eclipse会反应不过来,可以重启动eclipse,再次clean编译项目;
ant编译情况下:(待研究)
gradle环境下配置:
官方给的Gradle插件我没有测试成功,这个编译脚本是参照了网上的一个脚本写的
[plain] view plaincopy
- buildscript {
- repositories {
- mavenLocal()
- mavenCentral()
- }
- dependencies {
- classpath ‘com.android.tools.build:gradle:0.6.+‘
- classpath ‘com.googlecode.androidannotations:androidannotations:2.7.1‘
- classpath ‘com.googlecode.androidannotations:androidannotations-api:2.7.1‘
- }
- }
- repositories {
- mavenCentral()
- }
- apply plugin: ‘android‘
- dependencies {
- compile fileTree(dir: ‘libs‘, include: ‘*.jar‘)
- compile ‘com.squareup.dagger:dagger-compiler:1.0.1‘
- compile ‘com.squareup.dagger:dagger:1.0.1‘
- compile ‘com.squareup:otto:1.3.3‘
- }
- android {
- compileSdkVersion 8
- buildToolsVersion "19.0.0"
- sourceSets {
- main {
- manifest.srcFile ‘AndroidManifest.xml‘
- res.srcDirs = [‘res‘]
- assets.srcDirs = [‘assets‘]
- }
- instrumentTest.setRoot(‘tests‘)
- }
- }
- configurations {
- androidannotations
- androidannotations.extendsFrom(compile)
- }
- dependencies {
- androidannotations ‘com.googlecode.androidannotations:androidannotations:2.7.1‘
- compile ‘com.googlecode.androidannotations:androidannotations-api:2.7.1‘
- }
- android.applicationVariants.each { variant ->
- variant.javaCompile.classpath += configurations.androidannotations
- variant.javaCompile.options.compilerArgs += [
- ‘-processor‘, ‘com.googlecode.androidannotations.AndroidAnnotationProcessor‘,
- ‘-AandroidManifestFile=‘ + variant.processResources.manifestFile
- ]
- }
Dagger,ButterKnife,Roboguide,AndroidAnnotations框架的依赖注入浅析
注解框架---AndroidAnnotations这里强调了几点:
AndroidAnnotations简称为AA,大量的使用注解,不会对APP的造成不良影响,会影响到APP的执行性能。
分析主流注解框架:xUtils、ButterKnife、Dragger和Roboguice:
实现原理是一致的,都是通过反射机制实现的,在Runtime运行期去反射类中带有注解的Field和Method,然后再去执行注解相对应的逻辑代码,
这样做:在APP的运行期执行的,会造成执行的效率下降,执行时间变长的缺点。
AA工作的原理:
在编译器中加了一层额外的自动编译步骤,用来生成基于你源码的代码。
使用AA的注解在编译期间就已经自动生成了对应的子类,运行期运行的其实就是这个子类.则不会造成任何负面的影响
总结:从资料的分析来看,AndroidAnnotations像是综合了其他的几个框架的优点,通过注解,减少了繁琐(R.id.btn)的使用,并在编译的时候,将相应的注解进行转换。即:加快了开发的速度,又不影响app的性能。
综合考虑:
Android依赖注入:Dagger、RoboGuice和ButterKnife 这里有三者的比较,但是仅仅是译文,没有一个很好的解释到位。
相反:高手速成android开源项目[tool篇] 这里有很好的解释
AndroidAnnotations特点:
(1) 依赖注入:包括view,extras,系统服务,资源等等
(2) 简单的线程模型,通过annotation表示方法运行在ui线程还是后台线程
(3) 事件绑定:通过annotation表示view的响应事件,不用在写内部类
(4) REST客户端:定义客户端接口,自动生成REST请求的实现
(5) 没有你想象的复杂:AndroidAnnotations只是在在编译时生成相应子类
(6) 不影响应用性能:仅50kb,在编译时完成,不会对运行时有性能影响。
PS:AndroidAnnotations与roboguice的比较:
roboguice通过运行时读取annotations进行反射,所以可能影响应用性能,而AndroidAnnotations在编译时生成子类,所以对性能没有影响
roboguice 帮你处理了很多代码异常,利用annotation使得更少的代码完成项目
butterknife 利用annotation帮你快速完成View的初始化,减少代码
Dagger 依赖注入,适用于Android和Java
AndroidAnnotations是一个能够让你快速进行Android开发的开源框架,它能让你专注于真正重要的地方。
使代码更加精简,使项目更加容易维护,它的目标就是“Fast Android Development.Easy maintainance”。
通过一段时间的使用发现,相比原生的Android开发,确实能够让你少些很多代码,它的首页也给出了一个简单
的例子,通过例子也可以看到代码比之前几乎少写了一半。
No Magic [不知道为什么这样称呼,直译过来就是:无魔法,它的意思是:AndroidAnnotations在编译
的时候会产生一个子类(接下来你会明白),你查看这个子类,可以看到它是如何工作的]
除了@Eactivity @[email protected]之外还有
@EApplication
@EBean
@EFragment
@EService
@EView
@EviewGroup
@App
@Bean
@Fullscreen
注意的一点就是:使用AndroidAnnotations千万要记得,编译的时候会生成一个子类,这个子类的名称就是在
原来的类之后加了一个下划线“_”,比如这个例子产生的子类名称为“MyActivity_”,这就需要你在注册这个Activity的时候,在
AndroidManifest.xml中将 MyActivity 改为 MyActivity_ ,使用的时候也是使用MyActivity_来表示此类,如从另一个Activity跳转
到此节目就要这样用:startActivity(new Intent(this,MyActivity_.class));
一、组件的注解
@EActivity这个注解是用来修饰Activity的,向Activity注入布局,也可以设置页面的样式为全屏、无Title。这些使用具有实意的注解来实现,是不是很方便呀。对于其他的组件支持也是相当简单的,如@EService、@EReceiver、@EProvider、@EApplication、@EApplication、@EFragment。同时也能修饰自定义控件,注解为@EView、@EViewGroup。支持是不是相当全面
二、资源引用的注解
如果你想获取系统服务,只要在你的变量前加上@SystemService注解。
获取Intent中传递的值,加上@Extra注解,同时容错性很好,如果接收不到这个key对应的value,也没问题,你可以设置默认值。再有就是强转失败也不会造成crash,比如传递的是个int值,接收的时候是个String,也没有问题,只是接收失败罢了。
三、事件绑定注解
其他常用的还有@TextChange、@ItemClick、@SeekBarProgressChange。
四、异步线程与UI线程的交互
当View相关的成员变量初始化完毕后,会调用拥有@AfterViews注解的方法,你可以在里面初始化一些界面控件等。如果其他的成员变量处事完毕,就会调用@AfterInject。
比如大多数应用的逻辑是这样的,初始化界面之后,就发起耗时的数据请求,然后解析获取到的数据,再设置到界面上。一般的涉及UI线程与异步任务交互的时候,相对都比较麻烦一些。让我们看下AA是如何实现的。
很简单吧,UI线程执行的方法加个@UiThread,异步线程方法加个@Background,两者的交互就是方法直接的相互调用,其他的你不用关心,一切的实现都是AA的编译器去自动生成交互的代码。交互的过程,完全没有在执行异步的感觉,不用再使用Handler去发送接收Message了。两个注解就把以前一堆的代码实现的功能给实现了,真心给个最大的赞。
五、Rest API
在AA中也支持Rest API,而且支持所有的HTTP请求方法。下面演示的是一个GET请求。
@Rest("http://www.bookmarks.com")
public interface BookmarkClient {
@Get("/bookmarks/{userId}?search={search}")
Bookmarks getBookmarks(String search, String userId);
}
@Background
void searchAsync(String searchString, String userId) {
Bookmarks bookmarks = restClient.getBookmarks(searchString, userId);
updateBookmarks(bookmarks);
}
定义一个请求的接口,然后就可以直接使用了,不需要自己再去实现。这个跟公司后台接口设计紧密相关,如果你公司接口交互都是Rest风格的话,你就重写下,好好体验AA的魅力吧
跟原始android界面处理业务逻辑:
AndroidAnnotations工作在一个非常简单的方式。它会使用标准的Java注解处理工具自动添加一个额外的编译步骤生成的源代码。(译者注:即生成一个原有类名加“_”的类,这个类才是真正运行用的类)
* 源代码是什么样子的?
例如每个使用@EActivity注解的activity,将生成这个activity的一个子类,它的名字是在activity名称末尾追加一个下划线。
例如,下面的类:
@EActivity
public class MyActivity extends Activity{
// ...
}
将生成以下子类,在同一个包路径中,但在另一个源文件夹:(译者注:在测试过程中,并未在src目录下发现生成的类。但此类确实生成了,它在哪里呢?实际是在项目根目录的.apt_generated文件夹下,在eclipse中无法查看到,需要到资源管理其相应文件夹中查看。)
public final class MyActivity_ extends MyActivity{
// ...
}
该子类重载一些方法(例如的onCreate()),通过【委托方式】调用了你的activity的相关方法。这就是为什么你必须在AndroidManifest.xml文件中为你的activity名称添加“_”的原因:
<activityandroid:name=".MyListActivity_"/>
*
* 启动一个使用注解的activity
在原始的Android开发中,你通常是这样启动activity的:
startActivity(this,MyListActivity.class);
然而,如果使用AndroidAnnotations,真正被启动的activity是MyListActivity_:
startActivity(this,MyListActivity_.class);
创建Intent
1.AndroidAnnotations2.4及以上版本
我们提供了一个静态的助手方法,让你启动真正的activity:
// 启动 activity
MyListActivity_.intent(context).start();
// 创建一个intent使用 activity
Intentintent=MyListActivity_.intent(context).get();
// 你也可以设置flags
MyListActivity_.intent(context).flags(FLAG_ACTIVITY_CLEAR_TOP).start();
//你甚至可以在activity中使用@Extra定义扩展数据并作为activity的启动参数
MyListActivity_.intent(context).myDateExtra(someDate).start();
2.AndroidAnnotations2.7及以上版本
你还可以使用startActivityForResult()方法:
MyListActivity_.intent(context).startForResult();
启动一个使用注解的Service
在原始的Android开发中,你通常是这样启动一个服务的:
startService(this,MyService.class);
然而,如果使用AndroidAnnotations,则真正的服务MyService_将被启动:
startService(this,MyService_.class);
创建Intent
1.AndroidAnnotations2.7及以上版本
我们提供了一个静态的方法,让你启动生成的service:
// 启动service
MyService_.intent(context).start();
// 通过service创建一个intent
Intentintent=MyService_.intent(context).build();
// 你能在启动service时使用flags
MyService_.intent(context).flags(Intent.FLAG_GRANT_READ_URI_PERMISSION).start();
例如:
/**
*samy
*/
@EActivity(R.layout.activity_a20thirdparty_androidannotations_aamain)
// Sets content view to R.layout.translate
public class AAMainAct extends Activity {
@ViewById
// Injects R.id.textInput
// 提供id来生成控件,如果不指定ID,默认以控件名进行查找,如上面的myEditText
EditText myEditText;
@ViewById(R.id.myTextView)
// Injects R.id.myTextView
TextView textView;
@AnimationRes
// Injects android.R.anim.fade_in
Animation fadeIn;
@StringRes(R.string.hello)
String helloFormat;
@ColorRes
int androidColor;
@BooleanRes
boolean someBoolean;
@SystemService
NotificationManager notificationManager;
@SystemService
WindowManager windowManager;
//当View相关的成员变量初始化完毕后,会调用拥有@AfterViews注解的方法,你可以在里面初始化一些界面控件等。如果其他的成员变量处事完毕,就会调用@AfterInject。
/**
* AndroidAnnotations gracefully handles support for onBackPressed, whether you use ECLAIR (2.0), or pre ECLAIR android version.
*/
public void onBackPressed() {
super.onBackPressed();
Toast.makeText(this, "Back key pressed!", Toast.LENGTH_SHORT).show();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// windowManager should not be null
windowManager.getDefaultDisplay();
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
}
// //事件控制,可以以按钮的id作为方法名,同时支持的事件还有onLongClick,onTextChange等
// @LongClick
// When R.id.myButtonClicked button is clicked
// android:id="@+id/myButton"
// 两种点击事件方法都可以的;myButton() myButtonClicked()
@Click
void myButton() {
// void myButtonClicked() {
String name = myEditText.getText().toString();
setProgressBarIndeterminateVisibility(true);
someBackgroundWork(name, 5);
}
/**
* 对于@Click,方法名和xml文件中的id一样就可以这样写,AndroidAnnotations会自动识别,对于
* 多个Button,可以写多个@Click,也可以在这样
*/
// @Click({R.id.button1,R.id.button2,R.id.button3})
// void buttonClicked(Button bt){
// switch(bt.getId()){
// case R.id.button1: //
// break;
// ...
// }
// }
@Background
// Executed in a background thread
// 开启新线程后台运行,注意不要引用UI控件,而且返回值类型一定是void
void someBackgroundWork(String name, long timeToDoSomeLongComputation) {
try {
TimeUnit.SECONDS.sleep(timeToDoSomeLongComputation);
}
catch (InterruptedException e) {
}
String message = String.format(helloFormat, name);
updateUi(message, androidColor);
showNotificationsDelayed();
}
@UiThread
// Executed in the ui thread//UI线程
void updateUi(String message, int color) {
setProgressBarIndeterminateVisibility(false);
textView.setText(message);
textView.setTextColor(color);
}
@UiThread(delay = 2000)
// 可以设置延时时间,以毫秒为单位
void showNotificationsDelayed() {
Notification notification = new Notification(R.drawable.ic_launcher, "Hello !", 0);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(), 0);
notification.setLatestEventInfo(getApplicationContext(), "aa notification", "aa_test!", contentIntent);
notificationManager.notify(1, notification);
}
// android:id="@+id/startExtraActivity"
@LongClick
void startExtraActivity() {
// 这个传值有点不好弄
Intent intent = AAWithExtraAct_.intent(this).myDate(new Date()).myMessage("hello !").classCastExceptionExtra("42").get();
// Intent intent = ActivityWithExtra_.intent(this).myDate(new Date()).myMessage("hello !").get();
// intent.putExtra(ActivityWithExtra_.MY_INT_EXTRA, 42);
startActivity(intent);
}
@Click
void startListActivity(View v) {
startActivity(new Intent(this, AAListAct_.class));
}
@Touch
void myTextView(MotionEvent event) {
Toast.makeText(this, "myTextView was touched!: " , Toast.LENGTH_SHORT).show();
}
@Transactional
int transactionalMethod(SQLiteDatabase db, int someParam) {
return 42;
}
}
说到这里不得推荐一款开源框架:Butter Knife
Butter Knife也是使用注入视图的方式使开发人员尽可能少的编写代码。相比AndroidAnnotations,个人觉得没有AndroidAnnotations
使用简单,而且文档几乎也没有。还是先看一小段代码吧:
package com.example.butterknife;
import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import butterknife.InjectView;
import butterknife.OnClick;
import butterknife.ButterKnife;
import butterknife.OnItemClick;
import butterknife.OnLongClick;
import static android.widget.Toast.LENGTH_SHORT;
public class SimpleActivity extends Activity {
@InjectView(R.id.title) TextView title;
@InjectView(R.id.subtitle) TextView subtitle;
@InjectView(R.id.hello) Button hello;
@InjectView(R.id.list_of_things) ListView listOfThings;
@InjectView(R.id.footer) TextView footer;
private SimpleAdapter adapter;
@OnClick(R.id.hello) void sayHello() {
Toast.makeText(this, "Hello, views!", LENGTH_SHORT).show();
}
@OnLongClick(R.id.hello) boolean sayGetOffMe() {
Toast.makeText(this, "Let go of me!", LENGTH_SHORT).show();
return true;
}
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.simple_activity);
ButterKnife.inject(this);
// Contrived code to use the "injected" views.
title.setText("Butter Knife");
subtitle.setText("View \"injection\" for Android.");
footer.setText("by Jake Wharton");
hello.setText("Say Hello");
}
}
总之,两者虽有相似的地方,但看到AndroidAnnotations之后,就不愿使用Butter Knife了。另外,值得你注意的是butter Knife
有个代码生成的插件呢,不过是针对Android Studio的,请看图:
(gif 的图为什么不会动啊)
Generate
-> Generate ButterKnife Injections
点击 Confirm
, 代码自动生成!
插件项目主页:
https://github.com/inmite/android-butterknife-zelezny
下载插件:
http://plugins.jetbrains.com/plugin/7369
代码如下:
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Try to generate Activity injections by clicking to R.layout.activity_main
setContentView(R.layout.activity_main);
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new Fragment())
.commit();
}
}
}
2015年4月 星期六 19:30:36 edit by samy