安卓高效框架简单使用
来源:互联网 发布:手机能用淘宝助理吗 编辑:程序博客网 时间:2024/05/21 05:05
安卓高效框架
Rx系列
RxAndroid
本文使用的是RxAndroid 2.0.1,Rx2.xx和Rx1.xx有较大的区别,此处只讨论2.xx
Rx牛逼的异步响应式框架,这里只是个人的学习记录,可能有些地方有误,仅供参考。
如果想深入了解请移步到官网,或者是中文翻译的官网
学习地址:
https://gold.xitu.io/entry/5884374e570c350062c1ac3b
https://gank.io/post/560e15be2dca930e00da1083
Rx实现原理个人以为可简单理解为一个事件发出者和一个事件接收者,两者之间通过订阅建立联系,事件发出和事件接收处理都可以在不同的线程,框架默认是在主线程中做所有的事,所以如果有耗时任务,请务必使用相应的线程切换方法进行切换。
配置Rx2.0:
compile ‘io.reactivex.rxjava2:rxandroid:2.0.1’
如果要使用retrofit网络加载框架,则需添加以下依赖:
compile ‘com.squareup.retrofit2:retrofit:2.1.0’
compile ‘com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0’
compile ‘com.squareup.retrofit2:converter-gson:2.0.1’
使用RxAndroid:
Observable:
Observable的创建方法很多,列举如下:
- Create — 常规创建方式,事件的产生需要自己实现(调用onNext)
- Defer — 不会立即创建一个Observable,只有调用subscribe时才会创建,而且会为每一个订阅者创建一个新的Observable(事件可以被多个订阅者订阅)
- Empty/Never/Throw — create Observables that have very precise and limited behavior,不知道搞什么的~
- fromIterable — 从一个可以迭代的集合中产生事件
- fromArray — 从一个数组中产生
- Interval — 按一定的时间间隔发送相同事件
- Just — 传递一个数值集合,可以是数组和集合或者多个单一元素
- Range — 传递一个数值范围,然后框架会产生范围之间的所有数值
- Repeat — 重复发送某个相同的事件
- Start — create an Observable that emits the return value of a function
- Timer — create an Observable that emits a single item after a given delay
常规使用:
//创建一个ObservableObservable.create(new ObservableOnSubscribe<Integer>() { //在该方法中产生事件,并调用Emitter发射事件 @Override public void subscribe(ObservableEmitter<Integer> e) throws Exception { //一般使用onNext产生事件交给下游处理 e.onNext(1); SystemClock.sleep(5000); e.onNext(2); SystemClock.sleep(5000); e.onNext(3); //此处的onComplete表示事件已经发送完成,下游不需要再处理了,应该在事件产生完成时调用一下onComplete e.onComplete(); } }) //订阅在io线程,意思是上面的subscribe的事件产生在哪个线程,subscribeOn一般只会调用一次 //newThread() 总是在新的线程中执行 //computation 主要用于CPU密集型任务 //io 主要用于网络访问,文件处理 //immediate() 在当前线程立即开始执行任务 .subscribeOn(Schedulers.io()) //观察在哪个线程,也不知道是不是这个意思 //observeOn可以随便切换,表示接下来的操作在observeOn设定的线程执行,切换线程的灵魂所在 .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { Toast.makeText(mContext, "开始", Toast.LENGTH_SHORT).show(); } @Override public void onNext(Integer value) { tv.setText("" + value); } @Override public void onError(Throwable e) { } @Override public void onComplete() { Toast.makeText(mContext, "完成", Toast.LENGTH_SHORT).show(); } }); //subscribeOn会产生Disposable,这个Disposable是用于取消订阅事件,防止内存泄漏, //使用该框架请注意在OnDestroy方法或者其他合适的方法中调用Disposable对象的 if(dis != null && (!dis.isDisposed())) { dis.dispose(); }
使用Flowable
Flowable(处理背压问题,observable不具备了,所谓背压就是当生产速度大于消费速度时的一种处理策略,比如快速点击事件)
Flowable<String> flow = Flowable.create(new FlowableOnSubscribe<String>() { @Override public void subscribe(FlowableEmitter<String> e) throws Exception { e.onNext("hello rx"); e.onComplete(); } }, BackpressureStrategy.BUFFER); Subscriber<String> sub = new Subscriber<String>() { @Override public void onSubscribe(Subscription s) { Log.e("s", "订阅开始..."); s.request(Long.MAX_VALUE); } @Override public void onNext(String s) { Toast.makeText(RxActivity.this, s, Toast.LENGTH_SHORT).show(); } @Override public void onError(Throwable t) { Toast.makeText(RxActivity.this, "error", Toast.LENGTH_SHORT).show(); } @Override public void onComplete() { Toast.makeText(RxActivity.this, "完成", Toast.LENGTH_SHORT).show(); } }; flow.subscribe(sub);
使用Subject
Subject既可以发事件又可以处理事件
Subject subject = PublishSubject.create();subject.observeOn(EventThread.getScheduler(thread)) .subscribe(o -> { try { if (valid) { handleEvent(o); } } catch (InvocationTargetException e) { throwRuntimeException("Could not dispatch event: " + o.getClass() + " to subscriber " + SubscriberEvent.this, e); }});
RxBus
github:https://github.com/AndroidKnife/RxBus
注意该项目是使用的RxJava1.xx,如果项目中使用RxJava2.xx会出现Rx版本冲突而无法通过编译,个人解决方法是复制了RxBus的代码到项目中,再稍作修改。注意: 如果复制修改了别人的开源代码,请添加开源许可。
RxBus其实是通过RxJava实现的,其作用跟EventBus一样,能够在各种情形下进行数据交换,而无需繁复的代码调用,只需要在两个需要交换数据的地方注册就可以了。
使用方法
首先注册@Overrideprotected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main_activity); //注册 RxBus.get().register(this);}@Overrideprotected void onDestroy(){ super.onDestroy(); //取消注册,防止内存泄漏 RxBus.get().unregister(this);}//在响应activity或fragment中添加某个方法,如:@Subscribepublic void eat(String food) { // purpose}//或者这样的//thread指定响应线程,如果是ui操作,需要选择MAIN_THREAD,或者默认不写,//tags是标签,用于事件之间进行区分,如果事件不多,tags不写即可,框架会有默认值。//此处是个数组,可以同时响应多种事件,如果要单独处理,需要分开写。@Subscribe(thread = EventThread.IO,tags = {@Tag(BusAction.EAT_MORE)})public void doSomething(List<String> foods) { // purpose}//订阅以后在其他的activity或者fragment中使用post//带tags,只有订阅时tags里面有"dd"才会响应RxBus.get().post("dd", "走你");//默认RxBus.get().post("走你");
Retrofit
square出品,Rx风格的网络请求框架,注解式的请求方式,底层使用OkHttp,稳定性不用怀疑,必是良品。在访问一个链接得到一个结果,然后由结果去访问另外一个链接的这种情形下尤其有用。
使用Retrofit需要以下依赖:
compile ‘com.squareup.retrofit2:retrofit:2.1.0’
compile ‘com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0’
compile ‘com.squareup.retrofit2:converter-gson:2.0.1’
使用方法如下,由于没有对Retrofit太多的研究,如果要深入了解可移步官网或者
http://www.jianshu.com/p/308f3c54abdd
Retrofit retrofit = new Retrofit.Builder() //Retrofit建议此处放app后台的公共地址,并带斜杠 .baseUrl("http://192.254.1.5:8080/HotMusic/") //此处就是和RxJava连接的关键 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) //此处是Retrofit解析json需要使用的转换器 .addConverterFactory(GsonConverterFactory.create()) .build(); ApiService ser = retrofit.create(ApiService.class); Call<User> call = ser.getUser(); call.enqueue(new Callback<User>() { @Override public void onResponse(Call<User> call, Response<User> response) { Log.e("s", response.body().name); } @Override public void onFailure(Call<User> call, Throwable t) { } });}//public interface ApiService{ @GET("hot/getUser/{id}") //这里的{id} 表示是一个变量 Call<User> getUser(/** 这里的id表示的是上面的{id} */@Path("id") int id);}
Green Dao
greenDao是一个将对象映射到SQLite数据库中的轻量且快速的ORM解决方案。关于greenDAO的概念可以看官网
学习地址:http://www.jianshu.com/p/dac3bd9bad72
配置:
Project中的build.gradle中添加以下内容:
repositories { jcenter() mavenCentral()}dependencies { classpath 'com.android.tools.build:gradle:2.2.3' //lambda的配置 classpath 'me.tatarka:gradle-retrolambda:3.2.5' //green dao的配置 classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1'}
app中的build.gradle中添加以下内容:
//Green Dao的配置
使用插件
apply plugin: ‘org.greenrobot.greendao’
//添加依赖
compile ‘org.greenrobot:greendao:3.2.0’
//数据库配置,会自动在gen包下生成响应的类greendao { schemaVersion 1 daoPackage 'com.white.hot.hotmusic.gen' targetGenDir 'src/main/java'}
- schemaVersion 对应当前数据库版本
- daoPackage 由GreenDao自动生成代码所在的包名,默认的是在项目包下面新建一个gen。
- targetGenDir 设置自动生成代码的目录。
写好bean类,注意id必须为long型,然后点一下build就会自动生成DaoMaster,DaoSession,xxDao等类
- @Property 标识该属性在表中对应的列名称,默认会都会存储到数据库,可以不写这个注解,使用@Property(nameInDb = “fnam”)自定义存储时的字段名,外键不能使用该属性
- @Transient 标识该属性将不会映射到表中
- @Entity:告诉GreenDao该对象为实体,只有被@Entity注释的Bean类才能被dao类操作,表名默认是实体类的名称
- @Id:对象的Id,使用Long类型作为EntityId,否则会报错。(autoincrement = true)表示主键会自增,如果false就会使用旧值
- @NotNull:属性不能为空
- @Unique:该属性值必须在数据库中是唯一值
- @Generated:编译后自动生成的构造函数、方法等的注释,提示构造函数、方法等不能被修改
注释帮助文档
使用本地数据库:
注意:由于green dao的内部机制,所有表的id都是 _id ,所有字段名都是大写,所以如果要使用raw中的数据库,则表的设计请遵循该原则。
常规用法
创建一个管理类
public class GreenDaoManager{ private static GreenDaoManager instance; private DaoMaster mDaoMaster; private DaoSession mDaoSession; private static WeakReference<Context> wrContext; private String dbName; private GreenDaoManager(Context context, String dbName) { wrContext = new WeakReference<Context>(context); this.dbName = dbName; init(); } public static GreenDaoManager getInstance(Context context, String dbName) { if(instance == null) { synchronized (GreenDaoManager.class) { if(instance == null) { instance = new GreenDaoManager(context,dbName); } } } return instance; } private void init() { //字符串是数据库的名字 CustomDevOpenHelper helper = new CustomDevOpenHelper(wrContext.get(), dbName); mDaoMaster = new DaoMaster(helper.getWritableDatabase()); mDaoSession = mDaoMaster.newSession(); } public DaoMaster getDaoMaster() { return mDaoMaster; } public DaoSession getDaoSession() { return mDaoSession; } public DaoSession getNewSession() { mDaoSession = mDaoMaster.newSession(); return mDaoSession; }}在其他地方使用GreenDaoManager.getInstance(this, "dbName").getDaoSession().getUserDao().save(user);详细增删该查自行百度~
使用本地数据库的管理类:
以下关于greendao读取raw中数据库的内容参考了:http://www.cnblogs.com/libertycode/p/6256000.html
public class LocalGDManager{ private static LocalGDManager instance; private DaoMaster mDaoMaster; private DaoSession mDaoSession; private String dbName; private static WeakReference<Context> wrContext; private LocalGDManager(Context context,String dbName) { wrContext = new WeakReference<Context>(context); this.dbName = dbName; init(); } public static LocalGDManager getInstance(Context context, String dbName) { if(instance == null) { synchronized (LocalGDManager.class) { if(instance == null) { instance = new LocalGDManager(context, dbName); } } } return instance; } private void init() { //字符串是数据库的名字 //此处是自定义的Helper,因为自动生成的helper会强制生成所有表,对于我们从本地复制过去的表再对它进行创建肯定会出错 CustomDevOpenHelper devOpenHelper = new CustomDevOpenHelper(new GreenDaoContextWrapper(wrContext.get()),dbName, null); mDaoMaster = new DaoMaster(devOpenHelper.getWritableDatabase()); mDaoSession = mDaoMaster.newSession(); } public DaoMaster getDaoMaster() { return mDaoMaster; } public DaoSession getDaoSession() { return mDaoSession; } public DaoSession getNewSession() { mDaoSession = mDaoMaster.newSession(); return mDaoSession; }}
自定的helper,就是为了修改greendao的默认行为
public class CustomDevOpenHelper extends DaoMaster.DevOpenHelper{ @Override public void onCreate(Database db) { DaoMaster.createAllTables(db, true); } @Override public void onUpgrade(Database db, int oldVersion, int newVersion) { Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); DaoMaster.dropAllTables(db, false); onCreate(db); } public CustomDevOpenHelper(Context context, String name) { super(context, name); } public CustomDevOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) { super(context, name, factory); }}
需要自定义一个context wrapper用于复制本地数据库;
public class GreenDaoContextWrapper extends ContextWrapper{ private Context mContext; private int dbRes; public GreenDaoContextWrapper(Context base, int localDbRes) { super(base); this.mContext = base; dbRes = localDbRes; } @Override public File getDatabasePath(String name) { String filePath = mContext.getDatabasePath(name).getAbsolutePath(); File file = new File(filePath); if (!file.exists()) { if(!file.getParentFile().exists()) { file.getParentFile().mkdir(); } buildDatabase(filePath); } return file; } /** * 创建数据库文件,其实就是将raw文件夹下的数据库文件复制到应用的database文件夹下: * /data/data/com.xxxx/databases/ * * @param filePath */ private void buildDatabase(String filePath) { Log.d("GreenDao", "buildDatabase"); InputStream inputStream = mContext.getResources().openRawResource(dbRes); FileOutputStream fos = null; try { fos = new FileOutputStream(filePath); byte[] buffer = new byte[1024]; int length; while ((length = inputStream.read(buffer)) > 0) { fos.write(buffer, 0, length); } fos.flush(); fos.close(); inputStream.close(); } catch (Exception e) { e.printStackTrace(); } } @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) { Log.d("GreenDao", "openOrCreateDatabase"); SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory); return result; } @Override public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) { Log.d("GreenDao", "openOrCreateDatabase"); SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory); return result; }}
图片加载Glide
github:https://github.com/bumptech/glide
添加依赖:
compile ‘com.github.bumptech.glide:glide:3.7.0’
使用方法:
@Override public void onCreate(Bundle savedInstanceState) { ... ImageView imageView = (ImageView) findViewById(R.id.my_image_view); Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);}// For a simple image list:@Override public View getView(int position, View recycled, ViewGroup container) { final ImageView myImageView; if (recycled == null) { myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false); } else { myImageView = (ImageView) recycled; } String url = myUrls.get(position); Glide .with(myFragment) .load(url) .centerCrop() .placeholder(R.drawable.loading_spinner) .crossFade() .into(myImageView); return myImageView;}
加载gif
Glide.with(this) .load("http://wx2.sinaimg.cn/mw690/685d4d6cgy1fckkeajaovg20b407gb2b.gif") .asGif() .diskCacheStrategy(DiskCacheStrategy.SOURCE) .into(vf);
View注解ButterKnife
@Bind(R.id.btnf)Button btnf;@OnClick(R.id.btnf)public void onClick(View v){ Toast.makeText(getContext(), "click fragment", Toast.LENGTH_SHORT).show();}
frament绑定
@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState){ View v = inflater.inflate(R.layout.frag, container); ButterKnife.bind(this, v); return v;}@Overridepublic void onDestroyView(){ super.onDestroyView(); ButterKnife.unbind(this);}
activity绑定:
@Overrideprotected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this);}@OnClick(R.id.btn)public void onClick(View v){ v.getId(); Toast.makeText(this, "click activity", Toast.LENGTH_SHORT).show();}
OkHttp3
square出品的网络加载框架,使用广泛,安卓系统内部已经集成了该框架。
关于使用,这里不重复了,网上资料相当多,这里我列出自己写的一个okhttp帮助类,由于资源模块暂时不能用,只能贴代码了:
参考了鸿洋大神的博客:http://blog.csdn.net/lmj623565791/article/details/47911083
使用这个类需要添加Gson的依赖:compile ‘com.google.code.gson:gson:2.2.4’
public class OkHttpManager { private static OkHttpManager mInstance; private Handler mHandler; private Gson mGson; //默认超时时间20秒 private static int timeout = 20; private OkHttpClient clientDefault; private static Request simpleGetReq; private static Request simplePostReq; private static final String NET_FAILED_MSG = "未知异常!"; private static final String NET_FAILED_JSON_MSG = "Json 转换异常"; private static final String NET_FAILED_LINK_UNAVIlABLE_MSG = "无法连接"; private static final String NET_FAILED_TIMEOUT_MSG = "连接超时"; private static final String NET_FAILED_FILE_MSG = "文件不存在"; private OkHttpManager() { mGson = new Gson(); clientDefault = new OkHttpClient.Builder() .connectTimeout(timeout, TimeUnit.SECONDS) .readTimeout(timeout, TimeUnit.SECONDS) .retryOnConnectionFailure(true) .build(); mHandler = new Handler(Looper.getMainLooper()); } public static OkHttpManager getInstance() { if (mInstance == null) { synchronized (OkHttpManager.class) { if (mInstance == null) { mInstance = new OkHttpManager(); } } } return mInstance; } /*** * <b>发送一个get请求</b>, 回调要传入类型 * * @param url 链接 * @param callback 回调函数 */ public void doGet(String url, final ResultCallback<? extends Object> callback) { if (callback == null) { throw new RuntimeException("回调不能为空"); } if (simpleGetReq == null) { simpleGetReq = new Request.Builder().get().url(url).build(); } else { simpleGetReq = simpleGetReq.newBuilder().get().url(url).build(); } deliveryRequest(simpleGetReq, callback); } /*** * <b>发送一个post请求</b>, 回调要传入类型 * * @param url 链接 * @param callback 回调函数 * @param reqBodyParam 请求体参数 * @param reqHeader 请求头参数 */ public void doPost(String url, final ResultCallback<? extends Object> callback, Map<String, String> reqBodyParam, Map<String, String> reqHeader) { if (callback == null) { throw new RuntimeException("回调不能为空"); } if (simplePostReq == null) { if(reqHeader == null) { simplePostReq = new Request.Builder().post(reqBodyParam == null ? buildEmptyBody() :buildParams(reqBodyParam).build()).url(url).build(); }else { //构造请求头 Request.Builder builder = new Request.Builder(); Set<String> set = reqHeader.keySet(); for(Iterator<String> it = set.iterator();it.hasNext();) { String key = it.next(); String value = reqHeader.get(key); builder.addHeader(key, value); } simplePostReq = builder.post(reqBodyParam == null ? buildEmptyBody() : buildParams(reqBodyParam).build()).url(url).build(); } } else { if(reqHeader == null) { simplePostReq = simplePostReq.newBuilder().post(reqBodyParam == null ? buildEmptyBody() :buildParams(reqBodyParam).build()).url(url).build(); }else { //构造请求头 Request.Builder builder = simplePostReq.newBuilder(); Set<String> set = reqHeader.keySet(); for(Iterator<String> it = set.iterator();it.hasNext();) { String key = it.next(); String value = reqHeader.get(key); builder.addHeader(key, value); } simplePostReq = builder.post(reqBodyParam == null ? buildEmptyBody() : buildParams(reqBodyParam).build()).url(url).build(); } } deliveryRequest(simplePostReq, callback); } /*** * <b>发送一个post请求</b>, 回调要传入类型 * * @param url 链接 * @param callback 回调函数 * @param reqBodyParam 请求体参数 */ public void doPost(String url, final ResultCallback<? extends Object> callback, Map<String, String> reqBodyParam) { doPost(url, callback, reqBodyParam, null); } // public void doPost(String url, final ResultCallback<? extends Object> callback, Object obj) // { // Map<String, String> param = new HashMap<>(); // } /*** * <b>构建参数</b> * * @param map 参数 * @return */ private FormBody.Builder buildParams(Map<String, String> map) { FormBody.Builder builder = new FormBody.Builder(); if (map != null && map.size() > 0) { Set<String> set = map.keySet(); for (Iterator<String> it = set.iterator(); it.hasNext(); ) { String key = it.next(); String value = map.get(key); builder.add(key, value); } } return builder; } private RequestBody buildEmptyBody() { return RequestBody.create(null, new byte[0]); } /*** * <b>传递请求</b> * * @param request * @param callback */ private void deliveryRequest(Request request, final ResultCallback callback) { clientDefault.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, final IOException e) { failedResponse(e, callback); } @Override public void onResponse(Call call, Response response) throws IOException { try { final String string = response.body().string(); if(string.startsWith("<html>") || string.startsWith("<HTML>")) { int errStartIndex = string.indexOf("<body>")+6; int errEndIndex = string.indexOf("</body>"); String errStr = string.substring(errStartIndex, errEndIndex); errStartIndex = errStr.indexOf("<h1>")+4; errEndIndex = errStr.indexOf("</h1>"); errStr = errStr.substring(errStartIndex, errEndIndex); failedResponse(new IllegalArgumentException(errStr), callback); return; } if (callback.mType == String.class) { successResponse(string, callback); } else { Object o = mGson.fromJson(string, callback.mType); successResponse(o, callback); } } catch (com.google.gson.JsonParseException e)//Json解析的错误 { failedResponse(e, callback); } catch (IOException e) { failedResponse(e, callback); } } }); } /*** * <b>下载, 如果要拿到进度,需要复写callback的<b>onProgress()</b>方法</b>, 回调方法要传入类型 * * @param url 下载链接<br/> * @param fileAbsolutePath 文件绝对路径<br/> * @param callback 回调<br/> */ public void download(final String url, final String fileAbsolutePath, final ResultCallback callback) { final Request request = new Request.Builder() .url(url) .build(); final DownloadProgressListener progressListener = new DownloadProgressListener() { @Override public void update(long bytesRead, long contentLength, boolean done) { onDownloadProgress(bytesRead, contentLength, done, callback); } }; clientDefault = clientDefault.newBuilder().addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Response originalResponse = chain.proceed(chain.request()); return originalResponse.newBuilder().body( new ProgressResponseBody(originalResponse.body(), progressListener)) .build(); } }).build(); final Call call = clientDefault.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, final IOException e) { failedResponse(e, callback); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { is = response.body().byteStream(); File file = new File(fileAbsolutePath); fos = new FileOutputStream(file); while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); } fos.flush(); successResponse(file, callback); } catch (IOException e) { e.printStackTrace(); failedResponse(e, callback); } finally { try { if (is != null) is.close(); } catch (IOException e) { } try { if (fos != null) fos.close(); } catch (IOException e) { } } } }); } /*** * 文件上传 * @param url url * @param fileAbsolutePath 文件绝对路径 * @param fileParamName 文件上传的参数名,相当于post的param * @param callback 回调函数 */ public void upload(final String url, final String fileAbsolutePath, final String fileParamName, final ResultCallback callback) { if(callback == null) { throw new RuntimeException("回调不能为空"); } File file = new File(fileAbsolutePath); if(!file.exists()) { failedResponse(new FileNotFoundException(), callback); return; } final UploadProgressListener listener = new UploadProgressListener() { @Override public void onRequestProgress(long bytesWrite, long contentLength, boolean done) { onUploadProgress(bytesWrite, contentLength, done, callback); } }; String fileName = getFileName(fileAbsolutePath); RequestBody reqBody = RequestBody.create(MediaType.parse("application/octet-stream"), file); MultipartBody mBody = new MultipartBody.Builder("--------------------------").setType(MultipartBody.FORM) .addFormDataPart(fileParamName , fileName , new ProgressRequestBody(reqBody, listener)) .build(); clientDefault = clientDefault.newBuilder().build(); if (simplePostReq == null) { simplePostReq = new Request.Builder().post(mBody).url(url).build(); }else { simplePostReq = simplePostReq.newBuilder().url(url).post(mBody).build(); } Call call = clientDefault.newCall(simplePostReq); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { failedResponse(e, callback); } @Override public void onResponse(Call call, Response response) throws IOException { try { final String string = response.body().string(); if (callback.mType == String.class) { successResponse(string, callback); } else { Object o = mGson.fromJson(string, callback.mType); successResponse(o, callback); } } catch (com.google.gson.JsonParseException e)//Json解析的错误 { failedResponse(e, callback); } catch (IOException e) { failedResponse(e, callback); } } }); } public String getFileName(String filePath) { if (TextUtils.isEmpty(filePath)) return ""; return filePath.substring(filePath.lastIndexOf(File.separator) + 1); } /*** * 文件下载的响应体 */ private static class ProgressResponseBody extends ResponseBody { private final ResponseBody responseBody; private final DownloadProgressListener progressListener; private BufferedSource bufferedSource; public ProgressResponseBody(ResponseBody responseBody, DownloadProgressListener progressListener) { this.responseBody = responseBody; this.progressListener = progressListener; } @Override public MediaType contentType() { return responseBody.contentType(); } @Override public long contentLength() { return responseBody.contentLength(); } @Override public BufferedSource source() { if (bufferedSource == null) { bufferedSource = Okio.buffer(source(responseBody.source())); } return bufferedSource; } private Source source(Source source) { return new ForwardingSource(source) { long totalBytesRead = 0L; @Override public long read(Buffer sink, long byteCount) throws IOException { long bytesRead = super.read(sink, byteCount); totalBytesRead += bytesRead != -1 ? bytesRead : 0; progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1); return bytesRead; } }; } } interface DownloadProgressListener { /** * @param bytesRead 已下载字节数 * @param contentLength 总字节数 * @param done 是否下载完成 */ void update(long bytesRead, long contentLength, boolean done); } /*** * 文件上传的请求体 */ public class ProgressRequestBody extends RequestBody { //实际的待包装请求体 private final RequestBody requestBody; //进度回调接口 private final UploadProgressListener progressListener; //包装完成的BufferedSink private BufferedSink bufferedSink; /** * 构造函数,赋值 * @param requestBody 待包装的请求体 * @param progressListener 回调接口 */ public ProgressRequestBody(RequestBody requestBody, UploadProgressListener progressListener) { this.requestBody = requestBody; this.progressListener = progressListener; } /** * 重写调用实际的响应体的contentType * @return MediaType */ @Override public MediaType contentType() { return requestBody.contentType(); } /** * 重写调用实际的响应体的contentLength * @return contentLength * @throws IOException 异常 */ @Override public long contentLength() throws IOException { return requestBody.contentLength(); } /** * 重写进行写入 * @param sink BufferedSink * @throws IOException 异常 */ @Override public void writeTo(BufferedSink sink) throws IOException { if (bufferedSink == null) { //包装 bufferedSink = Okio.buffer(sink(sink)); } //写入 requestBody.writeTo(bufferedSink); //必须调用flush,否则最后一部分数据可能不会被写入 bufferedSink.flush(); } /** * 写入,回调进度接口 * @param sink Sink * @return Sink */ private Sink sink(Sink sink) { return new ForwardingSink(sink) { //当前写入字节数 long bytesWritten = 0L; //总字节长度,避免多次调用contentLength()方法 long contentLength = 0L; @Override public void write(Buffer source, long byteCount) throws IOException { super.write(source, byteCount); if (contentLength == 0) { //获得contentLength的值,后续不再调用 contentLength = contentLength(); } //增加当前写入的字节数 bytesWritten += byteCount; //回调 progressListener.onRequestProgress(bytesWritten, contentLength, bytesWritten == contentLength); } }; } } interface UploadProgressListener { /** * @param bytesWrite 已上传字节数 * @param contentLength 总字节数 * @param done 是否上传完成 */ void onRequestProgress(long bytesWrite, long contentLength, boolean done); } private void failedResponse(final Exception e, final ResultCallback callback) { mHandler.post(new Runnable() { @Override public void run() { if (callback != null) { if (e instanceof com.google.gson.JsonParseException) { callback.onError(NET_FAILED_JSON_MSG, e); } else if (e instanceof ConnectException) { callback.onError(NET_FAILED_LINK_UNAVIlABLE_MSG, e); } else if (e instanceof SocketTimeoutException) { callback.onError(NET_FAILED_TIMEOUT_MSG, e); } else if (e instanceof FileNotFoundException) { callback.onError(NET_FAILED_FILE_MSG, e); } else if (e instanceof IllegalArgumentException) { callback.onError("参数异常-"+e.getMessage(), e); } else { callback.onError(NET_FAILED_MSG, e); } } } }); } private void onDownloadProgress(final long progress, final long allLength, final boolean done, final ResultCallback callback) { mHandler.post(new Runnable() { @Override public void run() { callback.onDownloadProgress(progress, allLength, done); } }); } private void onUploadProgress(final long progress, final long allLength, final boolean done, final ResultCallback callback) { mHandler.post(new Runnable() { @Override public void run() { callback.onUploadProgress(progress, allLength, done); } }); } private void successResponse(final Object object, final ResultCallback callback) { mHandler.post(new Runnable() { @Override public void run() { if (callback != null) { callback.onSuccess(object); } } }); } /*** * 回调类,用于返回结果到前台 * * @param <T> 传入一个泛型,会自动根据类型产生对象,在post中用处较多 */ public static abstract class ResultCallback<T extends Object> { Type mType; public ResultCallback() { mType = getSuperclassTypeParameter(getClass()); } public static Type getSuperclassTypeParameter(Class<?> subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("ResultCallback泛型缺少对象类型"); } ParameterizedType parameterized = (ParameterizedType) superclass; return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); } public abstract void onError(String simpleMsg, Exception e); public void onDownloadProgress(long progress, long allLength, boolean done){} public void onUploadProgress(long progress, long allLength, boolean done){} public abstract void onSuccess(T response); } /*** * 此方法用于设置https访问时证书,仅用于单向验证,inputstream为证书文件的输入流,可以将证书放到main/assets目录下, * 也可以使用rfc命令得到字符串用 new Buffer().writeUtf(str).inputStream()得到输入流, * 需要包含-----BEGIN CERTIFICATE-----和-----END CERTIFICATE----- * @param certificate */ public void setCertificate(String alias, String password, InputStream certificate) { try { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); int index = 0; // for (InputStream certificate : certificates) // { // String certificateAlias = Integer.toString(index++); keyStore.setCertificateEntry(alias, certificateFactory.generateCertificate(certificate)); try { if (certificate != null) certificate.close(); } catch (IOException e) { } // } SSLContext sslContext = SSLContext.getInstance("TLS"); KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, password.toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); }else { sslContext.init(null,new TrustManager[]{trustManagers[0]},new SecureRandom()); clientDefault = clientDefault.newBuilder() .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagers[0]) .build(); } } catch (Exception e) { e.printStackTrace(); } } }
使用:
manager = OkHttpManager.getInstance();manager.doPost(Constant.WEB_BASE + "/jpush/notifyOne", new OkHttpManager.ResultCallback<BaseResp>() { @Override public void onError(String simpleMsg, Exception e) { Toast.makeText(PushActivity.this, simpleMsg, Toast.LENGTH_SHORT).show(); } @Override public void onSuccess(BaseResp response) { Toast.makeText(PushActivity.this, response.getInfo(), Toast.LENGTH_SHORT).show(); } }, null);
其他使用方法自行研究~
- 安卓高效框架简单使用
- 安卓网络框架---volley的简单使用。
- 安卓高效的HTTP请求框架HTTPRequest
- 安卓视频压缩框架简单易用
- 安卓 socket简单使用
- 安卓:WebView简单使用
- 简单高效的RPC框架
- 安卓开发框架Volly的使用
- 安卓volley框架基本使用
- 【安卓】Volley框架使用一
- 安卓Glide框架使用总结
- 安卓视频框架vitamio使用入门
- 安卓高效代码编写
- 安卓 Bitmap 高效加载
- 如何高效学习安卓
- 高效使用JavaEE ORM框架
- 高效使用JavaEE ORM框架
- 高效使用JavaEE ORM框架
- Java Web 学习笔记(一):开发环境搭建
- minicom 使用
- Linux下的常用操作
- Selenium疑问贴(持续更新中)
- 简单好用的自定义Dialog(二)
- 安卓高效框架简单使用
- HTTP Status Code 说明
- iOS回顾笔记( 01 )
- 电商产品设计:怎样设计实用的商品中心
- MB中消息集校验功能实现例子
- 近几日使用strtok的一点心得体会
- (1)caffe总结之Ubuntu 14.04 + Caffe + Cuda 7.5 + Opencv 3.0安装教程
- java线程池理解
- HTML5标签整理六