>>分享Android开发相关的技术 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 24750 个阅读者 刷新本主题
 * 贴子主题:  Android网络开发-请求队列-性能提升解决方案 回复文章 点赞(0)  收藏  
作者:javathinker    发表时间:2020-05-15 06:14:23     消息  查看  搜索  好友  复制  引用

   因为之前参与的网络开发项目都遇到一些相同的问题:

1.大量的并发请求造成堵塞,特别是遇上让人无语的3G网络,无限loading。。。

2.一般来说一个网络请求都会用使用到一个异步线程,大量的线程创建、运行、销毁又造成了系统资源的浪费

3.请求结束得到结果后,如果需要更新UI,一个不小心忘了返回UI线程,各种崩溃。。。

前些日子跟同事商量能不能做个请求队列去进行控制,于是趁着热度没消退说干就干,建了个模型,以备日后使用。

在这个模型中,有高中低三个优先级信道如下:高优先级--1,中优先级--3,低优先级--2

规则:

1.正常情况下各个优先级使用各自信道(线程)

2.高级信道满载、中、低级信道空置,则高级请求可使用低级信道

构思:

UI线程将期望的网络请求url和参数通过一个封装好的Runnable提交给Service处理(当然也可以交给一个Thread处理,本例使用Service),Service接收到请求,判断优先级,加入到相应线程池中排队。线程池启动线程发起网络请求,最后通过监听器将结果返回给Service,Service发送广播通知UI线程,UI线程更新相关界面,结束。

废话说完,上例子:

首先是封装好的Runnable
  1.    public   class  HttpConnRunnable  implements  Runnable, Parcelable {
  2.        public   static   final   int  HIGH_LEVEL =  0 ;
  3.        public   static   final   int  NORMAL_LEVEL =  1 ;
  4.        public   static   final   int  LOW_LEVEL =  2 ;
  5.        private   int  mPriority = NORMAL_LEVEL; //优先级,默认为普通  
  6.        private  String mUrl =  "" ;
  7.        private  HttpConnListener mListener; //监听器  
  8.        public  HttpConnRunnable() {
  9.            super ();
  10.       }
  11.        public  HttpConnRunnable( int  priority) {
  12.            super ();
  13.           mPriority = priority;
  14.       }    
  15.        @Override  
  16.        public   void  run() {
  17.           Log.i(Thread.currentThread().getName(),  "----Start to connect:"  + mUrl +  ", priority:"  + mPriority +  "-----" );
  18.            try  {
  19.               Thread.sleep( 10000 );
  20.                //TODO:进行网络请求相关操作,并通过listener返回结果  
  21.               mListener.onSucceed( "Connected to "  + mUrl +  " succeed!" );
  22.           }
  23.            catch  (InterruptedException e) {
  24.               e.printStackTrace();
  25.           }
  26.           Log.i(Thread.currentThread().getName(),  "----Finish to connect:"  + mUrl +  ", priority:"  + mPriority +  "-----" );
  27.       }
  28.        public   int  getPriority() {
  29.            return  mPriority;
  30.       }
  31.        public   void  setPriority( int  priority) {
  32.           mPriority = priority;
  33.       }
  34.        public  String getURL() {
  35.            return  mUrl;
  36.       }
  37.        public   void  setURL(String url) {
  38.           mUrl = url;
  39.       }
  40.        public   void  setHttpConnListener(HttpConnListener listener) {
  41.           mListener = listener;
  42.       }
  43.        //序列化,为了传递给Service,如果是使用Thread处理本例,则无需序列化  
  44.        public   static   final  Parcelable.Creator<HttpConnRunnable> CREATOR =  new  Creator<HttpConnRunnable>() {
  45.            @Override  
  46.            public  HttpConnRunnable createFromParcel(Parcel source) {
  47.               HttpConnRunnable data =  null ;
  48.               Bundle bundle = source.readBundle();
  49.                if (bundle !=  null ) {
  50.                   data =  new  HttpConnRunnable(bundle.getInt( "PRIORITY" ));
  51.                   data.mUrl = bundle.getString( "URL" );
  52.               }
  53.                return  data;
  54.           }
  55.            @Override  
  56.            public  HttpConnRunnable[] newArray( int  size) {
  57.                return   new  HttpConnRunnable[size];
  58.           }
  59.       };
  60.        @Override  
  61.        public   int  describeContents() {
  62.            return   0 ;
  63.       }
  64.        @Override  
  65.        public   void  writeToParcel(Parcel dest,  int  flags) {
  66.           Bundle bundle =  new  Bundle();
  67.           bundle.putInt( "PRIORITY" , mPriority);
  68.           bundle.putString( "URL" , mUrl);
  69.           dest.writeBundle(bundle);
  70.       }
  71.   }

    Service的处理:

  1.    public   class  HttpConnService  extends Service  implements  HttpConnListener {
  2.        public   static   final  String HTTP_POOL_PARAM_KEYWORD =  "HttpPoolParam" ;            //网络参数传递的关键字  
  3.        private   final   int  HIGH_POOL_SIZE =  1 ;
  4.        private   final   int  NORMAL_POOL_SIZE =  3 ;
  5.        private   final   int  LOW_POOL_SIZE =  2 ;
  6.        // 可重用固定线程数的线程池  
  7.        private  ThreadPoolExecutor mHighPool;
  8.        private  ThreadPoolExecutor mNormalPool;
  9.        private  ThreadPoolExecutor mLowPool;
  10.        @Override  
  11.        public   void  onCreate() {
  12.            //初始化所有  
  13.           mHighPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(HIGH_POOL_SIZE);
  14.           mNormalPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(NORMAL_POOL_SIZE);
  15.           mLowPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(LOW_POOL_SIZE);
  16.            super .onCreate();
  17.       }
  18.        @Override  
  19.        public   int  onStartCommand(Intent intent,  int  flags,  int  startId) {
  20.            //接受到来自UI线程的请求  
  21.            //取出Runnable,并加入到相应队列  
  22.           Bundle bundle = intent.getExtras();
  23.           HttpConnRunnable httpConnRunnable = bundle.getParcelable(HTTP_POOL_PARAM_KEYWORD);
  24.            if  (httpConnRunnable !=  null ) {
  25.               httpConnRunnable.setHttpConnListener(HttpConnService. this );
  26.                int  level = httpConnRunnable.getPriority();
  27.                switch  (level) {
  28.                    case  HttpConnRunnable.HIGH_LEVEL:
  29.                        //如果高级池满而低级池未满交由低级池处理  
  30.                        //如果高级池满而普通池未满交由普通池处理  
  31.                        //如果高级池未满则交给高级池处理,否则,交由高级池排队等候  
  32.                        if  (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) {
  33.                           mLowPool.execute(httpConnRunnable);
  34.                       }
  35.                        else   if  (mHighPool.getActiveCount() == HIGH_POOL_SIZE && mNormalPool.getActiveCount() < NORMAL_POOL_SIZE) {
  36.                           mNormalPool.execute(httpConnRunnable);
  37.                       }
  38.                        else  {
  39.                           mHighPool.execute(httpConnRunnable);
  40.                       }
  41.                        break ;
  42.                    case  HttpConnRunnable.NORMAL_LEVEL:
  43.                        //如果普通池满而低级池未满交由低级池处理  
  44.                        //如果普通池未满则交给普通池处理,否则,交由普通池排队等候  
  45.                        if  (mNormalPool.getActiveCount() == NORMAL_POOL_SIZE && mLowPool.getActiveCount() < LOW_POOL_SIZE) {
  46.                           mLowPool.execute(httpConnRunnable);
  47.                       }
  48.                        else  {
  49.                           mNormalPool.execute(httpConnRunnable);
  50.                       }
  51.                        break ;
  52.                    case  HttpConnRunnable.LOW_LEVEL:
  53.                       mLowPool.execute(httpConnRunnable);
  54.                        break ;
  55.               }
  56.           }
  57.            return   super .onStartCommand(intent, flags, startId);
  58.       }
  59.        @Override  
  60.        public   void  onDestroy() {
  61.           mHighPool.shutdownNow();
  62.           mNormalPool.shutdownNow();
  63.           mLowPool.shutdownNow();
  64.           mNormalPool =  null ;
  65.           mLowPool =  null ;
  66.            super .onDestroy();
  67.       }
  68.        @Override  
  69.        public  IBinder onBind(Intent intent) {
  70.            return   null ;
  71.       }
  72.        @Override  
  73.        public   void  onSucceed(String result) {
  74.           Intent intent =  new  Intent();
  75.           intent.setAction( "com.ezstudio.connpool.HttpConnReceiver" );
  76.            // 要发送的内容  
  77.           intent.putExtra( "RESULT" , result);
  78.            // 发送 一个无序广播  
  79.           sendBroadcast(intent);
  80.       }
  81.        @Override  
  82.        public   void  onFailed() {
  83.            // TODO Auto-generated method stub  
  84.       }
  85.   }

       Receiver的处理比较简单:

  1.    public   class  HttpConnReceiver  extends BroadcastReceiver {
  2.        private  HttpConnListener mListener;
  3.        public   void  setHttpConnListener (HttpConnListener listener) {
  4.           mListener = listener;
  5.       }
  6.        @Override  
  7.        public   void  onReceive(Context context, Intent intent) {
  8.           String action = intent.getAction();
  9.            if  (action.equals( "com.ezstudio.connpool.HttpConnReceiver" )) {
  10.               String result = intent.getStringExtra( "RESULT" );
  11.               mListener.onSucceed(result);
  12.           }
  13.       }
  14.   }

        ok,流程走完了,写个测试界面

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小

       看结果非常满意:

    05-03 16:42:20.225: I/HighPollingThread(2318): ----HighQuqeue is  empty-----

    05-03 16:42:20.225: I/NormalPollingThread(2318): ----NormalQuqeue  is empty-----

    05-03 16:42:20.233: I/LowPollingThread(2318): ----LowQuqeue is  empty-----

    05-03 16:42:20.233: I/HighPollingThread(2318): ----HighQuqeue is  empty-----

    05-03 16:42:20.233: I/pool-1-thread-1(2318): ----Start to  connect:www.0.com, priority:0-----

    05-03 16:42:22.374:  I/NormalPollingThread(2318): ----NormalQuqeue is empty-----

    05-03  16:42:22.374: I/pool-2-thread-1(2318): ----Start to connect:www.1.com,  priority:1-----

    05-03 16:42:22.780: I/LowPollingThread(2318): ----LowQuqeue  is empty-----

    05-03 16:42:22.780: I/pool-3-thread-1(2318): ----Start to  connect:www.2.com, priority:2-----

    05-03 16:42:23.428:  I/NormalPollingThread(2318): ----NormalQuqeue is empty-----

    05-03  16:42:23.428: I/pool-2-thread-2(2318): ----Start to connect:www.3.com,  priority:1-----

    05-03 16:42:23.835: I/HighPollingThread(2318): ----HighQuqeue  is empty-----

    05-03 16:42:23.835: I/pool-3-thread-2(2318): ----Start to  connect:www.4.com, priority:0-----

    05-03 16:42:24.171:  I/NormalPollingThread(2318): ----NormalQuqeue is empty-----

    05-03  16:42:24.171: I/pool-2-thread-3(2318): ----Start to connect:www.5.com,  priority:1-----

    05-03 16:42:24.507: I/LowPollingThread(2318): ----LowQuqeue  is empty-----

    05-03 16:42:24.764: I/NormalPollingThread(2318):  ----NormalQuqeue is empty-----

    05-03 16:42:25.030: I/HighPollingThread(2318):  ----HighQuqeue is empty-----

    05-03 16:42:25.335: I/NormalPollingThread(2318):  ----NormalQuqeue is empty-----

    05-03 16:42:25.647: I/LowPollingThread(2318):  ----LowQuqeue is empty-----

    05-03 16:42:25.936: I/NormalPollingThread(2318):  ----NormalQuqeue is empty-----

    05-03 16:42:26.163:  I/NormalPollingThread(2318): ----NormalQuqeue is empty-----

    05-03  16:42:26.389: I/NormalPollingThread(2318): ----NormalQuqeue is  empty-----

    05-03 16:42:26.694: I/LowPollingThread(2318): ----LowQuqeue is  empty-----

           总结:如果不算Service一共最多使用了3个线程池,6个线程,或许可以考虑将三个池合并为一个。但却也大量减少了单独发起请求时的线程创建和销毁的消耗。

      

----------------------------
原文链接:https://blog.51cto.com/winwyf/851412

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-06-05 08:24:34 重新编辑]
  Java面向对象编程-->Swing组件(下)
  JavaWeb开发-->自定义JSP标签(Ⅱ)
  JSP与Hibernate开发-->第一个helloapp应用
  Java网络编程-->基于UDP的数据报和套接字
  精通Spring-->Vue Router路由管理器
  Vue3开发-->Vue组件开发基础
  Android网络编程之WebKit应用
  Android ListView滑动加载
  Android制作Tabs界面的常用方法
  android实用测试方法之Monkey与MonkeyRunner
  Android UI学习 - Tab的学习和使用
  Android API 中Toast类的用法
  Android HelloGallery范例实验记录
  Android 解码播放GIF图像
  Android多线程断点续传
  Android ListView滑动加载
  Android内核开发:图解Android系统的启动过程
  Android Camera2.0 结合ImageReader拍照并解决图片偏转问题
  Android 活动(Activity)
  Android_实现商品详情的展示页及布局
  Android中shape的使用-Kofi
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。