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实现底部半透明弹出框PopUpWindow效果
这篇文章主要为大家详细介绍了Android实现底部半透明弹出框PopUpWindow效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2017-07-07
最新评论