Dagger2使用攻略

Dagger 2 是 Square 的 Dagger 分支,是一种依赖注入框架。眼下由 Google 接手进行开发,Dagger2是使用代码自己主动生成和手写代码来实现依赖注入。据说在 Dagger 的基础上效率又提升了13%。而且相同功能强大。

1.Gradle配置

(1)须要配置apt 插件:(在project根文件夹build.gradle文件里加入例如以下代码)

dependencies {
...
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}

(2)加入依赖:(在modulebuild.gradle文件里加入例如以下代码)

apply plugin: 'com.neenbedankt.android-apt'// 凝视处理

    dependencies {
...
compile 'com.google.dagger:dagger:2.0.2'
apt 'com.google.dagger:dagger-compiler:2.0.2'
compile 'org.glassfish:javax.annotation:10.0-b28' // Java标注
}

● 当前最新版本号是2.0.2

● 加入2、3条依赖的原因參考:Dagger2入坑指南

● 假设在项目中同一时候用了Butterknife,在Build时会报凝视冲突。

解决方法:(在modulebuild.gradle文件里加入例如以下代码)

 packagingOptions {
exclude 'META-INF/services/javax.annotation.processing.Processor'
}

(3)最后点击Build-->Make Project就能够開始使用Dagger2了。

2.Dagger2 经常使用注解

写了一个简单的Demo,以下依据Demo进行介绍。

Dagger2要理解必须看Dagger 2自己主动生成的代码。Build后代码在项目-->app-->build-->generated-->source-->apt-->debug文件夹下。

1.Inject

@Inject:在须要依赖的地方使用这个注解。告诉Dagger这个类或者字段须要依赖注入,这样Dagger会构造一个这个类实例来满足依赖。

1.构造器注入:首先举一个简单的样例。无參构造方法。

public class Person {
private String name;
private int age; @Inject
public Person() {
} public String getName() {
return "Jack";
} public int getAge() {
return 15;
} }

这个的局限性是我们不能给这个类中的多个构造器作@Inject注解。

2.注解成员变量:

接着上面我们要使用这个实例化类。

public class MainActivity extends AppCompatActivity {

    @Inject
Person mPerson; StorageComponent mStorageComponent; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mStorageComponent = ((MyApplication)this.getApplication()).getStorageComponent();
mStorageComponent.inject(this);//注入MainActivity Toast.makeText(this,mPerson.getName() + "----" +mPerson.getAge(),Toast.LENGTH_SHORT).show();
}
}

这里我们能够查看生成的代码:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<Person> mPersonProvider; public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Person> mPersonProvider) { assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert mPersonProvider != null;
this.mPersonProvider = mPersonProvider;
} @Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mPerson = mPersonProvider.get();//这里mPersonProvider替我们实例化了Person
} public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<Person> mPersonProvider) {
return new MainActivity_MembersInjector(supertypeInjector, mPersonProvider);
}
}

同一时候我们也能够了解到@Inject Person mPerson; 为什么不能使用private 。上面代码中的injectMembers 方法调用后面会说到。

3.方法注入

public class LoginActivityPresenter {

    private LoginActivity loginActivity;

    @Inject //构造方法注入
public LoginActivityPresenter(LoginActivity loginActivity) {
this.loginActivity = loginActivity;
} @Inject //方法注入
public void enableWatches(Watches watches) {
watches.register(this);
}
}

如当我们希望传入类的当前实例(this引用)到被注入的依赖中。方法注入会在构造器调用后立即被调用,所以这表示我们能够传入全然被构造的this。

2.Module

@Module:用来修饰类,表示此类的方法是用来提供依赖的,它告诉Dagger在哪里能够找到依赖。

@Module
public class StorageModule { private final MyApplication application; public StorageModule(MyApplication application) {
this.application = application;
} @Provides
@Singleton
SharedPreferences provideSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(application);
} }

@Provides以下说到,@Singleton 单例,使用@Singleton注解之后。对象仅仅会被初始化一次。之后的每次都会被直接注入相同的对象。@Singleton就是一个内置的作用域。

