最近因為項目需求,需要完成一個全局的網絡加載彈窗需求,真正完成這個需求之后,感覺最重要的不是結果,而是思維。
我剛開始接到這個需求的時候,第一種想到的方案是 基類加單例。但是實際做起來之后發現,因為單例的原因,你的彈窗只能在第一次創建這個單例的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();
}
}
}
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。