Android优化指南

Android系统中GC内存泄漏的原因

主动回收内存System.gc();、getruntime.runtime.gc

导致内存泄漏主要的原因是,申请了内存空间而忘记了释放。如果程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器GC验证这些对象是否不再需要。如果存在对象的引用,这个对象就被定义为"有效的活动",同时不会被释放。要确定对象所占内存将被回收,我们就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。但当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。

什么是GC

GC垃圾收集器,它让创建的对象不需要像c/c++那样delete、free掉,GC的时间系统自身决定,时间不可预测或者说调用System.gc()的时候。 对超出作用域的对象或引用置为空的对象进行清理,删除不使用的对象,腾出内存空间。

Java带垃圾回收的机制,为什么还会内存泄露呢?

举个例子 当你堆里某个对象没有被引用时,然后再过一段时间,垃圾回收机制才会回收,那么 while(true){ String str=new String("ni hao ni hao "); } 一直循环创建 String对象。。。你觉得堆不会溢出嘛。。。 垃圾回收 要有2个条件 1 该对象没有被引用 2 过了一段时间

Java 内存泄露的根本原因就是 保存了不可能再被访问的变量类型的引用,回收不确定性

内存溢出和内存泄漏

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!

内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。 

从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。

 Java中有内存泄露吗?举一些例子?

1.查询数据库没有关闭游标 2. 构造Adapter时,没有使用缓存的 convertView 3. Bitmap对象不再使用时调用recycle()释放内存 4. 无用时没有释放对象的引用 5. 在Activity中使用非静态的内部类,并开启一个长时间运行的线程,因为内部类持有Activity的引用,会导致Activity本来可以被gc时却长期得不到回收 6.使用Handler处理消息前,Activity通过例如finish()退出,导致内存泄漏 7.动态注册广播在Activity销毁前没有unregisterReceive

内存的优化

  • 回收已经使用的资源,比如游标cursor 、I/O、Bitmap(close并且引用置为null)
  • 合理的使用缓存,比如图片是很耗内存的,使用lru缓存图片和压缩
  • 合理设置变量的作用范围
  • 节制的使用服务,后台任务运行完,即使它不执行任何操作,服务也会一直运行,这些是十分消耗内存的,可以用intentservice
  • 当界面不可见时释放内存,在activity的onTrimMemory方法里与ui的相关资源,在onstop里释放与组件相关的资源
  • 合理的使用多进程,如果后台任务和前台界面是相互独立在,可以在组件标签下写process,这样这个组建就在另一个进程里了。而服务的话更倾向于开启自己所依赖的进程,而那个进程可能很多东西都不需要,比如ui
  • 使用线程池、对象池
  • Bitmap对象在不使用时,应该先调用recycle()释放内存,然后才它设置为null。

说说线程池

好处

避免线程的创建和销毁所带来的性能得开销

能有效控制线程池的最大并发数,避免了大量线程间抢占资源而导致的阻塞现象

能够对线程进行简单的管理,并提供定时执行以及指定间隔循环执行等功能

由于不需要每次处理复杂逻辑耗时操作,比如加载网络并不需要都开启一个新的线程,可以用线程池处理,把线程存起来,用的时候在取出来,

在onDestory里去销毁线程,这样就会节省内存

