当前位置: 首页 > 工具软件 > dhroid > 使用案例 >

快速开发框架dhroid的使用

邵沛
2023-12-01

由于dhroid已经一年多没更新了,所以有些地方用的不是最新的API,大家慢慢去了解吧。

基本配置

将框架引入项目有三种方式
1. 引入jar包(切换到Project目录,将jar包放到app\libs下)
2. 引入源码(进入到项目文件夹目录,将代码拷贝到app\src\main\java下)
3. 此项目没发布到Maven,就不说了。

此时项目是编译不通过的,需要引入Universal Image Loader作为图片加载库,引入Gson作为解析json数据库,引入httpmime.jar为网络部分做支持。

首先,在dhroid根目录下有两个类Const.javaDhroid.java,作为配置类。

public class Const {
    // 打印日志
    public static boolean logable = true;
    // 打印日志时打印行号
    public static boolean logline = true;
    // 网络框架中拦截异常,上线时打开
    public static boolean net_error_try = false;
    // 自动注入
    public static boolean auto_inject = true;
    // 数据库版本号
    public static int DATABASE_VERSION = 1;
    //adapter 的分页相关,弃用,后面会说明
    public static String netadapter_page_no = "page";
    public static String netadapter_step = "step";
    public static Integer netadapter_step_default = 20;
    public static String netadapter_timeline = "timeline";
    public static String netadapter_json_timeline = "id";
    public static String netadapter_no_more = "已经没有了";

    public static String[] ioc_instal_pkg = null;

    //图片缓存相关
    public static String image_cache_dir = "dhcache";// 缓存目录
    public static int image_cache_num = 12;// 缓存数量
    public static Boolean image_cache_is_in_sd = false;
    public static long image_cache_time = 100000l;

    //网络访问返回数据的格式定义,需要结合后台返回数据格式去做更改
    public static String response_success = "success";
    public static String response_msg = "msg";
    public static String response_data = "data";
    public static String response_code = "code";
    public static int net_pool_size = 10;
}
/**
 * 完成一些系统的初始化的工作
 * @author Administrator
 */
public class Dhroid {
    public static void init(Application app) {
        Ioc.initApplication(app);
        //对话框的配置
        Ioc.bind(DialogImpl.class).to(IDialog.class).scope(InstanceScope.SCOPE_PROTOTYPE);
        // 配置ImageLoader
        ImageLoaderConfiguration imageconfig = new ImageLoaderConfiguration.Builder(
                app.getApplicationContext())
                .threadPoolSize(3)
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .memoryCacheSize(1500000)
                .denyCacheImageMultipleSizesInMemory()
                .discCacheFileNameGenerator(new Md5FileNameGenerator())// 缓存数据md5加密
                .build();
        ImageLoader.getInstance().init(imageconfig);
        //数据库初始化
        DhDB db = IocContainer.getShare().get(DhDB.class);
        db.init("dhdbname", Const.DATABASE_VERSION);// 初始化数据库名和版本
    }
}

首先重写一个Application,配置到AndroidManifest.xml

<application
        android:name=".MyApplication"
        ...
        >
</application>
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // 调用Dhroid的初始化方法,完成注解,图片,数据库等的初始化
        Dhroid.init(this);
    }
}

额外配置请看DemoApplication.java

新建MainActivity.java继承net.duohuo.dhroid.activity.BaseActivity
BaseActivity.java中有如下关键代码

// 内部用ArrayList控制Activity完全退出,切换到某Activity等方法
private ActivityTack tack = ActivityTack.getInstanse();
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    tack.addActivity(this);
}
@Override
public void finish() {
    super.finish();
    tack.removeActivity(this);
}
@Override
public void setContentView(int layoutResID) {
    super.setContentView(layoutResID);
    if (Const.auto_inject) {
        InjectUtil.inject(this);// 注解导入
    }
}

以后可以在这个基类中添加更多共用的代码


先来测试注解导入功能

在布局activity_main.xml中加入一个Button,在MainActivity.java中加入下面代码

