首页 文章 精选 留言 我的

精选列表

搜索[android studio],共10000篇文章
优秀的个人博客,低调大师

【Android开发坑系列】之经常被忽略的背景图片内存泄露

我们平时设置图片的时候,几乎都忘记回收老的(背景)图片,比如: TextView.setBackgroundDrawable() TextView.setBackgroundResource() ImageView.setImageDrawable() ImageView.setImageResource() ImageView.setImageBitmap() 这样造成内存浪费,积少成多,整个软件可能浪费不少内存。 如果记得优化,整个软件的内存占用会有10%~20%的下降。 // 获得ImageView当前显示的图片 Bitmap bitmap1 = ((BitmapDrawable) imageView.getBackground()).getBitmap(); Bitmap bitmap2 = Bitmap.createBitmap(bitmap1, 0, 0, bitmap1.getWidth(),bitmap1.getHeight(), matrix, true); // 设置新的背景图片 imageView.setBackgroundDrawable(new BitmapDrawable(bitmap2)); // bitmap1确认即将不再使用,强制回收,这也是我们经常忽略的地方 if (!bitmap1.isRecycled()) { bitmap1.recycle(); } 看上面的代码,设置新的背景之后,老的背景确定不再使用,则应该回收。 封装如下(仅针对setBackgroundXXX做了封装,其他的原理类同): /** * 给view设置新背景,并回收旧的背景图片<br> * <font color=red>注意:需要确定以前的背景不被使用</font> * * @param v */ @SuppressWarnings("deprecation") public static void setAndRecycleBackground(View v, int resID) { // 获得ImageView当前显示的图片 Bitmap bitmap1 = null; if (v.getBackground() != null) { try { //若是可转成bitmap的背景,手动回收 bitmap1 = ((BitmapDrawable) v.getBackground()).getBitmap(); } catch (ClassCastException e) { //若无法转成bitmap,则解除引用,确保能被系统GC回收 v.getBackground().setCallback(null); } } // 根据原始位图和Matrix创建新的图片 v.setBackgroundResource(resID); // bitmap1确认即将不再使用,强制回收,这也是我们经常忽略的地方 if (bitmap1 != null && !bitmap1.isRecycled()) { bitmap1.recycle(); } } /** * 给view设置新背景,并回收旧的背景图片<br> * <font color=red>注意:需要确定以前的背景不被使用</font> * * @param v */ @SuppressWarnings("deprecation") public static void setAndRecycleBackground(View v, BitmapDrawable imageDrawable) { // 获得ImageView当前显示的图片 Bitmap bitmap1 = null; if (v.getBackground() != null) { try { //若是可转成bitmap的背景,手动回收 bitmap1 = ((BitmapDrawable) v.getBackground()).getBitmap(); } catch (ClassCastException e) { //若无法转成bitmap,则解除引用,确保能被系统GC回收 v.getBackground().setCallback(null); } } // 根据原始位图和Matrix创建新的图片 v.setBackgroundDrawable(imageDrawable); // bitmap1确认即将不再使用,强制回收,这也是我们经常忽略的地方 if (bitmap1 != null && !bitmap1.isRecycled()) { bitmap1.recycle(); } } 本文转自Kai的世界,道法自然博客园博客,原文链接:http://www.cnblogs.com/kaima/p/3497525.html,如需转载请自行联系原作者。

优秀的个人博客,低调大师

[Android]Activity跳转传递任意类型的数据、Activity为SingleTask时代替StartActivityForRes...

以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/4389674.html 需求:在ActivityA跳转到ActivityB,然后在ActivityB操作完返回数据给ActivityA。 这个很普遍的需求,一般情况是使用startActivityForResult的方式去完成。 但是当ActivityB为SingleTask时,这个方式就无效了。你会发现当你执行startActivityForResult后,onActivityResult方法马上就会被回调。至于为什么会出现这种情况,参考这位老兄的文章就可以理解http://blog.csdn.net/sodino/article/details/22101881。 解决这种情况的方法,第一种是把ActivityA也设置为SingleTask,然后在ActivityB中startActivity(context, ActivityA.class),然后ActivityA在onNewIntent(Intent intent)方法中去获取传递数据,这样的方式不仅破坏了ActivityA的lauchMode,而且还需要ActivityB中启动指定的ActivityA。 所以,如果能把ActivityA的当前对象(实现某个接口)传到ActivityB中,然后ActivityB中通过接口直接回调那就解决问题了。 但是问题是怎么把当前对象传过去,使用Intent显然不行。 思路是维护一个StoragePool,里面可以暂存需要传递的数据。相当于一个暂存区,ActivityA跳转前,把数据放入这个暂存区,获得一个唯一标识,然后把这个唯一标识使用Intent的方式传递给ActivityB,然后ActivityB拿到这个唯一标识后去暂存区去取数据就好了。 暂存区StoragePool代码如下: 1 /** 2 * Author: wangjie 3 * Email: tiantian.china.2@gmail.com 4 * Date: 3/30/15. 5 */ 6 public class StoragePool { 7 /** 8 * key -- 标识是哪一个intent的(UUID) 9 * 10 * |- key -- 存储的对象标识(StorageKey,使用UUID唯一) 11 * value --| 12 * |- value -- 存储的内容 13 */ 14 private static ConcurrentHashMap<String, HashMap<StorageKey, WeakReference<Object>>> storageMapper = new ConcurrentHashMap<>(); 15 16 private StoragePool() { 17 } 18 19 public static void storage(String tagUUID, StorageKey key, Object content) { 20 if (null == key || null == content) { 21 return; 22 } 23 HashMap<StorageKey, WeakReference<Object>> extraMapper = storageMapper.get(tagUUID); 24 if (null == extraMapper) { 25 extraMapper = new HashMap<>(); 26 storageMapper.put(tagUUID, extraMapper); 27 } 28 extraMapper.put(key, new WeakReference<>(content)); 29 } 30 31 public static Object remove(String tagUUID, StorageKey key) { 32 if (null == key) { 33 return null; 34 } 35 HashMap<StorageKey, WeakReference<Object>> extraMapper = storageMapper.get(tagUUID); 36 if (null == extraMapper) { 37 return null; 38 } 39 40 WeakReference<Object> ref = extraMapper.remove(key); 41 if (ABTextUtil.isEmpty(extraMapper)) { 42 storageMapper.remove(tagUUID); 43 } 44 return null == ref ? null : ref.get(); 45 } 46 47 public static HashMap<StorageKey, WeakReference<Object>> remove(String tagUUID) { 48 if (null == tagUUID) { 49 return null; 50 } 51 return storageMapper.remove(tagUUID); 52 } 53 54 public static void clear() { 55 storageMapper.clear(); 56 } 57 58 } 如上代码,StoragePool维护了一个HashMap,key是一个UUID,代表唯一的一个Intent跳转,ActivityA跳转时会把这个UUID传递到ActivityB,ActivityB就是通过这个UUID来获取这次跳转需要传递的数据的。value也是一个HashMap,里面存储了某次跳转传递的所有数据。key是StorageKey,实质上也是一个UUID,value是任意的数据。 跳转前的存储数据和真正的StartActivity都需要使用StorageIntentCenter来进行操作,代码如下: 1 /** 2 * Author: wangjie 3 * Email: tiantian.china.2@gmail.com 4 * Date: 3/31/15. 5 */ 6 public class StorageIntentCenter { 7 public static final String STORAGE_INTENT_CENTER_KEY_UUID = StorageIntentCenter.class.getSimpleName() + "_UUID"; 8 private static final String TAG = StorageIntentCenter.class.getSimpleName(); 9 10 private Intent intent; 11 private String uuid; 12 private HashMap<StorageKey, Object> extras; 13 private boolean isUsed; 14 public StorageIntentCenter() { 15 intent = new Intent(); 16 uuid = java.util.UUID.randomUUID().toString(); 17 intent.putExtra(STORAGE_INTENT_CENTER_KEY_UUID, uuid); 18 isUsed = false; 19 } 20 21 public StorageIntentCenter putExtra(String intentKey, Object content){ 22 if (null == content) { 23 return this; 24 } 25 StorageKey storageKey = new StorageKey(content.getClass()); 26 intent.putExtra(intentKey, storageKey); 27 if(null == extras){ 28 extras = new HashMap<>(); 29 } 30 extras.put(storageKey, content); 31 return this; 32 } 33 34 public void startActivity(Context packageContext, Class<?> cls){ 35 if(isUsed){ 36 Logger.e(TAG, this + " can not be reuse!"); 37 return; 38 } 39 intent.setClass(packageContext, cls); 40 if(!ABTextUtil.isEmpty(extras)){ 41 Set<Map.Entry<StorageKey, Object>> entrySet = extras.entrySet(); 42 for(Map.Entry<StorageKey, Object> entry : entrySet){ 43 StoragePool.storage(uuid, entry.getKey(), entry.getValue()); 44 } 45 } 46 isUsed = true; 47 packageContext.startActivity(intent); 48 } 49 50 51 } 每个StorageIntentCenter都维护了一个真正跳转的Intent,一个此次跳转的uuid和所有需要传递的数据。 使用方式(以从MainActivity跳转到OtherActivity为例): MainActivity中: @AILayout(R.layout.main) public class MainActivity extends BaseActivity implements ICommunicate { private static final String TAG = MainActivity.class.getSimpleName(); @Override @AIClick({R.id.ac_test_a_btn}) public void onClickCallbackSample(View view) { switch (view.getId()) { case R.id.ac_test_a_btn: new StorageIntentCenter() .putExtra("iCommunicate", this) .putExtra("testString", "hello world") .putExtra("testFloat", 3.2f) .startActivity(context, OtherActivity.class); break; } } @Override public void hello(String content) { Logger.d(TAG, "hello received: " + content); } } OtherActivity继承了BaseActivity。 BaseActivity: 1 /** 2 * Author: wangjie 3 * Email: tiantian.china.2@gmail.com 4 * Date: 4/2/15. 5 */ 6 public class BaseActivity extends AIActivity { 7 private String storageIntentCenterUUID; 8 9 @Override 10 protected void onCreate(Bundle savedInstanceState) { 11 super.onCreate(savedInstanceState); 12 13 initExtraFromStorage(); 14 // remove extra from StoragePool 15 StoragePool.remove(storageIntentCenterUUID); 16 } 17 18 protected void initExtraFromStorage() { 19 } 20 21 protected final <T> T getExtraFromStorage(String key, Class<T> contentType) { 22 StorageKey storageKey = (StorageKey) getIntent().getSerializableExtra(key); 23 if (null == storageIntentCenterUUID) { 24 storageIntentCenterUUID = getIntent().getStringExtra(StorageIntentCenter.STORAGE_INTENT_CENTER_KEY_UUID); 25 } 26 return (T) StoragePool.remove(storageIntentCenterUUID, storageKey); 27 } 28 29 } Line15:为了防止跳转到OtherActivity后,如果没有去暂存区把数据取出来从而导致暂存区有无用的数据(甚至内存泄漏,暂存区使用软引用也是为了防止这种情况的发生),所以这里提供一个initExtraFromStorage方法让子类重写,子类可以在这个方法中去把数据取出来。然后在initExtraFromStorage方法执行完毕后,再及时把暂存区的数据删除。 Line21~27:这里提供了从暂存区提取数据的方法供子类调用。 OtherActivity: /** * Author: wangjie * Email: tiantian.china.2@gmail.com * Date: 4/2/15. */ @AILayout(R.layout.other) public class OtherActivity extends BaseActivity{ private static final String TAG = OtherActivity.class.getSimpleName(); private ICommunicate iCommunicate; private String testString; private Float testFloat; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void initExtraFromStorage() { iCommunicate = getExtraFromStorage("iCommunicate", ICommunicate.class); testString = getExtraFromStorage("testString", String.class); testFloat = getExtraFromStorage("testFloat", Float.class); } @Override @AIClick({R.id.other_btn}) public void onClickCallbackSample(View view) { switch(view.getId()){ case R.id.other_btn: if(null == iCommunicate){ return; } Logger.d(TAG, "iCommunicate: " + iCommunicate); iCommunicate.hello("content from ACTestBActivity!"); Logger.d(TAG, "testString: " + testString); Logger.d(TAG, "testFloat: " + testFloat); finish(); break; } } } 如上代码OtherActivity中获取了从MainActivity中传递过来的MainActivity实例,在点击事件发生后通过MainActivity实例进行直接回调。 日志打印如下: 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/OtherActivity﹕ iCommunicate: com.wangjie.androidstorageintent.sample.MainActivity@42879ff8 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/MainActivity﹕ hello received: content from ACTestBActivity! 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/OtherActivity﹕ testString: hello world 04-03 12:09:52.184 25529-25529/com.wangjie.androidstorageintent D/OtherActivity﹕ testFloat: 3.2 MainActivity被回调,并获取了数据“content from ACTestBActivity!”字符串。 注: 1. 以上使用的代码已托管到github:https://github.com/wangjiegulu/AndroidStorageIntent 2. 上面的注解实现使用AndroidInject:https://github.com/wangjiegulu/androidInject 本文转自天天_byconan博客园博客,原文链接:http://www.cnblogs.com/tiantianbyconan/p/4389674.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

【硬创邦】跟hoowa学做智能路由(十三):网络音箱之Android篇

我们继续网络音箱的专题,这章将介绍安卓系统下的MP标准软件控制路由器播放音乐。 什么是MP MP全称为音乐播放进程(Music Player Daemon)。它是一个可定制化功能强大的服务端播放音乐软件,通过其自身的插件和库系统即可完成通过网络控制播放音乐。MP具备一个自己的控制管理协议,这些协议是基于TCP协议进行传输的。客户端连接到服务器上控制服务端进行处理。MPD表示服务端,MPC表示客户端。 MP是一个完全开放源代码的整体系统,因此有很多操作系统下的客户端,在安卓手机中即可使用MPDroid这个软件控制服务端播放,而如果您需要开发自己的产品,完全可以参考官方的资料自己开发一个控制程序,甚至给服务端增加新的功能。 使用MP的好处是,只要你的手机连接到家里的路由器上既可以控制播放音乐,而手机还随身携带,这样不影响你扫地啊、

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册