Android单一实例全局可调用网络加载弹窗

 更新时间:2018年12月10日 15:00:56   作者:WWGtest  
这篇文章主要为大家详细介绍了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效果

    这篇文章主要为大家详细介绍了Android实现底部半透明弹出框PopUpWindow效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-07-07
  • Flutter实现自定义搜索框AppBar的示例代码

    Flutter实现自定义搜索框AppBar的示例代码

    开发中,页面头部为搜索样式的设计非常常见,为了可以像系统AppBar那样使用,本文将利用Flutter自定义一个搜索框,感兴趣的可以了解一下
    2022-04-04
  • Android 处理空列表的方法(必看篇)

    Android 处理空列表的方法(必看篇)

    下面小编就为大家带来一篇Android 处理空列表的方法(必看篇)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-04-04
  • Android开发之天气趋势折线图

    Android开发之天气趋势折线图

    在开发天气APP的时候会要显示多天的信息,所以加一个折线图来显示一下天气变化趋势是很不错的效果,本文详细介绍了开发过程,下面一起来看看。
    2016-08-08
  • 详解Android中Drawable方法

    详解Android中Drawable方法

    这篇文章主要为大家详细介绍了Android中Drawable方法,感兴趣的朋友可以参考一下
    2016-05-05
  • Cocos2d-x的内存管理总结

    Cocos2d-x的内存管理总结

    这篇文章主要介绍了Cocos2d-x的内存管理总结,详解探讨了手工对象内存管理、自动对象内存管理、自动释放的时机等问题,需要的朋友可以参考下
    2014-04-04
  • zxing二维码位矩阵转换成Bitmap位图的实战教程

    zxing二维码位矩阵转换成Bitmap位图的实战教程

    二维码的应用已经可以说是非常广泛了,下面这篇文章主要给大家介绍了关于zxing二维码位矩阵转换成Bitmap位图的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • Android实现读写JSON数据的方法

    Android实现读写JSON数据的方法

    这篇文章主要介绍了Android实现读写JSON数据的方法,以完整实例形式分析了Android解析及生成json数据的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • Android编程实现Listview点击展开和隐藏的方法

    Android编程实现Listview点击展开和隐藏的方法

    这篇文章主要介绍了Android编程实现Listview点击展开和隐藏的方法,涉及Android中Listview的响应点击与样式变换相关操作技巧,需要的朋友可以参考下
    2015-12-12
  • 全面解析Android之ANR日志

    全面解析Android之ANR日志

    不论从事安卓应用开发,还是安卓系统研发,应该都遇到应用无响应(简称ANR)问题,当应用程序一段时间无法及时响应,则会弹出ANR对话框,让用户选择继续等待,还是强制关闭。本文将带你全面解析Android之ANR日志
    2021-06-06

最新评论