反射机制及开源框架xUitls的使用,使用HttpUtils通过断点续传下载文件
反射:
Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性
Java反射机制主要提供下面几种用途:
1•在运行时判断任意一个对象所属的类
2•在运行时构造任意一个类的对象
3•在运行时判断任意一个类所具有的成员变量和方法
4•在运行时调用任意一个对象的方法
第一步 得到某个类的class对象,有三种方式;
方式一: Class<Student> class1 = Student.class;
方式二: Class class2 = Class.forName("包名");
方式三: Student student = new Student();
Class class3 = student.getClass();
然后我们就可以对类中的方法属性进行操作了..
访问类中的属性了,属性包括了私有和公有的属性
Field fields[] = class1.getDeclaredFields(); for (Field field : fields) { System.out.println(field); }
通过反射创建对象
//1.得到无参构造方法 Constructor<Student> constructor = class1.getConstructor(); //2.创建对象 Student stu = constructor.newInstance(); //等价于Student stu = new Student();
调用set方法设置数据
Method method = class1.getDeclaredMethod("setName", new Class[]{String.class}); //私有方法需要设置权限 method.setAccessible(true); //2.通过之前的student对象调用setName表示的方法 method.invoke(stu, new Object[]{"张三"});
通过Get方法得到数据
Method getName = class1.getDeclaredMethod("getName", new Class[]{}); //通过之前的student对象调用getName表示的方法 Object object = getName.invoke(stu, new Object[]{}); System.out.println(object);
第三方框架XUitls的使用:
下载XUils 地址:https://github.com/wyouflf/xUtils
导入项目,将jar包复制到当前工程下的libs目录下---点击该jar包-右键--As a Library --ok
- xUtils 包含了很多实用的android工具。
- xUtils 支持大文件上传,更全面的http请求协议支持(10种谓词),拥有更加灵活的ORM,更多的事件注解支持且不受混淆影响...
- xUitls 最低兼容android 2.2 (api level 8)
目前xUtils主要有四大模块:
-
DbUtils模块:
- android中的orm框架,一行代码就可以进行增删改查;
- 支持事务,默认关闭;
- 可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);
- 支持绑定外键,保存实体时外键关联实体自动保存或更新;
- 自动加载外键关联实体,支持延时加载;
- 支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。
-
ViewUtils模块:
- android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;
- 新的事件绑定方式,使用混淆工具混淆后仍可正常工作;
- 目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。
-
HttpUtils模块:
- 支持同步,异步方式的请求;
- 支持大文件上传,上传大文件不会oom;
- 支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;
- 下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;
- 返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。
-
BitmapUtils模块:
- 加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;
- 支持加载网络图片和本地图片;
- 内存管理使用lru算法,更好的管理bitmap内存;
- 可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等...
-
使用xUtils快速开发框架需要有以下权限:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
ViewUtils使用方法
API:http://xutilsapi.oschina.mopaas.com/
- 完全注解方式就可以进行UI绑定和事件绑定。
-
无需findViewById和setClickListener等。
注解:从原理上讲,注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理。
首先需要在activity中注入:(否则控件,资源,,注入没用)
//在Activity中注入: @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); ViewUtils.inject(this); //注入view和事件 ... textView.setText("some text...");
注入布局:相当于setContentView(R.layout.activity_main);
@ContentView(R.layout.activity_main) public class MainActivity extends AppCompatActivity {
注入控件 等价于 findVIewById(R.id.tv_text)
@ViewInject(R.id.tv_text) private TextView tvText;
注入数据资源
//id表示资源的id type表示资源的数据类型,String,demens.color,drawable,animation...
@ResInject(id = R.string.hello,type = ResType.String) private String hello;
注入点击事件:方法名可以任意,但是参数必须与原始的参数一致
// 取消了之前使用方法名绑定事件的方式,使用id绑定不受混淆影响,方法名可以自定义
// 支持绑定多个id @OnClick({R.id.id1, R.id.id2, R.id.id3})
// or @OnClick(value={R.id.id1, R.id.id2, R.id.id3}, parentId={R.id.pid1, R.id.pid2, R.id.pid3})
@OnClick(R.id.btn01) public void onButtonClick(View view){ Toast.makeText(this,"点击了btn01",Toast.LENGTH_SHORT).show(); }
!!!使用碎片可以进行碎片注入,注入碎片后方可对其中的控件进行注入操作
在Fragment中注入:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.bitmap_fragment, container, false); // 加载fragment布局 ViewUtils.inject(this, view); //注入view和事件 ... }
BitmapUtils使用方法
首先我们需要创建一个BitmapUtils对象,一个活动只需要创建一个,因此我们设置在MyApplication中,注意需要在清单文件中注册
public class MyApplication extends Application { private static BitmapUtils bitmapUtils; @Override public void onCreate() { super.onCreate(); //创建对象 bitmapUtils = new BitmapUtils(getApplicationContext()); } public static BitmapUtils getBitmapUtils(){ return bitmapUtils; } }
这里将该对象进行了封装,活动只需要调用MyApplication的getBitmapUtils方法就可以得到该对象了,主活动的onCreate方法中注入actiivity和得到bitmapUtils对象
ViewUtils.inject(this);//注入view和事件 bitmapUtils = MyApplication.getBitmapUtils();
加载本地图片(路径以/开头, 绝对路径):需要加入权限(android.permission.WRITE_EXTERNAL_STORAGE)
@OnClick(R.id.btn_file) public void onClickSDCard(View view){ //参数一:要设置图片的图片控件 bitmapUtils.display(image,"/mnt/sdcard/img/a.jpg");
加载assets中的图片(路径以assets开头)
@OnClick(R.id.btn_assert) public void onClickAssets(View view){ bitmapUtils.display(image,"assets/a.jpg"); }
加载网络图片:(需要加入权限android.permission.INTERNET)
显示图片到指定控件,如果是ImageView,会调用setImageBitmap(bitmap);其他控件使用setBackgroundDrawable(drawable)
方式一:
container - 控件View
uri - 本地文件完整路径,assets文件路径(assets/xxx),或者URL地址
itmapUtils.display(image,"http://p1.so.qhmsg.com/t01e63fec232667f916.jpg");
方式二:
参数:
container - 控件View
uri - 本地文件完整路径,assets文件路径(assets/xxx),或者URL地址
displayConfig - 图片显示配置项BitmapDisplayConfig
BitmapDisplayConfig bitmapDisplayConfig = new BitmapDisplayConfig();//创建图片显示配置项对象 //设置最大尺寸 bitmapDisplayConfig.setBitmapMaxSize(new BitmapSize(200,200)); //设置动画 ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 1, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); scaleAnimation.setDuration(2000); scaleAnimation.setRepeatCount(1); scaleAnimation.setFillAfter(true); bitmapDisplayConfig.setAnimation(scaleAnimation); // bitmapUtils.display(image,"http://p1.so.qhmsg.com/t01e63fec232667f916.jpg",bitmapDisplayConfig);
方式三:
//该方法设置动画效果没用
参数:
container - 控件View
uri - 本地文件完整路径,assets文件路径(assets/xxx),或者URL地址
callBack - 图片加载回调接口BitmapLoadCallBack*/
bitmapUtils.display(image, "http://p1.so.qhmsg.com/t01e63fec232667f916.jpg", new BitmapLoadCallBack<ImageView>() { //加载图片回调监听 @Override public void onLoadCompleted(ImageView imageView, String s, Bitmap bitmap, BitmapDisplayConfig bitmapDisplayConfig, BitmapLoadFrom bitmapLoadFrom) { //设置回调后的图片 imageView.setImageBitmap(bitmap); } //加载失败 @Override public void onLoadFailed(ImageView imageView, String s, Drawable drawable) { } });
方式四:
//该方法设置动画效果没用
参数:container - 控件View
uri - 本地文件完整路径,assets文件路径(assets/xxx),或者URL地址
displayConfig - 图片显示配置项BitmapDisplayConfig
callBack - 图片加载回调接口BitmapLoadCallBack
bitmapUtils.display(image, "http://p1.so.qhmsg.com/t01e63fec232667f916.jpg", bitmapDisplayConfig, new BitmapLoadCallBack<ImageView>() { @Override public void onLoadCompleted(ImageView imageView, String s, Bitmap bitmap, BitmapDisplayConfig bitmapDisplayConfig, BitmapLoadFrom bitmapLoadFrom) { imageView.setImageBitmap(bitmap); } @Override public void onLoadFailed(ImageView imageView, String s, Drawable drawable) { } });
DBUtils使用方法
创建数据库:
参数:
context - android.content.Context
dbDir - 数据库文件存储路径
dbName - 数据库文件名
dbVersion - 数据库版本号
dbUpgradeListener - 数据库版本升级通知接口
返回:
DbUtils实例DbUtils
dbUtils = DbUtils.create(this, getCacheDir().getAbsolutePath(), "dbUtils.db",1, this)
这里由于该类实现了DbUtils.DbUpgradeListener,实现了其中的方法,所以最后一个参数传入this
实现的方法
/** * 更新数据库 * @param dbUtils * @param i 旧版本 * @param i1 新版本 */ @Override public void onUpgrade(DbUtils dbUtils, int i, int i1) { Log.i("tag","onUpgrade--i--"+i+"--i1--"+i1); dbUtils = DbUtils.create(this, getCacheDir().getAbsolutePath(), "dbUtils.db",2, this); }
创建表:
* 创建表 * @param v */ @OnClick(R.id.btn_createTab) public void onCreateTable(View v){ //创建数据库表,当表不存在时 //entityType - 实体类类型Class try { dbUtils.createTableIfNotExist(Student.class);
简单的增删改查方法:
增:
保存实体到DB(insert)
根据实体类注解,自动创建表;
只持久化基本数据类型、java.lang.*等,不能处理的类型自动忽略;
对静态属性、添加忽略注解属性自动忽略。
插入一条数据:
Student student = new Student(); student.setAge(19); student.setName("张三"); student.setSex("男"); //插入一条数据 dbUtils.save(student);
插入多条数据:
//插入多条数据,当有一条数据出错时,后面的数据不会再进行插入操作 List<Student>dataList = new ArrayList<>(); for (int i = 0; i < 20; i++) { Student student = new Student(); student.setName("alice"+(i+1)); student.setAge((i+19)); if(i % 2 == 0) { student.setSex("男"); }else{ student.setSex("女"); } dataList.add(student); } dbUtils.saveAll(dataList);
删:
//删除id>85,age>22的数据 dbUtils.delete(Student.class,WhereBuilder.b("_id",">","85").and("age",">","22"));
改:
//更新_id>40的数据为贝塔,1000,女 List<Student> list = dbUtils.findAll(Selector.from(Student.class).where(WhereBuilder.b("_id",">","40"))); for (int i = 0; i < list.size(); i++) { Student s = list.get(i); s.setAge(1000); s.setName("贝塔"); s.setSex("女"); // updateColumnNames为空时,更新所有字段的值 //entity - 实体类实例 updateColumnNames -String..可变参数 需要更新的字段名, dbUtils.update(s,"age","name","sex");
//更新所有_id<10的名字
dbUtils.update(s,WhereBuilder.b("_id","<","10"),"name");
查:
//查询所有数据 List<Student> list = dbUtils.findAll(Student.class);
//查询1
List<DbModel> dbModelAll = dbUtils.findDbModelAll(DbModelSelector.
from(Student.class). //表示从那个表查询
select("_id", "name", "sex", "age"). //表示查询的字段
where("age", "<", "22")); //表示查询条件*/
//查询所有_id<10的数据
// List<Student> list = dbUtils.findAll(Selector.from(Student.class).where("_id", "<", "10"));
实体类:
/** * 创建表 * */ //指定表名 @Table(name = "Student") public class Student { //指定列名 @Column(column = "_id") //指定是主键 @Id(column = "_id") private int _id; @Column(column = "name") private String name; @Column(column = "age") //限制条件 年龄大于18 @Check("age > 18 ") private int age; //性别必须为男或者女 @Column(column = "sex") @Check("sex in ('男','女')") private String sex; public int get_id() { return _id; } public void set_id(int _id) { this._id = _id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
HttpUtils使用
httpUtils仅仅支持安卓6.0以下应用,因为里面使用的都是HttpClient的网络请求方式,而google公司已经将其弃用.
普通Get方法:
//声名httputils工具 HttpUtils httpUtils = new HttpUtils(); //发送请求 httpUtils.send(HttpRequest.HttpMethod.GET, pathGet, new RequestCallBack<String>() { //*请求成功的回调*//* @Override public void onSuccess(ResponseInfo<String> responseInfo) { //获取数据 String string = responseInfo.result; Log.i("AAA",string); Log.i("AAA","ThreadName:-" + Thread.currentThread().getName() + "-threadId-" + Thread.currentThread().getId()); } @Override public void onFailure(HttpException e, String s) { } }); }
post方法:
HttpUtils httpUtils = new HttpUtils(); //post提交的字段:pageNo=1&pageSize=20&serialIds=2143,3404&v=4.0.0 // String pathPost = "http://mrobot.pcauto.com.cn/v2/cms/channels/1?"; RequestParams requestParams = new RequestParams(); //设置post请求参数 requestParams.addBodyParameter("pageNo", "1"); requestParams.addBodyParameter("pageSize", "20"); requestParams.addBodyParameter("serialIds", "2143,3404"); requestParams.addBodyParameter("v", "4.0.0"); /* com.lidroid.xutils.http.client.HttpRequest.HttpMethod method, 请求类型 Get,Post.. @NotNull java.lang.String url, 网络地址 com.lidroid.xutils.http.RequestParams params, 请求参数 com.lidroid.xutils.http.callback.RequestCallBack<T> callBack 请求成功的回调 httpUtils.send()*/ httpUtils.send(HttpRequest.HttpMethod.POST, pathPost, requestParams, new RequestCallBack<String>() { @Override public void onSuccess(ResponseInfo<String> responseInfo) { Log.i("AAA", "onSuccess: " + responseInfo.result); } @Override public void onFailure(HttpException e, String s) { } }); }
-
使用HttpUtils下载文件:(需加入网络权限,写入sd卡的权限)
- 支持断点续传,随时停止下载任务,开始任务
- 注意:回调的方法在主线程中执行
@ContentView(R.layout.activity_main) public class MainActivity extends Activity { @ViewInject(R.id.tvText) private TextView tvText; private String pathApk = "http://down.72g.com/upload/app/201407/201407150923238621.apk"; private ProgressDialog progressDialog; private HttpHandler<File> httpHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //注入activity ViewUtils.inject(this); //初始化对话框 initProgressDialog(); } /*初始化对话框*/ private void initProgressDialog() { //创建进度条对话框 progressDialog = new ProgressDialog(this); //设置标题 progressDialog.setTitle("下载文件"); //设置信息 progressDialog.setMessage("玩命下载中..."); //设置显示的格式 progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //设置按钮 progressDialog.setButton(ProgressDialog.BUTTON_NEGATIVE, "暂停",new DialogInterface.OnClickListener(){ @Override public void onClick(DialogInterface dialog, int which) { //点击取消正在下载的操作,再次触发点击事件时,会重新创建httpHandler对象,但会从暂停的地方继续下载,从而实现了断点续传的操作 httpHandler.cancel(); }}); } @OnClick(R.id.btn_download) public void onClickDownLoadFile(View view){ //声明httpUtils工具 HttpUtils httpUtils = new HttpUtils(); //存储的路径 String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/app3.apk";
//下载 httpHandler = httpUtils.download(pathApk,//文件地址
path,//文件下载的目标目录
true,// 如果目标文件存在,接着未完成的部分继续下载。服务器不支持RANGE时将从新下载。
true,// 如果从请求返回信息中获取到文件名,下载完成后自动重命名
new RequestCallBack<File>() {//下载的回调,在主线程中运行
/*执行下载操作之前调用*/ @Override public void onStart() { super.onStart(); //显示对话框 progressDialog.show(); } /*正在下载的时候调用*/ @Override public void onLoading(long total, long current, boolean isUploading) { super.onLoading(total, current, isUploading); // Log.i("tag", "线程--"+Thread.currentThread().getName()); // Log.i("tag", "current--total--"+current+"--"+total); //设置进度 progressDialog.setProgress((int)(current*100/total)); } /*请求成功的时候调用*/ @Override public void onSuccess(ResponseInfo<File> responseInfo) { progressDialog.dismiss(); Log.i("tag","下载成功"); //获得下载后的文件 File file = responseInfo.result; InstallApkUtils.inStallApk(MainActivity.this, file); } /*请求失败的时候调用*/ @Override public void onFailure(HttpException error, String msg) { Log.i("tag", "下载失败"); progressDialog.dismiss(); } /*取消的时候调用*/ @Override public void onCancelled() { super.onCancelled(); Log.i("tag","取消下载"); } }); } }
安装apk的工具类:
public static void inStallApk(Context context,File file){ Intent intent = new Intent(); //隐式意图激活安装 apk 的activity intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); context.startActivity(intent); }
效果: