2017-03-07 82 views
2

當應用程序離線時,我在應用程序的底部添加了一個小的TextView。所以我有一個BroadcastReceiver監視網絡連接變化,並在onReceive,我顯示的橫幅。這裏是一個對現有的視圖的頂部增加了TextView旗幟類:WindowManager addView - Android 7.1.1

public static void show() { 
     if (!isShowing && !isAppBackgrounded()) { 
      MyApplication app = MyApplication.getInstance(); 
      WindowManager windowManager = (WindowManager) app.getSystemService(Context.WINDOW_SERVICE); 
      Resources res = app.getResources(); 
      TextView offlineTv = app.getOfflineTv(); 

      if (offlineTv.getWindowToken() != null) { 
       return; 
      } 

      offlineTv.setText("Offline"); 
      offlineTv.setTextColor(ContextCompat.getColor(app, R.color.yellow)); 
      offlineTv.setGravity(Gravity.CENTER); 
      offlineTv.setBackgroundColor(ContextCompat.getColor(app, R.color.dark_grey)); 
      offlineTv.setTextSize(TypedValue.COMPLEX_UNIT_SP, app.getResources().getInteger(R.integer.offline_banner_text_size)); 

      WindowManager.LayoutParams params = createLayoutParams(WindowManager.LayoutParams.TYPE_TOAST, null); 
      windowManager.addView(offlineTv, params); 
      isShowing = true; 
     } 
    } 

這裏是所有的設備,但7.1.1設備createLayoutParams方法

private static WindowManager.LayoutParams createLayoutParams(int type, @Nullable IBinder windowToken) { 
     WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(); 
     layoutParams.format = PixelFormat.TRANSLUCENT; 
     layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; 
     layoutParams.height = 25; 
     layoutParams.gravity = GravityCompat.getAbsoluteGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, ViewCompat.LAYOUT_DIRECTION_LTR); 
     layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 
     layoutParams.type = type; 
     layoutParams.token = windowToken; 
     layoutParams.windowAnimations = android.R.style.Animation_Toast; 

     return layoutParams; 
    } 

此代碼工作正常。在7.1.1設備中,TextView顯示一段時間後消失。在7.1.1設備上只有一個空白空白而不是TextView。任何想法爲什麼會發生?

編輯:如要求在評論,這裏是我得到的TextView:這是爲MyApplication類擴展應用:

TextView offlineTv = null; 
/** Get the TextView to show the offline message */ 
    public TextView getOfflineTv() { 
     if (offlineTv == null) { 
      offlineTv = new TextView(this); 
     } 
     return offlineTv; 
    } 

    /** Clear the offline TextView once we are done showing it */ 
    public void clearOfflineTv() { 
     if (offlineTv != null) { 
      offlineTv = null; 
     } 
    } 

這是我的廣播接收器,在這裏我顯示/隱藏:

public class DSConnectionChangeReceiver extends BroadcastReceiver { 

    /** 
    * Connection-changed callback 
    * @param context Context 
    * @param intent Intent 
    */ 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
     NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo(); 
     boolean connected = false; 
     boolean isCellularData = false; 

     if (activeNetworkInfo != null) { 
      connected = activeNetworkInfo.isAvailable() && activeNetworkInfo.isConnected(); 
      int type = activeNetworkInfo.getType(); 
      isCellularData = (type == ConnectivityManager.TYPE_MOBILE) || (type == ConnectivityManager.TYPE_MOBILE_DUN); 
     } 

     if (connected) { 
      if (OfflineBanner.isShowing()) { 
       OfflineBanner.dismiss(); 
      } 
     } else { 
      OfflineBanner.show(); 
     } 
    } 
} 
+0

你可以從MyApplication類發佈getOfflineTv()體嗎?另外請告訴我們什麼時候使用show()以及如何/何時從WindowManager中刪除離線電視。 – Raphau

+0

@Raphau我根據你的要求發佈了更多細節 – Intern

回答

2

問題是由於您添加了android.R.style.Animation_Toast窗口動畫引起的。當動畫在實際吐司上結束時,整個吐司將消失。在這種情況下,您的視圖在層次結構中,因此不會消失,而是變爲空白。

你應該做的是讓layoutParams.windowAnimations斷則params的,而是創建和設置爲View.GONE能見度附加視圖,則該視圖動畫到手動

手工動畫視圖可以用下面的實現屏幕效用:

Animation animIn = AnimationUtils.makeInAnimation(context, true); 
textView.setAnimation(animIn); 
textView.setVisibility(View.VISIBLE); 
textView.animate(); 

小吃吧備選:

public final class ConnectionBar { 

    private static boolean mIsConnected = true; //static to preserve state 
    private static ConnectionReceiver mReceiver; //static to detect leaks 
    private static SnackBar mSnack; 

    private ConnectionBar() { /* required */) 

    public static void prepare(Context ctx) { 
     if (mReceiver != null) { 
      Log.e(TAG, "WARNING previous ConnectionBar was leaked"); 
     } 
     mReceiver = new ConnectionReceiver(); 
     ctx.registerBroadcastReceiver(mReceiver); 
     if (!mIsConnected) { //static so will remember from last screen 
      showBar(ctx); 
     } 
    } 

    private static void showBar(Context ctx) { 
     if (mSnack == null) { 
      mSnack = Snackbar.make(view, message, SnackBar.LENGTH_INDEFINITE); 
      mSnack.show(); 
     } 
    } 

    public static void release(Context ctx) { 
     if (mReceiver != null) { 
      ctx.unregisterBroadcastReceiver(mReceiver); 
      mReceiver = null; 
     } 
     if (mSnack != null) { 
      mSnack.dismiss(); 
     } 
    } 

    private static class ConnectionReceiver extends BroadcastReceiver { 

     @Override 
     public void onReceive(Context context, Intent intent) { 
      ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 
      NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo(); 
      boolean isCellularData = false; //migrate this how you want 
      if (activeNetworkInfo != null) { 
       ConnectionBar.mIsConnected = activeNetworkInfo.isAvailable() && activeNetworkInfo.isConnected(); 
       int type = activeNetworkInfo.getType(); 
       isCellularData = (type == ConnectivityManager.TYPE_MOBILE) || (type == ConnectivityManager.TYPE_MOBILE_DUN); 
      } 
     } 
     if (connected && ConnectionBar.mSnack != null) { 
      ConnectionBar.mSnack.dismiss(); //check this, might need to wrap in runOnUiThread 
     } else { 
      ConnectionBar.showBar(context); 
     } 
    } 
} 

然後在您的活動:

public void onResume() { 
    ConnectionBar.prepare(this); //takes care of setting br too 
} 

public void onPause() { 
    ConnectionBar.release(this); 
} 
+0

我試過你所做的,它仍然消失:(它只發生在7.1.1設備上(甚至沒有7.0仿真器) – Intern

+0

如何做附加文本視圖?如果你可以,請將該部分添加到問題中,我可以問爲什麼你不只是使用無限小吃棒嗎?(你需要一個例子嗎?) –

+0

我添加了我調用show()的部分來將TextView附加到問題上。當然,我並沒有添加無限期的SnackBar,因爲我需要在應用程序離線時在所有屏幕上顯示它。對於我來說,我必須在應用程序中的所有活動中添加SnackBar。沒有BaseActivity :( – Intern

2

如果你想在窗口管理器,查看仍然超過BroadcastReciever生命週期你需要做一個類內部延伸服務。退房this tutorial

我認爲仍然有生命週期的問題。你如何使用它以及系統如何處理它。 如果你想迫使系統不要殺你的服務(而不是刪除WindowManager),你有3個選項。

  1. 返回OnStartCommand與proper flag

    return Service.START_REDELIVER_INTENT;

  2. 添加前景通知

    startForeground(123,NotificationFunction());

  3. 並且如果您有很多進程需要添加輔助功能服務。check out this
+0

這是一個很好的觀點。我在一個服務中移動了代碼,但它仍然不斷消失:( – Intern

+0

好的,所以現在知道服務的生命週期是很重要的,當沒有進程保持它活着的時候,系統通常會終止服務,但是如果你需要強制系統不殺它有三種選擇,請參閱我的編輯。 –

0

這是自Android 7.1以來出現的一種意圖行爲,用於防止應用程序無法使用Toast視圖覆蓋其他應用程序。無論何時使用TYPE_TOAST視圖,系統都會爲您的視圖顯示施加最多3.5秒(即LONG吐司)(並將視圖動畫更改爲內部Toast樣式),然後您的Toast視圖將會被隱藏,除了你的應用程序是當前重點的應用程序。

爲避免應用程序崩潰,您的視圖仍然保留在視圖層次結構中。換句話說,在它被系統隱藏之後,你仍然可以調用removeView,而不會導致非法的狀態異常。

(參考:參見提交消息到Android源: https://github.com/aosp-mirror/platform_frameworks_base/commit/aa07653d2eea38a7a5bda5944c8a353586916ae9

要在Android 7.1顯示在其他應用的視圖或以上則可能需要請求SYSTEM_ALERT_WINDOW權限,提示用戶獲得繪製應用程序權限,並使用其他視圖類型,例如TYPE_SYSTEM_OVERLAY