//AsyncTask就是Handler和线程池的封装
//自定义线程池
public class ThreadManager {
	private ThreadManager() {
	}
	private static ThreadManager instance = new ThreadManager();
	private ThreadPoolProxy longPool;
	private ThreadPoolProxy shortPool;
	public static ThreadManager getInstance() {
		return instance;
	}
	// 联网比较耗时
	// 开启线程数一般是cpu的核数*2+1
	public synchronized ThreadPoolProxy createLongPool() {
		if (longPool == null) {
			longPool = new ThreadPoolProxy(5, 5, 5000L);
		}
		return longPool;
	}
	// 操作本地文件
	public synchronized ThreadPoolProxy createShortPool() {
		if(shortPool==null){
			shortPool = new ThreadPoolProxy(3, 3, 5000L);
		}
		return shortPool;
	}
	public class ThreadPoolProxy {
		private ThreadPoolExecutor pool;
		private int corePoolSize;
		private int maximumPoolSize;
		private long time;
		public ThreadPoolProxy(int corePoolSize, int maximumPoolSize, long time) {
			this.corePoolSize = corePoolSize;
			this.maximumPoolSize = maximumPoolSize;
			this.time = time;
		}
		/**
		 * 执行任务
		 * @param runnable
		 */
		public void execute(Runnable runnable) {
			if (pool == null) {
				// 创建线程池
				/*
				 * 1. 线程池里面管理多少个线程2. 如果排队满了, 额外的开的线程数3. 如果线程池没有要执行的任务 存活多久4.
				 * 时间的单位 5 如果 线程池里管理的线程都已经用了,剩下的任务 临时存到LinkedBlockingQueue对象中 排队
				 */
				pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
						time, TimeUnit.MILLISECONDS,
						new LinkedBlockingQueue<Runnable>(10));
			}
			pool.execute(runnable); // 调用线程池 执行异步任务
		}
		/**
		 * 取消任务
		 * @param runnable
		 */
		public void cancel(Runnable runnable) {
			if (pool != null && !pool.isShutdown() && !pool.isTerminated()) {
				pool.remove(runnable); // 取消异步任务
			}
		}
	}
}

三种静态

  • 静态内部类:尽量不要用一个生命周期长于Activity的对象来持有Activity的引用。声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放。在Activity中尽量避免使用生命周期不受控制的非静态类型的内部类,可以使用静态类型的内部类加上弱引用的方式实现。
  • 静态变量:不要直接或者间接引用Activity、Service等。这会使用Activity以及它所引用的所有对象无法释放,然后,用户操作时间一长,内存就会狂升。  
  • 静态引用:应该避免 static 成员变量引用资源耗费过多的实例,比如 Context。尽量使用 getApplicationContext:如果为了满足需求下必须使用 Context 的话:Context 尽量使用 Application Context,因为 Application 的 Context 的生命周期比较长,引用它不会出现内存泄露的问题,而不是activity的context,单例。可以通过调用 Context.getApplicationContext() or Activity.getApplication()来获得

Handler内存泄漏 Handler作为内部类存在于Activity中,但是Handler生命周期与Activity生命周期往往并不是相同的,比如当Handler对象有Message在排队,则无法释放,进而导致本该释放的Acitivity也没有办法进行回收。 解决办法:声明handler为static类,这样内部类就不再持有外部类的引用了,就不会阻塞Activity的释放

System.gc()

我们可以调用System.gc方法,建议虚拟机进行垃圾回收工作(注意,是建议,但虚拟机会不会这样干,我们也无法预知!)

下面来看一个例子来了解finalize()System.gc()的使用:

public class TestGC {  
    public TestGC() {}  
      
    //当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。  
    protected void finalize() {  
        System.out.println("我已经被垃圾回收器回收了...");  
    }  
      
    public static void main(String [] args) {  
        TestGC gc = new TestGC();  
        gc = null;    
        // 建议虚拟机进行垃圾回收工作  
        System.gc();  
    }  
}  

如上面的例子所示,大家可以猜猜重写的finalize方法会不会执行?

答案是:不一定

因为无论是设置gc的引用为null还是调用System.gc()方法都只是"建议"垃圾回收器进行垃圾回收,但是最终所有权还在垃圾回收器手中,它会不会进行回收我们无法预知!

AsynTask为什么要设计为只能够一次任务?

最核心的还是线程安全问题,多个子线程同时运行,会产生状态不一致的问题。所以要务必保证只能够执行一次

java中的soft reference

StrongReference 是 Java 的默认引用实现, 它会尽可能长时间的存活于 JVM 内, 当没有任何对象指向它时 GC 执行后将会被回收,SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证), 这一特性使得 SoftReference 非常适合缓存

内存溢出OOM解决方案?(解决方法)