@InjectView(id = R.id.button)
Button button;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(MainActivity.this, "注解导入成功了,再也不用findViewById()了", Toast.LENGTH_SHORT).show();
        }
    });
}

有些人就该问了,这个button没有初始化,直接用的话不会包空指针么?

答案是,不会。因为在声明button时在它上面加了一行注释@InjectView(id = R.id.button),这句话的意思就是将这个button指向setContentView(layoutId)中传入的布局中的id为button的节点,完成初始化。

现在把Activity中的findViewById省略了,但还是要写setOnClickListener,能不能用注解也完成呢,看下面代码

@InjectView(id = R.id.button, click = "clickBtn")
Button button;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void clickBtn(View view){
    Toast.makeText(MainActivity.this, "注解导入成功了, 不用写setOnClickListener了~", Toast.LENGTH_SHORT).show();
}

这里要注意,方法要用public修饰,需要一个View作为参数

其他用法看这里 基础高级


再来看看网络部分

常用的有两个类DhNet.javaNetTask.java

// 这里借用知乎日报的一个接口测试一下~
DhNet dhNet = new DhNet("http://news-at.zhihu.com/api/4/themes");
//        dhNet.addParam("key", "value");
NetTask task = new NetTask(this) {
    @Override
    public void doInUI(Response response, Integer transfer) {
        // 请求成功
        Log.d("response", response.result);
    }

    @Override
    public void onErray(Response response) {
        // 请求失败
        Log.d("onErray", response.msg);
    }
};

dhNet.doGet(task);
//  dhNet.doGetInDialog(task);    //网络请求时显示一个Dialog
//  dhNet.doPost(task);           //使用post请求

要注意添加权限

<!-- 网络使用权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 检查网络状态的权限 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

处理接口返回的数据时

@Override
public void doInUI(Response response, Integer transfer) {
    // 请求成功
    //Log.d("response", response.result);
    try {
        JSONObject jsonObject = new JSONObject(response.result);
        JSONArray jsonArray = jsonObject.getJSONArray("others");

        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject other = jsonArray.getJSONObject(i);
            String name = other.getString("name");
            Log.d("name", name);
        }

    } catch (JSONException e) {
        e.printStackTrace();
    }
}

OK,日志已经能够打出来了

12-22 18:40:11.136 11009-11009/gavinhua.demo D/name: 日常心理学
12-22 18:40:11.136 11009-11009/gavinhua.demo D/name: 用户推荐日报
12-22 18:40:11.136 11009-11009/gavinhua.demo D/name: 电影日报
...

但是这么解析数据时不是感觉很累?
这里引入一个解析库Gson

Gson gson = new Gson();
ThemeEntity themeEntity = gson.fromJson(response.result, ThemeEntity.class);
Log.d("themes", themeEntity.toString());

ThemeEntity 类似根据JSON生成的POJO类,用于保存数据。

