Android单一实例全局可调用网络加载弹窗
最近因为项目需求,需要完成一个全局的网络加载弹窗需求,真正完成这个需求之后,感觉最重要的不是结果,而是思维。
我刚开始接到这个需求的时候,第一种想到的方案是 基类加单例。但是实际做起来之后发现,因为单例的原因,你的弹窗只能在第一次创建这个单例的activity中显示出来。
那么发现这个问题之后在这个的基础上改进一下,如果我不用activity的上下文,而是采用类似于application的一种全局上下文呢?当然,个人能力有限,这种想法就给毙掉了,后来由导师指点,利用service的上下文,dialog的style设置为系统级弹窗,那么这时候就会有一种潜在的情况,如果app退到后台的话,加载网络的时候不管用户在那个页面,都会显示这个弹窗,严重影响用户体验。
后来把思路又回到起点,需要实现两个点,一:全局可调用。二:单一实例。
总结一下遇到的问题:
一、dialog必须依赖activity
二、因为单例的原因,dialog只能在第一次创建单例的activity显示
三、不能使用系统级弹窗
ok,基于这些问题和要求,结合自己所掌握的知识。
dialog必须依赖activity,那我就创建一个activity,专门去承载这个dialog,activity背景设置为透明,效果达到。
这时又会出现新的问题,如果在单例中去开启这个activity,那么就会有很多dialog对象,违反初衷,如果在单例中创建dialog,那么开启activity的时候又会有很多intent对象,得不偿失。解决方法,创建两个单例,保证intent对象和dialog对象都保持唯一。
实际测试发现,第一次可以正常显示,第二次就会崩溃。
原因:当activity被销毁,又重新创建的时候,上下文会改变。因为单例的原因,你dialog的上下文还是第一次activity被创建时候的上下文,那么你再次调用这个dialog的时候,就会报activity不存在的异常。
到这里似乎没有办法解决了。
再次思考这个问题,突然灵光一闪,为什么我非要用dialog呢?我既然已经创建出一个专门承载这个dialog的activity了,而且activity的死活是完全和dialog一致的,那么我为什么还要再去创建一个dialog呢?直接把dialog的布局写在activity里不行吗?当外部去创建这个activity的时候直接播放动画,同时提供一个暴露给外部的关闭方法。而且这样也能用单例保证这个activity实例的单一性。
想到就去做,经过尝试和优化,问题完美解决。
下面是具体实现代码:
要显示的activity:
public class netwaitdialogactivity extends appcompatactivity { @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_net_wait_dialog); //将activity实例添加到appmanager的堆栈 myactivitymanager.getappmanager().addactivity(this); transparentstatusbar(); simpledraweeview netwait_dialog_gif = (simpledraweeview) findviewbyid(r.id.netwait_dialog_gif); //展示动图 draweecontroller draweecontroller_phone_wait = fresco.newdraweecontrollerbuilder() .setautoplayanimations(true) //设置uri,加载本地的gif资源 .seturi(uri.parse("res://"+this.getpackagename()+"/"+r.drawable.wait)) .build(); netwait_dialog_gif.setcontroller(draweecontroller_phone_wait); } /** * 透明状态栏 */ private void transparentstatusbar() { viewgroup contentframelayout = (viewgroup) findviewbyid(window.id_android_content); view parentview = contentframelayout.getchildat(0); if (parentview != null && build.version.sdk_int >= 14) { parentview.setfitssystemwindows(true); getwindow().getdecorview().setsystemuivisibility(view.system_ui_flag_layout_fullscreen | view.system_ui_flag_light_status_bar); } } @override protected void ondestroy() { super.ondestroy(); log.d("网络加载弹窗", "netwaitdialogactivity.ondestroy"); } public static void dismiss(){ log.d("网络加载弹窗", "调用dismiss()方法"); if (myactivitymanager.getappmanager().isactivityexist(netwaitdialogactivity.class)){ //结束指定类名的activity log.d("网络加载弹窗", "调用activity管理工具结束activity"); myactivitymanager.getappmanager().finishactivity(netwaitdialogactivity.class); } else { log.d("网络加载弹窗", "指定类不存在,调用备用方法"); if (((activity)netwaitdialogcontext).isfinishing() || ((activity)netwaitdialogcontext).isdestroyed()) { log.d("网络加载弹窗", "网络加弹窗不存在"); } else { log.d("网络加载弹窗", "调用强制关闭"); ((activity)netwaitdialogcontext).finish(); } } } }
布局文件:
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:fresco="http://schemas.android.com/apk/res-auto"> <com.facebook.drawee.view.simpledraweeview android:id="@+id/netwait_dialog_gif" android:layout_width="360dp" android:layout_height="100dp" android:layout_centerinparent="true" fresco:roundedcornerradius="20dp"></com.facebook.drawee.view.simpledraweeview> </relativelayout>
style.xml中创建透明样式:
<!-- 网络加载activity背景 --> <style name="transparent" parent="theme.appcompat.light.noactionbar"> <item name="android:windowbackground">@android:color/transparent</item> <item name="android:windowistranslucent">true</item> <item name="android:windowanimationstyle">@android:style/animation</item> <item name="android:windownotitle">true</item> </style>
androidmanifest.xml中设置样式:
<activity android:name=".netwaitdialogactivity" android:theme="@style/transparent"></activity>
单例工具类:
public class netwaitstatusutils { private static netwaitstatusutils instance; private intent intent; private context context; private netwaitstatusutils(context context) { this.context = context; intent = new intent(context, netwaitdialogactivity.class); } public static netwaitstatusutils getinstance(context context) { if (instance == null) { instance = new netwaitstatusutils(context); } return instance; } public void show(){ context.startactivity(intent); } public void dismiss(){ netwaitdialogactivity.dismiss(); } }
在基类中获取实例:
netwaitdialog = netwaitstatusutils.getinstance(getapplication());
外部调用:
public class mainactivity extends iactivity { private handler handler = new handler(); @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); button load = findviewbyid(r.id.load); button gotwo = findviewbyid(r.id.gotwo); load.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { netwaitdialog.show(); handler.postdelayed(new runnable(){ @override public void run() { netwaitdialog.dismiss(); } }, 3000); } }); gotwo.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { startactivity(new intent(mainactivity.this,main2activity.class)); finish(); } }); } @override protected int getlayoutid() { return r.layout.activity_main; } }
这里还有一点需要注意,就是activity的启动模式,推荐使用singletask。但是这样也会有一个弊端,就是它会把自它到栈顶的所有activity实例都销毁,具体大家可以自行百度。
我这里是用到一个activity的管理类:
package com.example.a9focus.sxt.base; import android.annotation.targetapi; import android.app.activity; import android.app.activitymanager; import android.content.context; import android.os.build; import android.util.log; import java.util.stack; /** * created by hxy on 18-12-1. */ public class myactivitymanager { private static stack<activity> activitystack; private static myactivitymanager instance; private myactivitymanager(){} /** * 单一实例 */ public static myactivitymanager getappmanager(){ if(instance==null){ instance=new myactivitymanager(); } return instance; } /** * 添加activity到堆栈 */ public void addactivity(activity activity){ if(activitystack==null){ activitystack=new stack<activity>(); } activitystack.add(activity); log.d("myactivitymanager", activitystack.tostring()); } /** * 获取当前activity(堆栈中最后一个压入的) */ public activity currentactivity(){ activity activity=activitystack.lastelement(); return activity; } /** * 结束当前activity(堆栈中最后一个压入的) */ public void finishactivity(){ activity activity=activitystack.lastelement(); if(activity!=null){ activity.finish(); activity=null; } } /** * 结束指定的activity */ public void finishactivity(activity activity){ if(activity!=null){ activitystack.remove(activity); activity.finish(); activity=null; } } /** * 结束指定类名的activity */ public void finishactivity(class<?> cls){ // try { for (activity activity : activitystack) { if(activity.getclass().equals(cls) ){ finishactivity(activity); } } // }catch (exception e){ // log.d("myactivitymanager", "指定类不存在"); // } } /** * 判断一个activity 是否存在 * * @param clz * @return */ @targetapi(build.version_codes.jelly_bean_mr1) public boolean isactivityexist(class<?> clz) { boolean res; activity activity = getactivity(clz); if (activity!=null) log.d("myactivitymanager", "判断是否存在的activity实例 --> "+activity.tostring()); if (activity == null) { res = false; } else { if (activity.isfinishing() || activity.isdestroyed()) { res = false; } else { res = true; } } log.d("myactivitymanager", "指定activity存在状态" + res); return res; } /** * 获得指定activity实例 * * @param clazz activity 的类对象 * @return */ public activity getactivity(class<?> clazz) { activity returnactivity = null; for (activity activity : activitystack) { if(activity.getclass().equals(clazz) ){ returnactivity = activity; return returnactivity; } } return null; } /** * 结束所有activity */ public void finishallactivity(){ for (int i = 0, size = activitystack.size(); i < size; i++){ if (null != activitystack.get(i)){ activitystack.get(i).finish(); } } activitystack.clear(); } /** * 退出应用程序 */ public void appexit(context context) { try { finishallactivity(); activitymanager activitymgr= (activitymanager) context.getsystemservice(context.activity_service); activitymgr.restartpackage(context.getpackagename()); system.exit(0); } catch (exception e) { e.printstacktrace(); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: Android实现悬浮窗体效果
下一篇: 去日本旅行 拼死也要品茶美味的河豚