3.Provides

@Provides:在@Module 中使用。我们定义的方法用这个注解,用于告诉 Dagger 我们须要构造实例并提供依赖。

为什么要使用@Provides,由于默认情况下,Dagger满足依赖关系是通过调用构造方法得到的实例,比方上面的Person类使用。可是有时由于@Inject 的局限性。我们不能使用@Inject。比方构造方法有多个、三方库中的类我们不知道他是怎么实现的等等。比如以下代码中的SharedPreferences。我们使用@Provides 返回一个创建好的实例,这样做也显得灵活不是吗?

    @Provides
@Singleton
SharedPreferences provideSharedPreferences(){
return PreferenceManager.getDefaultSharedPreferences(application);
}

注意:

● 依照习惯 @Providers方法都会用provide作为前缀,@Module类都用Module作为后缀。

● 假设@Provides方法有參数。这个參数也要保证能够被Dagger得到(比如通过其它的@Provides方法或者@Inject注解的构造方法。)

4.Component

@Component: 是@Inject@Module的桥梁,须要列出所有的@Modules以组成该组件。

@Singleton
@Component(modules = {
StorageModule.class ,
ScheduleModule.class
})
public interface StorageComponent { Storage execute();
void inject(MainActivity mMainActivity);
}

Dagger会依照上面接口生成一个实现类。生成类以Dagger为前缀。提供builder()来生成实例。调用方法:(由于是单例,所以这里放到了MyApplication)

public class MyApplication extends Application {

    private StorageComponent component;

    @Override
public void onCreate() {
super.onCreate(); component = DaggerStorageComponent
.builder()//调用构建类
.storageModule(new StorageModule(this)) //传入Module
.build();//生成实例 } public StorageComponent getStorageComponent() {
return component;
} }

MainActivity代码:

public class MainActivity extends AppCompatActivity {

    @Bind(R.id.button1)
Button mButton1; @Bind(R.id.button2)
Button mButton2; @Inject
SharedPreferences mPreferences;//全局的SharedPreferences @Inject
Person mPerson; StorageComponent mStorageComponent;
private final String KEY = "Dagger 2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this); mStorageComponent = ((MyApplication)this.getApplication()).getStorageComponent();
mStorageComponent.inject(this);//注入MainActivity
mStorageComponent.execute().storage();//运行储存操作 } @OnClick({R.id.button1,R.id.button2})
void onButtonClicked(View v) {
switch (v.getId()) {
case R.id.button1:
Toast.makeText(this,mPreferences.getString(KEY,"---"),Toast.LENGTH_SHORT).show();
//上面是演示样例获取mPreferences,实际中将SharedPreferences操作都能够封装进Storage中。例如以下
//Toast.makeText(this,
//mStorageComponent.execute().getStorage(),Toast.LENGTH_SHORT).show();
break;
case R.id.button2:
Toast.makeText(this,
mPerson.getName() + "----" + mPerson.getAge(),Toast.LENGTH_SHORT).show();
break;
}
}
}

下来把整个流程走一遍:首先进入MyApplication 运行DaggerStorageComponent.builder().storageModule(new StorageModule(this)).build(); 方法获取实例化StorageComponent。那我我们查看DaggerStorageComponent 类:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerStorageComponent implements StorageComponent {
private Provider<SharedPreferences> provideSharedPreferencesProvider;
private Provider<ScheduleImpl> provideScheduleProvider;
private Provider<Storage> storageProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector; private DaggerStorageComponent(Builder builder) {
assert builder != null;
initialize(builder);
} public static Builder builder() {
return new Builder();
} private void initialize(final Builder builder) {
this.provideSharedPreferencesProvider = ScopedProvider.create(StorageModule_ProvideSharedPreferencesFactory.create(builder.storageModule));
this.provideScheduleProvider = ScopedProvider.create(ScheduleModule_ProvideScheduleFactory.create(builder.scheduleModule));
this.storageProvider = Storage_Factory.create(provideSharedPreferencesProvider, provideScheduleProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideSharedPreferencesProvider, Person_Factory.create());//实例化到这里结束
} @Override
public Storage execute() {
return storageProvider.get();
} @Override
public void inject(MainActivity mMainActivity) {
mainActivityMembersInjector.injectMembers(mMainActivity);
} public static final class Builder {
private StorageModule storageModule;
private ScheduleModule scheduleModule; private Builder() {
} public StorageComponent build() {
if (storageModule == null) {
throw new IllegalStateException("storageModule must be set");
}
if (scheduleModule == null) {
this.scheduleModule = new ScheduleModule();
}
return new DaggerStorageComponent(this);
} public Builder storageModule(StorageModule storageModule) {
if (storageModule == null) {
throw new NullPointerException("storageModule");
}
this.storageModule = storageModule;
return this;
} public Builder scheduleModule(ScheduleModule scheduleModule) {
if (scheduleModule == null) {
throw new NullPointerException("scheduleModule");
}
this.scheduleModule = scheduleModule;
return this;
}
}
}

上面代码最后运行到MainActivity_MembersInjector.create(…)查看MainActivity_MembersInjector类:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<SharedPreferences> mPreferencesProvider;
private final Provider<Person> mPersonProvider; public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<SharedPreferences> mPreferencesProvider, Provider<Person> mPersonProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert mPreferencesProvider != null;
this.mPreferencesProvider = mPreferencesProvider;
assert mPersonProvider != null;
this.mPersonProvider = mPersonProvider;
} @Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mPreferences = mPreferencesProvider.get();//赋值
instance.mPerson = mPersonProvider.get();
} public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<SharedPreferences> mPreferencesProvider, Provider<Person> mPersonProvider) {
return new MainActivity_MembersInjector(supertypeInjector, mPreferencesProvider, mPersonProvider);
}
}

下来进入到了MainActivity 。在通过((MyApplication)this.getApplication()).getStorageComponent() 获取到component 后运行mStorageComponent.inject(this); 方法注入MainActivity,终于回调到上面代码中的injectMembers方法中。能够看出MainActivity中的成员变量所有初始完毕。之后就能够直接使用了。

5.Lazy 类

Lazy类是实现懒载入,调用的时候才创建实例,通过Lazy对象实现,得到对象的实例使用get()方法。比如:

public class Storage {

    private SharedPreferences mPreferences;
private Lazy<ScheduleImpl> mScheduleImpl;//Lazy 类
private final String KEY = "Dagger 2"; @Inject
public Storage(SharedPreferences mPreferences ,Lazy<ScheduleImpl> mScheduleImpl) {
this.mPreferences = mPreferences;
this.mScheduleImpl = mScheduleImpl;
} public void storage() {
mScheduleImpl.get().start();//get()方法
mPreferences.edit().putString(KEY, "Dagger 2 -- Example").commit();
mScheduleImpl.get().end();
} }

6.Scope

@Scope:注解作用域,通过自己定义注解限定对象的作用范围。它是JSR-330标准的一部分,事实上@Singleton就是一种@Scope

在Dagger 2中,@Scope被用于标记自己定义的scope注解。简单说它们能够相似单例地标记依赖。

被作注解的依赖会变成单例,可是这会与component的生命周期(不是整个应用)关联。

首先创建一个LoginScope:

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginScope {
}

Module:

@Module
public class LoginModule { @Provides
@LoginScope //<---这里为单例
Person providePerson() {
Person mPerson = new Person();
mPerson.setAge(23);
mPerson.setName("WeiLu");
return mPerson;
}
@Provides
Login provideLogin() {
Login mLogin = new Login();
mLogin.setPassword("######");
mLogin.setName("小关");
return mLogin;
}
}

Component:

@LoginScope
@Component(modules = {
LoginModule.class
})
public interface LoginComponent {
void inject(MyApplication myApplication);
}

调用:

