欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-02-07 15:15:06
最近因为项目需求,需要完成一个全局的网络加载弹窗需求,真正完成这个需求之后,感觉最重要的不是结果,而是思维。 我刚开始接到这个需求的时候,第一种想到的方案是 基类加单例。...

最近因为项目需求,需要完成一个全局的网络加载弹窗需求,真正完成这个需求之后,感觉最重要的不是结果,而是思维。

我刚开始接到这个需求的时候,第一种想到的方案是 基类加单例。但是实际做起来之后发现,因为单例的原因,你的弹窗只能在第一次创建这个单例的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();
  }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。