内存缓存的时候可能内存溢出,因为Android默认给每个app只分配16M的内存,,每个手机不一样,我的手机是3G内存,分配的内存是29m,通过这样可以获得

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  

解决方法1:java中的引用(使用软引用)

    - 强引用 垃圾回收器不会回收, java默认引用都是强引用     - 软引用 SoftReference   在内存不够时,垃圾回收器会考虑回收     - 弱引用 WeakReference  在内存不够时,垃圾回收器会优先回收     - 虚引用 PhantomReference  在内存不够时,垃圾回收器最优先回收 注意: Android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用

内存中使用LRUCache是最合适的。如果用HashMap来实现,不是不可以,但需要注意在合适的时候释放缓存。至于具体怎么释放,我没考虑过,但用软引用的问题在于,你很难控制缓存的大小,也就是说,只有等到你的内存快要撑爆,你的图片缓存才会被回收。是不是感觉傻傻的?

 解决方法2:LruCache 

    least recentlly use 最少最近使用算法     会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定。他内部是是一个linkedhashmap以强引用的方式存储外界的缓存对象,提供了get,put方法来操作,当缓存满了,lru会移除较早使用的缓存对象,把新的添加进来。也可以自己remove  解决方法3:图片压缩

三级缓存

  • 先读取内存缓存, 因为优先加载, 速度最快,内存缓存没有再读取本地缓存, 次优先加载, 速度也快,本地没有再加载网络缓存, 速度慢,浪费流量在网络缓存中从网络下载图片,并且保存在本地和内存中,在下载的时候可以对图片进行压缩
  • 服务器端下载的图片是使用 Http的缓存机制,每次执行将本地图片的时间发送给服务器,如果俩次访问的时间间隔短,返回码是 304,会读取网络缓存(说明服务端的图片和本地的图片是相同的,直接使用本地保存的图片),如果返回码是 200,则开始下载新的图片并实现缓存。在从服务器获取到图片后,需要再在本地和内存中分别存一份,这样下次直接就可以从内存中直接获取了,这样就加快了显示的速度,提高了用户的体验。
  • 大量图片加载,当用户不停的滑动时,由于ui在主线程操作的,会出现卡顿,可以在滑动的时候停止加载(setOnscrollerListener),在getView方法里只有静止才加载图片
InputStream inputStream = conn.getInputStream();
				
				//图片压缩处理
				BitmapFactory.Options option = new BitmapFactory.Options();
				option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
				option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式
				
				Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
				return bitmap;
....

本地保存时可以将名字用MD5加密保存

// 将图片保存在本地,
			bitmap.compress(CompressFormat.JPEG, 100,
					new FileOutputStream(file));//100是质量
//取
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
						file));//decodeStream放的是输入输出流
				return bitmap;


Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
						file));//
				return bitmap;

内存缓存在保存的时候可以给图片分配内存

private LruCache<String, Bitmap> mMemoryCache;
	public MemoryCacheUtils() {
		long maxMemory = Runtime.getRuntime().maxMemory() / 8;//主流都是分配16m的8/1
		mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
			@Override
			protected int sizeOf(String key, Bitmap value) {
				int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小
				return byteCount;
			}
		};
	}

正常一张720x1080的图片在内存中占多少空间?怎么加载大图片?

看他的渲染方式,RGB888啥的,占用的字节不同的。

如果是一张的话压缩处理,大量图片的话用lru

图片的总大小 = 图片的总像素 * 每个像素占用的大小

加载大图片

  • 计算机把图片所有像素信息全部解析出来,保存至内存
  • Android保存图片像素信息,是用ARGB保存,所以每个像素占用4个字节,很容易内存溢出
  • 可以对图片的宽高和质量进行压缩 首先对图片进行缩放
    • 获取屏幕宽高 //设置缩放比例 opts.inSampleSize = scale; //为图片申请内存 opts.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts); iv.setImageBitmap(bm); int scale = 1; int scaleX = imageWidth / screenWidth; int scaleY = imageHeight / screenHeight; if(scaleX >= scaleY && scaleX > 1){ scale = scaleX; } else if(scaleY > scaleX && scaleY > 1){ scale = scaleY; } Options opts = new Options(); //请求图片属性但不申请内存 opts.inJustDecodeBounds = true; BitmapFactory.decodeFile("sdcard/dog.jpg", opts); int imageWidth = opts.outWidth; int imageHeight = opts.outHeight; Display dp = getWindowManager().getDefaultDisplay(); int screenWidth = dp.getWidth(); int screenHeight = dp.getHeight();
    • 获取图片宽高 //设置缩放比例 opts.inSampleSize = scale; //为图片申请内存 opts.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts); iv.setImageBitmap(bm); int scale = 1; int scaleX = imageWidth / screenWidth; int scaleY = imageHeight / screenHeight; if(scaleX >= scaleY && scaleX > 1){ scale = scaleX; } else if(scaleY > scaleX && scaleY > 1){ scale = scaleY; } Options opts = new Options(); //请求图片属性但不申请内存 opts.inJustDecodeBounds = true; BitmapFactory.decodeFile("sdcard/dog.jpg", opts); int imageWidth = opts.outWidth; int imageHeight = opts.outHeight;
    • 图片的宽高除以屏幕宽高,算出宽和高的缩放比例,取较大值作为图片的缩放比例,且大于1才缩放 //设置缩放比例 opts.inSampleSize = scale; //为图片申请内存 opts.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts); iv.setImageBitmap(bm); int scale = 1; int scaleX = imageWidth / screenWidth; int scaleY = imageHeight / screenHeight; if(scaleX >= scaleY && scaleX > 1){ scale = scaleX; } else if(scaleY > scaleX && scaleY > 1){ scale = scaleY; }

    2.然后按缩放比例加载图片 //设置缩放比例 opts.inSampleSize = scale; //为图片申请内存 opts.inJustDecodeBounds = false; Bitmap bm = BitmapFactory.decodeFile("sdcard/dog.jpg", opts); iv.setImageBitmap(bm);

如何在不失真的条件下显示一张超高清的图片或者长图

  • 针对这个问题,我自己一般用以下两种方法解决: 1、使用WebView来加载该图片; 2、使用MapView或者TileView来显示图片(类似地图的机制);

subsampling-scale-image-view

缩减APK包大小代码

  • 保持良好的编程习惯,不要重复或者不用的代码,谨慎添加libs,移除使用不到的libs。
  • 使用proguard混淆代码,它会对不用的代码做优化,并且混淆后也能够减少安装包的大小。
  • native code的部分,大多数情况下只需要支持armabi与x86的架构即可。如果非必须,可以考虑拿掉x86的部分。
  • 使用Lint工具查找没有使用到的资源。去除不使用的图片,String,XML等等。
  • assets目录下的资源请确保没有用不上的文件。
  • 生成APK的时候,aapt工具本身会对png做优化,但是在此之前还可以使用其他工具如tinypng对图片进行进一步的压缩预处理。
  • jpeg还是png,根据需要做选择,在某些时候jpeg可以减少图片的体积。
  • 对于9.png的图片,可拉伸区域尽量切小,另外可以通过使用9.png拉伸达到大图效果的时候尽量不要使用整张大图。
  • 有选择性的提供hdpi,xhdpi,xxhdpi的图片资源。建议优先提供xhdpi的图片,对于mdpi,ldpi与xxxhdpi根据需要提供有差异的部分即可。
  • 尽可能的重用已有的图片资源。例如对称的图片,只需要提供一张,另外一张图片可以通过代码旋转的方式实现。
  • 能用代码绘制实现的功能,尽量不要使用大量的图片。例如减少使用多张图片组成animate-list的AnimationDrawable,这种方式提供了多张图片很占空间