12-22 20:14:33.219 21534-21534/gavinhua.demo D/themes: ThemeEntity{limit=1000,
 subscribed=[], others=[OthersEntity{color=15007, thumbnail='http://pic3.zhimg.
 com/0e71e90fd6be47630399d63c58beebfc.jpg', description='了解自己和别人,了解彼此的
...

这么简单的几行代码,就已经把数据保存好了,是一件多么快乐的事情~


接下来是持久化数据

主要分为两种:

  • SharedPreferences适用于少量的数据,例如设置类数据,用户账户信息等。接受的格式为key-value,保存格式为XML。
  • SQLiteAndroid内置的数据库,用于保存大量数据,或者不易于处理的数据。

在dhroid中提供了这两个方式的封装方法,便于开发。DhDBPerference

首先来看数据库的使用。

for (int i = 0; i < 2; i++) {
    UserEntity userEntity = new UserEntity();
    userEntity.setUsername("admin" + i);
    userEntity.setPassword("1234");
    userEntity.setSex(0);
    dhDB.save(userEntity);// 增加
}

List<UserEntity> list = dhDB.queryAll(UserEntity.class);// 查询
Log.d("list", list.toString());

UserEntity admin1 = dhDB.queryFrist(UserEntity.class, "username = ?", "admin1");// 条件查询
Log.d("admin1", admin1.toString());

admin1.setUsername("change name");
dhDB.update(admin1);// 更新
list = dhDB.queryAll(UserEntity.class);
Log.d("list", list.toString());

dhDB.delete(admin1);// 删除
list = dhDB.queryAll(UserEntity.class);
Log.d("list", list.toString());
// 增加
12-23 10:55:10.723 12438-12438/gavinhua.demo D/list: [UserEntity{username='admin0', password='1234', sex=0}, 
UserEntity{username='admin1', password='1234', sex=0}]
// 条件查询
12-23 10:55:10.729 12438-12438/gavinhua.demo D/admin1: UserEntity{username='admin1', password='1234', sex=0}
// 修改
12-23 10:55:10.756 12438-12438/gavinhua.demo D/list: [UserEntity{username='admin0', password='1234', sex=0}, 
UserEntity{username='change name', password='1234', sex=0}]
// 删除
12-23 10:55:10.775 12438-12438/gavinhua.demo D/list: [UserEntity{username='admin0', password='1234', sex=0}]

是不是很简单,但是需要配置UserEntity.java

@Entity(table = "user") // 表名
public class UserEntity {
    @Column(pk = true, auto = true) // 主键,自动
    public long id;
    @Column // 标注是要存到库中
    public String username;
    @Column
    public String password;
    @Column
    public int sex;
...

下面来看Perference

public class UserPerference extends Perference{
    public UserEntity userEntity;// 必须用public修饰
    public String type;
    public boolean isActive;
}
UserEntity entity = new UserEntity();
entity.setUsername("admin");
entity.setSex(0);
entity.setPassword("123");

UserPerference user = new UserPerference();
user.account = "110";// 这组数据的标识
user.isActive = true;
user.type = "1";
user.userEntity = entity;
user.commit();// 提交修改

UserPerference per = new UserPerference();
per.load();
Log.d("perference", per.toString());       

来看一下log

12-23 15:45:13.445 4508-4508/gavinhua.demo D/perference: UserPerference{userEntity=UserEntity{username='admin', password='123', sex=0}, type='1', isActive=true}

Perference的局限性很大,所以不推荐使用。


EventBus 事件总线

这个EventBus和greenrobot家的EventBus可不是一个,不要弄混了。

public static final String NAME = "clickBtn"; // 事件标识

@InjectView(id = R.id.button, click = "clickBtn")
Button button;

@Inject // 使用这个注解,保持单例
EventBus bus;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

public void clickBtn(View view) {
    bus.fireEvent(NAME);// 发送事件
}

@OnEvent(name = NAME) // 将这个方法与事件标识绑定
public void anyWay() { //方法名随便起
    Toast.makeText(MainActivity.this, "被点击了", Toast.LENGTH_SHORT).show();
}

@Override
protected void onResume() {
    super.onResume();
    EventInjectUtil.inject(this);// 将方法注册上
}

@Override
protected void onPause() {
    super.onPause();
    EventInjectUtil.unInject(this);// 反注册
}

EventBus根据事件辨识去找处理事件的方法。这么一看是不是觉得没什么作用?但是它能跨Activity、Service等等处理事件呢?一下子就将模块间的通信变得简单了,降低了耦合性。

进阶用法

public void clickBtn(View view) {
    bus.fireEvent(NAME, "点击按钮~");
}

@OnEvent(name = NAME ,onBefore = true, ui = true) // onBefore可以收到注册事件之间的消息,ui在主线程处理事件
public void anyWay(String str) { // 可以根据参数对同一标识做不同处理
    bus.clearEvents(NAME); // 取消事件向下传递
    Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
}

@OnEvent(name = NAME)
public void anyWay() {
    Toast.makeText(MainActivity.this, "被点击了", Toast.LENGTH_SHORT).show();
}

更多进阶用法看 这里


总结

dhroid框架已经有点过时了,比如网络部分不能加header、不支持gzip、要求权限过多、不支持Android M的新的权限模型等等。
但是还是有值得学习的地方。更多的文档看 这里

 类似资料: