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

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

布局文件:

<?  version=\"1.0\" encoding=\"utf-8\"?>
<RelativeLayout  ns:android=\"http://schemas.android.com/apk/res/android\"
  android:layout_width=\"match_parent\"
  android:layout_height=\"match_parent\"
   ns: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. 中创建透明样式:

<!-- 网络加载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:windowNo \">true</item>
  </style>

AndroidManifest. 中设置样式:

<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.set Listener(new View. Listener() {
      @Override
      public void  (View v) {
        netWaitDialog.show();
        handler.postDelayed(new Runnable(){
          @Override
          public void run() {
            netWaitDialog.dismiss();
          }
        }, 3000);
      }
    });
    gotwo.set Listener(new View. Listener() {
      @Override
      public void  (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. ;
 
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();
    }
  }
}

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

收藏 打印