安卓高效框架简单使用

安卓高效框架

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 —创建精确和有限行为的观测值,不知道搞什么的~
  • fromIterable — 从一个可以迭代的集合中产生事件
  • fromArray — 从一个数组中产生
  • Interval — 按一定的时间间隔发送相同事件
  • Just — 传递一个数值集合,可以是数组和集合或者多个单一元素
  • Range — 传递一个数值范围,然后框架会产生范围之间的所有数值
  • Repeat — 重复发送某个相同的事件
  • Start — 通过一个函数返回值床架Observable对象
  • Timer — 定时产生Observable对象

常规使用:

//创建一个Observable
Observable.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作用跟EventBus一样,也是通过订阅发布的方式来达到组件间通信。

RxBus也好EventBus也好,过度使用会导致代码结构混乱,逻辑难以追踪,维护困难,所以也要适度使用。

使用方法

首先注册
@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_activity);
    //注册
    RxBus.get().register(this);
}

@Override
protected void onDestroy()
{
    super.onDestroy();
    //取消注册,防止内存泄漏
    RxBus.get().unregister(this);
}

//在响应activity或fragment中添加某个方法,如:
@Subscribe
public void eat(String food) {
    // purpose
}

//或者这样的
//thread指定响应线程,如果是ui操作,需要选择MAIN_THREAD,或者默认不写,
//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
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
    View v = inflater.inflate(R.layout.frag, container);
    ButterKnife.bind(this, v);
    return v;
}

@Override
public void onDestroyView()
{
    super.onDestroyView();
    ButterKnife.unbind(this);
}

activity绑定:

@Override
protected 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);

其他使用方法自行研究~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 平台上有许多主流框架供开发者使用。以下是一些常用的 Android 框架: 1. Android Jetpack:Jetpack 是一套库、工具和指南集合,用于帮助开发者更轻松地构建高质量的 Android 应用。它包括各种组件,如 LiveData、ViewModel、Room、WorkManager 等,以及其他辅助工具。 2. Retrofit:Retrofit 是一个强大的网络请求库,用于简化与 RESTful API 进行通信。它提供了简洁的 API 接口,可以轻松地定义网络请求、处理响应和数据解析。 3. OkHttp:OkHttp 是一个高效的 HTTP 客户端库,用于发送网络请求。它支持同步和异步请求,并提供了诸如请求重试、缓存控制、连接池管理等功能。 4. Dagger:Dagger 是一个依赖注入框架,用于帮助管理和组织 Android 应用中的对象依赖关系。它提供了编译时依赖注入的机制,可以减少手动依赖注入的工作量。 5. Glide:Glide 是一个强大的图片加载库,用于在 Android 应用中加载和展示图片。它支持网络图片加载、本地图片加载、图片缓存等功能,并提供了简单易用的 API 接口。 6. RxJava:RxJava 是一个基于观察者模式的异步编程库,用于简化 Android 应用中的异步操作和事件处理。它提供了丰富的操作符和线程调度机制,可以帮助开发者更优雅地处理异步任务。 这些框架都在 Android 开发中得到广泛应用,可以提高开发效率、简化代码结构,同时提供了许多强大的功能和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值