mLoginComponent = DaggerLoginComponent.builder()
.loginModule(new LoginModule())
.build();
mLoginComponent.inject(this);

这里我们看一下生成代码:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerLoginComponent implements LoginComponent {
private Provider<Person> providePersonProvider;
private Provider<Login> provideLoginProvider;
private MembersInjector<MyApplication> myApplicationMembersInjector; private DaggerLoginComponent(Builder builder) {
assert builder != null;
initialize(builder);
} public static Builder builder() {
return new Builder();
} public static LoginComponent create() {
return builder().build();
} private void initialize(final Builder builder) {
this.providePersonProvider = ScopedProvider.create(LoginModule_ProvidePersonFactory.create(builder.loginModule));
this.provideLoginProvider = LoginModule_ProvideLoginFactory.create(builder.loginModule);
this.myApplicationMembersInjector = MyApplication_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), providePersonProvider, provideLoginProvider);
} @Override
public void inject(MyApplication myApplication) {
myApplicationMembersInjector.injectMembers(myApplication);
} public static final class Builder {
private LoginModule loginModule; private Builder() {
} public LoginComponent build() {
if (loginModule == null) {
this.loginModule = new LoginModule();
}
return new DaggerLoginComponent(this);
} public Builder loginModule(LoginModule loginModule) {
if (loginModule == null) {
throw new NullPointerException("loginModule");
}
this.loginModule = loginModule;
return this;
}
}
}

initialize方法:没有加@LoginScope 的Login类。那么他的创建是就是利用工厂模式new了一个Login。

相反加了@LoginScope 的Person类,是利用ScopedProvider 储存了起来。源代码例如以下:

public final class ScopedProvider<T> implements Provider<T> {
private static final Object UNINITIALIZED = new Object();
private final Factory<T> factory;
private volatile Object instance; private ScopedProvider(Factory<T> factory) {
this.instance = UNINITIALIZED; assert factory != null; this.factory = factory;
} public T get() {
Object result = this.instance;
if(result == UNINITIALIZED) {
synchronized(this) {
result = this.instance;
if(result == UNINITIALIZED) {
this.instance = result = this.factory.get();
}
}
} return result;
} public static <T> Provider<T> create(Factory<T> factory) {
if(factory == null) {
throw new NullPointerException();
} else {
return new ScopedProvider(factory);
}
}
}

7.Qualifier

@Qualifier:限定符,当类的类型不足以鉴别一个依赖的时候会使用到。假设我们没有去区分,会报错:xxx cannot be provided without an @Provides-annotated method。比如上面的Person类,我们如今准备返回两个:小明与小关。返回的都是Person类,怎么区分依赖?

首先自己定义一个@Qualifier

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface User {
}

下来是Module:

@Module
public class UserModule { @Provides
@User//加上这个自己定义注解用于区分
Login provideXiaoMingUser() {
Login xiaomin = new Login();
xiaomin.setPassword("******");
xiaomin.setName("小明");
return xiaomin;
}
@Provides
Login provideXiaoGuanUser() {
Login xiaoguan = new Login();
xiaoguan.setPassword("######");
xiaoguan.setName("小关");
return xiaoguan;
}
}

Component:

@Subcomponent(modules = {
UserModule.class
})
public interface UserComponent {
void inject(SecondActivity mSecondActivity);
}

这里用到了@Subcomponent,我们想复用组件时。能够使用它。以下是父组件用法。还有一种是注解属性加入dependencies。

@Singleton
@Component(
modules ={ AppModule.class
}
)
public interface AppComponent { Context getAppContext();
UserComponent createUserComponent(UserModule userModule);
}

这样的复用组件事实上是在在父组件中创建了子组件的内部类。例如以下:

@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerAppComponent implements AppComponent {
private Provider<Context> provideContextProvider; private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
} public static Builder builder() {
return new Builder();
} private void initialize(final Builder builder) {
this.provideContextProvider = ScopedProvider.create(AppModule_ProvideContextFactory.create(builder.appModule));
} @Override
public Context getAppContext() {
return provideContextProvider.get();
} @Override
public UserComponent createUserComponent(UserModule userModule) {
return new UserComponentImpl(userModule);
} public static final class Builder {
private AppModule appModule; private Builder() {
} public AppComponent build() {
if (appModule == null) {
throw new IllegalStateException("appModule must be set");
}
return new DaggerAppComponent(this);
} public Builder appModule(AppModule appModule) {
if (appModule == null) {
throw new NullPointerException("appModule");
}
this.appModule = appModule;
return this;
}
} private final class UserComponentImpl implements UserComponent {//内部类
private final UserModule userModule;
private Provider<Login> provideXiaoMingUserProvider;
private Provider<Login> provideXiaoGuanUserProvider;
private MembersInjector<SecondActivity> secondActivityMembersInjector; private UserComponentImpl(UserModule userModule) {
if (userModule == null) {
throw new NullPointerException();
}
this.userModule = userModule;
initialize();
} private void initialize() {
this.provideXiaoMingUserProvider = UserModule_ProvideXiaoMingUserFactory.create(userModule);
this.provideXiaoGuanUserProvider = UserModule_ProvideXiaoGuanUserFactory.create(userModule);
this.secondActivityMembersInjector = SecondActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideXiaoMingUserProvider, provideXiaoGuanUserProvider);
} @Override
public void inject(SecondActivity mSecondActivity) {
secondActivityMembersInjector.injectMembers(mSecondActivity);
}
}
}

初始化:(MyApplication中)

mAppComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
mUserComponent = mAppComponent.createUserComponent(new UserModule());

调用:

public class SecondActivity extends AppCompatActivity {

    UserComponent userComponent;

    @Inject
@User
Login xiaoming; @Inject
Login xiaoguan; @Bind(R.id.button4)
Button mButton4; @Bind(R.id.button5)
Button mButton5; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
ButterKnife.bind(this);
userComponent = ((MyApplication)this.getApplication()).getUserComponent();
userComponent.inject(this);
}
@OnClick({
R.id.button4,
R.id.button5,
})
void onButtonClicked(View v) {
switch (v.getId()) {
case R.id.button4:
Toast.makeText(this,
xiaoming.getName() + "----" + xiaoming.getPassword(),Toast.LENGTH_SHORT).show();
break;
case R.id.button5:
Toast.makeText(this,
xiaoguan.getName() + "----" + xiaoguan.getPassword(),Toast.LENGTH_SHORT).show();
break;
}
}
}

详细生成的代码。大家下载Demo后自行查看。

通过自己主动生成的代码能够看出Dagger 2主要用到了Builder模式、Factory模式。代码不难理解。同一时候由于Dagger 2没有使用反射,尽管效率提高了,可是缺乏灵活性。

这也是为了提高效率的代价。

3.Dagger2 练习Demo

Demo下载链接:Dagger2Example

4.參考

1.Dagger 2 API文档

2.Android Dagger2学习

3.使用Dagger 2依赖注入 - API

4.Dependency injection with Dagger 2 - Custom scopes


PS:最后说一下,关于Dagger2的学习成本还是挺高的。我自己也是从零開始接触。利用业余时间前前后后用了近一周时间去学习,一開始看的也是云里雾里。

事实上对比着自己主动生成的代码多看看就比較好理解了。有什么错误地方。希望多多交流。就这样。

。。

Dagger2使用攻略的更多相关文章

  1. 【C#代码实战】群蚁算法理论与实践全攻略——旅行商等路径优化问题的新方法

    若干年前读研的时候,学院有一个教授,专门做群蚁算法的,很厉害,偶尔了解了一点点.感觉也是生物智能的一个体现,和遗传算法.神经网络有异曲同工之妙.只不过当时没有实际需求学习,所以没去研究.最近有一个这样 ...

  2. 微软MVP攻略 (如何成为MVP?一个SQL Server MVP的经验之谈)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 初衷 什么是微软MVP? 成为微软MVP的条件? 如何成为微软MVP? (一) 申请时间划分 (二) 前期准备 (三) ...

  3. Windows下LATEX排版论文攻略—CTeX、JabRef使用介绍

    Windows下LATEX排版论文攻略—CTeX.JabRef使用介绍 一.工具介绍 TeX是一个很好排版工具,在学术界十分流行,特别是数学.物理学和计算机科学界. CTeX是TeX中的一个版本,指的 ...

  4. linux下安装apache与php;Apache+PHP+MySQL配置攻略

    1.apache   在如下页面下载apache的for Linux 的源码包    http://www.apache.org/dist/httpd/;   存至/home/xx目录,xx是自建文件 ...

  5. 生成 PDF 全攻略【2】在已有PDF上添加内容

    项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此 ...

  6. Java数组技巧攻略

      Java数组技巧攻略 0.  声明一个数组(Declare an array) String[] aArray = new String[5]; String[] bArray = {" ...

  7. BZOJ3252: 攻略

    Description 题目简述:树版[k取方格数]   众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>,这款游戏有n个场景 ...

  8. [经验] Win7减肥攻略(删文件不删功能、简化优化系统不简优化性能)

    [经验] Win7减肥攻略(删文件不删功能.简化优化系统不简优化性能) ☆心梦无痕☆ 发表于 2014-1-24 11:15:04 https://www.itsk.com/thread-316471 ...

  9. 从小工到专家 ——读《Java程序员职场全攻略》有感

    从小工到专家 ——读<Java程序员职场全攻略>有感   <Java程序员职场全攻略>是以故事的形式,向读者介绍Java程序员的职场经验.作者牛开复在北京从事软件开发,已经是一 ...

随机推荐

  1. Comet反向ajax技术实现客服聊天系统

    说明:Comet反向Ajax是在看了燕十八老师的视频以后,结合他讲解的例子,自己用ajax+java实现了一遍.在这里把代码贴出来,以供大家学习.同时,ajax轮询技术也可以用在消息推送的功能中,下次 ...

  2. Spring boot -环境搭建 ,初步接触(1)

    1. Eclipse 创建 maven project  项目目录如下: 2. pom.xml  配置文件 <project xmlns="http://maven.apache.or ...

  3. 算法之dfs篇

    dfs算法是深度搜索算法.从某一节点开始遍历直至到路径底部,如果不是所寻找的,则回溯到上个节点后,再遍历其他路径.不断重复这个过程.一般此过程消耗很大,需要一些优化才能保持算法的高效. hdu1010 ...

  4. js 图片轮播代码编辑

    图片轮播,将几张图片统一放在展示平台 banner上,通过banner移动将图片轮流播放. <script>// 取对象 var btn_l = document.getElementsB ...

  5. C#多线程方法 可传参

    //将线程执行的方法和参数都封装到一个类里面.通过实例化该类,方法就可以调用属性来实现间接的类型安全地传递参数.using System; using System.Threading; //Thre ...

  6. SLAM: SLAM的发展历程(WIKI)

    参考维基百科: https://en.wikipedia.org/wiki/Simultaneous_localization_and_mapping 你们叫他SLAM,我还是习惯叫他三维重建.... ...

  7. HDU_5690_快速幂,同余的性质

    All X Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/Others) Problem D ...

  8. matlab学习GUI可调的界面窗口

    创建一个GUI界面,在此依然利用GUI_01的窗口来演示 发现它的最大化窗口不可调 在GUI绘制中,工具--->选择GUI选项---->选择第二个成比例 再运行就可以调控大小了

  9. eas之编辑界面中分录默认携带的标题栏

    this.kdtEntrys_detailPanel.setTitle("物件内容");   KDContainer kdtEntrys_Container = (KDContai ...

  10. HDU 2267 How Many People Can Survive(广搜,简单)

    题目 //一道简单的广搜水题 #include<queue> #include<stdio.h> #include<string.h> #include<al ...