ListView的优化

  • 复用convertview , 历史的view对象
  • 减少子孩子查询的次数 viewholder
  • 异步加载数据(把图片缓存)
  • 条目多时分页加载数据
  • 加载时显示进度条让用户等待
  • Item的布局层次结构尽量简单,避免布局太深或者不必要的重绘
  • 避免在 getView 方法中做耗时的操作: 例如加载本地 Image 需要载入内存以及解析 Bitmap ,都是比较耗时的操作,如果用户快速滑动listview,会因为getview逻辑过于复杂耗时而造成滑动卡顿现象。用户滑动时候不要加载图片,待滑动完成再加载,可以使用这个第三方库glide
  • 应该尽量避免 static 成员变量引用资源耗费过多的实例,比如 Context。
  • 尽量使用 getApplicationContext:如果为了满足需求下必须使用 Context 的话:Context 尽量使用 Application Context,因为Application 的 Context 的生命周期比较长,引用它不会出现内存泄露的问题
  • 在一些场景中,ScollView内会包含多个ListView,可以把listview的高度写死固定下来。 由于ScollView在快速滑动过程中需要大量计算每一个listview的高度,阻塞了UI线程导致卡顿现象出现,如果我们每一个item的高度都是均匀的,可以通过计算把listview的高度确定下来,避免卡顿现象出现
  • 使用 RecycleView 代替listview: 每个item内容的变动,listview都需要去调用notifyDataSetChanged来更新全部的item,太浪费性能了。RecycleView可以实现当个item的局部刷新,并且引入了增加和删除的动态效果,在性能上和定制上都有很大的改善
  • ListView 中元素避免半透明: 半透明绘制需要大量乘法计算,在滑动时不停重绘会造成大量的计算,在比较差的机子上会比较卡。 在设计上能不半透明就不不半透明。实在要弄就把在滑动的时候把半透明设置成不透明,滑动完再重新设置成半透明。
  • 尽量开启硬件加速: 硬件加速提升巨大,避免使用一些不支持的函数导致含泪关闭某个地方的硬件加速。当然这一条不只是对 ListView。

布局的优化

  • 尽量重用一个布局文件,使用include标签,多个相同的布局可以复用
  • 减少一个布局的不必要节点
  • 尽量使用view自身的参数,例如:Button,有一个可以把图绘制在左边的参数:android:drawableLeft
  • 使用< ViewStub />标签来加载一些不常用的布局;使用< merge />标签减少布局的嵌套层次

ViewPager的优化

  • viewpager会默认加载左右俩个页面,有时候我们并不想看,会浪费用户的流量,可以在setOnPageChangeListener的onPageSelected的方法里选中哪个页面,初始化哪个页面
  • 由于viewpager会默认销毁第三页面,可以强制让viewpager加载所有的页面pagerView.setOffscreenPageLimit(pageCount);,但是如果页面多的话就不能这样干了
  • 可以定义一个集合将页面缓存起来,在destroyItem的时候保存起来,在instantiateItem读取集合,有就用,没有的话再创建,就像listview的convertView似的
	class HomeAdapter extends PagerAdapter {
		// 当前viewPager里面有多少个条目
		LinkedList<ImageView> convertView=new LinkedList<ImageView>();
		@Override
		public int getCount() {
			return	Integer.MAX_VALUE;
		}
		/* 判断返回的对象和 加载view对象的关系 */
		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			return arg0 == arg1;
		}
		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			ImageView view=(ImageView) object;
			convertView.add(view);// 把移除的对象 添加到缓存集合中
			container.removeView(view);
		}
		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			ImageView view;
			if(convertView.size()>0){
				view=convertView.remove(0);
			}else{
				view= new ImageView(UiUtils.getContext());
			}
			bitmapUtils.display(view, HttpHelper.URL + "image?name="
					+ datas.get(index));
			container.addView(view); // 加载的view对象
			return view; // 返回的对象
		}
	}

内存的优化

  •  回收已经使用的资源,比如游标cursor 、I/O、Bitmap(close并且引用置为null)
  •   合理的使用缓存,比如图片是很耗内存的,使用lru缓存图片和压缩
  • 合理设置变量的作用范围
  • 节制的使用服务,后台任务运行完,即使它不执行任何操作,服务也会一直运行,这些是十分消耗内存的,可以用intentservice
  • 当界面不可见时释放内存,在activity的onTrimMemory方法里与ui的相关资源,在onstop里释放与组件相关的资源
  • 合理的使用多进程,如果后台任务和前台界面是相互独立在,可以在组件标签下写process,这样这个组建就在另一个进程里了。而服务的话更倾向于开启自己所依赖的进城,而那个进程可能很多东西都不需要,比如ui
  • 使用线程池、对象池
  • Bitmap对象在不使用时,应该先调用recycle()释放内存,然后才它设置为null。

代码优化

这部分就是是细微的优化,但是细微多了也就内存节约了

任何一个Java类,包括内部类、匿名类,都要占用大概500字节的内存空间。 任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程序上影响内存的,所以要避免创建不必要的对象

  1. 如果有一个需要拼接的字符串,那么可以优先考虑使用StringBuffer或者StringBuilder来进行拼接,而不是加号连接符,因为使用加号连接符会创建多余的对象,拼接的字符串越长,加号连接符的性能越低
  2. 尽量使用基本数据类来代替封装数据类型,int比Integer要更加高效,其它数据类型也是一样

使用静态

  1. 使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中应当尽可能地不使用枚举。
  2. 如果你并不需要访问一个对象中的某些字段,只是想调用它的某个方法来去完成一项通用的功能,那么可以将这个方法设置成静态方法,这会让调用的速度提升15%-20%,同时也不用为了调用这个方法而去专门创建对象了,这样还满足了上面的一条原则。另外这也是一种好的编程习惯,因为我们可以放心地调用静态方法,而不用担心调用这个方法后是否会改变对象的状态(静态方法内无法访问非静态字段)

对常量使用static final修饰符

使用增强型for循环语法

多使用系统封装好的API,比如:indexOf(),System.arraycopy()

  性能优化:尽量使用drawable对象保存图片而不是bitmap

drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png");

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java 成神之路

spring 之 import标签、alias标签、beans标签 解析

58610
来自专栏我和未来有约会

如何在silverlihgt中使用右键

一般我们在silverlight中点击右键会出现如下的对话筐. ? ? 在flash中 其提供了一个可定制话的右键菜单系统.(ContextMenu) 这个...

2117
来自专栏木宛城主

Unity应用架构设计(3)——构建View和ViewModel的生命周期

对于一个View而言,本质上是一个MonoBehaviour。它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等。...

2415
来自专栏飞雪无情的博客

Go语言实战笔记(二十)| Go Context

控制并发有两种经典的方式,一种是WaitGroup,另外一种就是Context,今天我就谈谈Context。

1983
来自专栏Pythonista

牛掰的python与unix

  加载subprocess模块仅仅是将可以使用的代码文件加载进来。也可以创建自己的模块或文件,拱以后重复使用,这与加载subprocess模块的方法相同。IP...

1162
来自专栏屈定‘s Blog

设计模式--适配器模式的思考

个人认为适配器模式是一种加中间层来解决问题的思想,为的是减少开发工作量,提高代码复用率.另外在对于第三方的服务中使用适配器层则可以很好的把自己系统与第三方依赖解...

1235
来自专栏Golang语言社区

GoLang并发控制(下)

context的字面意思是上下文,是一个比较抽象的词,字面上理解就是上下层的传递,上会把内容传递给下,在go中程序单位一般为goroutine,这里的上下文便是...

3253
来自专栏潇涧技术专栏

Android Heroes Reading Notes 4

《Android群英传》读书笔记 (4) 第八章 Activity和Activity调用栈分析 + 第九章 系统信息与安全机制 + 第十章 性能优化

791
来自专栏葡萄城控件技术团队

Wijmo 更优美的jQuery UI部件集:导出Wijmo的GridView到Excel

Wijmo GridView 控件不提供导出Excel文件的方法。本篇博客介绍一种将Wijmo的GridView控件保存到Excel的简单方法。你可以使用同样的...

2588
来自专栏Android 开发学习

data-binding 踩坑记

2114

扫码关注云+社区

领取腾讯云代金券