2017-11-12 46 views
5

Tôi đang cố gắng thêm chế độ xem tôi đang tạo thông qua dịch vụ. Mã tôi đang sử dụng dựa trên Facebook Chatheads luôn được hiển thị, bất kể trạng thái ứng dụng. Họ cũng được hiển thị trên bất cứ điều gì khác nữa:Thay đổi LayoutParams của luôn hiển thị Trò chuyện Thủ trưởng không phải luôn luôn hiển thị

enter image description here Android Chat Head

bây giờ tôi muốn hạn chế người đứng đầu cuộc trò chuyện với ứng dụng hoạt động. Cụ thể là tôi đang đối phó với Ngoại lệ Bad Token bất cứ khi nào tôi thay đổi Window.LayoutParams từ TYPE_PHONE thành TYPE_DRAWN_APPLICATION.

CÂU HỎI CỦA TÔI: Tôi biết rằng tôi được yêu cầu chuyển đúng mã thông báo cửa sổ cho LayoutParams nhưng dường như không thể tìm ra cách thực hiện điều này một cách chính xác. Mọi lời khuyên sẽ được đánh giá cao.

Đây là mã của tôi:

// Hoạt động chính

private void addNewBubble() { 
     BubbleLayout bubbleView = (BubbleLayout)LayoutInflater.from(MainActivity.this).inflate(R.layout.bubble_layout, null); 
     bubblesManager.addBubble(bubbleView, 60, 20); 
} 

// initializes Bubbles Manager 
private void initializeBubblesManager() { 
     bubblesManager = new BubblesManager.Builder(this) 
       .setTrashLayout(R.layout.task_bubble_trash_layout) 
       .setInitializationCallback(new OnInitializedCallback() { 
        @Override 
        public void onInitialized() { 
         addNewBubble(); // Called when addNewBubble is initialized and the bubble data is loaded. When used on devices running API 18 or below, this function is always called. 

        } 
       }) 
       .build(); 
     bubblesManager.initialize(); 
    } 

// initializes Bubbles Manager 
     private void initializeBubblesManager() { 
      bubblesManager = new BubblesManager.Builder(this) 
        .setTrashLayout(R.layout.task_bubble_trash_layout) 
        .setInitializationCallback(new OnInitializedCallback() { 
         @Override 
         public void onInitialized() { 
          addNewBubble(); // Called when addNewBubble is initialized and the bubble data is loaded. When used on devices running API 18 or below, this function is always called. 

         } 
        }) 
        .build(); 
      bubblesManager.initialize(); 
     } 

// XML - Tuỳ chỉnh Bubble_layout

<com.momely.bubbles.BubbleLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:clipChildren="false" 
    android:clipToPadding="false"> 

    <ImageView 
     android:id="@+id/avatar" 
     android:layout_width="70dp" 
     android:layout_height="70dp" 
     android:layout_gravity="center" 
     android:background="@drawable/profile_decorator" 
     android:src="@drawable/round_button" 
     android:scaleType="centerCrop"/> 

    <TextView 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:textColor="@color/white" 
     android:textSize="15sp" 
     android:layout_marginTop="2dp" 
     android:layout_marginLeft="2dp" 
     android:paddingLeft="4dp" 
     android:paddingRight="4dp" 
     android:background="@drawable/bubble_counter_bkg" 
     android:text="1"/> 

</com.momely.bubbles.BubbleLayout> 

// trong bubblesManager

public class BubblesManager { 
    private static BubblesManager INSTANCE; 
    private Context context; 
    private boolean bounded; 
    private BubblesService bubblesService; 
    private int trashLayoutResourceId; 
    private OnInitializedCallback listener; 


    //getInstance (called in Builder below) 
    private static BubblesManager getInstance(Context context){ 
     if (INSTANCE == null) { 
      INSTANCE = new BubblesManager(context); 
     } 
     return INSTANCE; 
    } 

    //Binds the service to the application 
    private ServiceConnection bubbleServiceConnection = new ServiceConnection(){ 
     @Override 
     public void onServiceConnected(ComponentName name, IBinder service){ 
      BubblesService.BubblesServiceBinder binder = (BubblesService.BubblesServiceBinder)service; 
      BubblesManager.this.bubblesService = binder.getService(); 
      configureBubblesService(); 
      bounded = true; 
      if(listener != null){ 
       listener.onInitialized(); 
      } 
     } 

    //Initializes Bubbles Manager 
    private BubblesManager(Context context){ 
     this.context = context; 
     } 

    //Initializes the service 
    public void initialize(){ 
     context.bindService(new Intent(context, BubblesService.class), 
      bubbleServiceConnection, 
      Context.BIND_AUTO_CREATE); 
     } 

    public void addBubble(BubbleLayout bubble, int x, int y){ 
     if(bounded){ 
      bubblesService.addBubble(bubble, x, y); 
      Log.d("Bubble", "Bubble created"); 
     } 

    //Builder class 
    public static class Builder { 
     private BubblesManager bubblesManager; 

     //Builder constructor 
     public Builder(Context context){ 
      this.bubblesManager = getInstance(context); 
     } 

     //Sets initialization Callbacks - a callback is when we provide a function as an argument to another function in order to enforce the order of operations. 
     public Builder setInitializationCallback(OnInitializedCallback listener){ 
      bubblesManager.listener = listener; 
      return this; 
     } 

     //Sets Trash Layout 
     public Builder setTrashLayout(int trashLayoutResourceId){ 
      bubblesManager.trashLayoutResourceId = trashLayoutResourceId; 
      return this; 
     } 

     //Triggers BubbleManager; 
     public BubblesManager build(){ 
      return bubblesManager; 
     } 
    } 
} 

// trong bubblesService

imports... 


public class BubblesService extends Service{ 
    private BubblesServiceBinder binder = new BubblesServiceBinder(); 
    private List<BubbleLayout> bubbles = new ArrayList<>(); 
    private BubbleTrashLayout bubblesTrash; 
    private WindowManager windowManager; 
    private BubblesLayoutCoordinator layoutCoordinator; 

    //overrides the IBind method 
    @Override 
    public IBinder onBind(Intent intent){ 
     return binder; 
    } 


    //overrides the onUnbind method 
    @Override 
    public boolean onUnbind(Intent intent){ 
     for (BubbleLayout bubble : bubbles){ 
      recycleBubble(bubble); 
     } 
     bubbles.clear(); 
     return super.onUnbind(intent); 
    } 


    //Gets the Windows Manager 
    private WindowManager getWindowManager(){ 
     if (windowManager ==null){ 
      windowManager = (WindowManager)getSystemService(WINDOW_SERVICE); 
     } 
     return windowManager; 
    } 

    // Adds view to the Window 
    public void addBubble(BubbleLayout bubble, int x, int y){ 
     WindowManager.LayoutParams layoutParams = buildLayoutParamsForBubble(bubble, x,y); 
     layoutParams.token = bubble.getApplicationWindowToken(); 
     bubble.setWindowManager(getWindowManager()); 
     bubble.setViewParams(layoutParams); 
     bubble.setLayoutCoordinator(layoutCoordinator); 
     bubbles.add(bubble); 
     addViewToWindow(bubble); 
    } 


    // Initializes the Layout Cocordinator 
    private void initializeLayoutCoordinator(){ 
     layoutCoordinator = new BubblesLayoutCoordinator.Builder(this) 
       .setWindowManager(getWindowManager()) 
       .setTrashView(bubblesTrash) 
       .setTrashView(bubblesTrash) 
       .build(); 
    } 

    //Adds view to the Window 
    private void addViewToWindow(final BubbleBaseLayout view){ 
     new Handler(Looper.getMainLooper()).post(new Runnable(){ 
      @Override 
      public void run(){ 
       getWindowManager().addView(view, view.getViewParams()); 
      } 
     }); 
    } 

    //BUILDING LAYOUT PARAMS --> THIS IS WHERE THE TYPE IS SET 
    private WindowManager.LayoutParams buildLayoutParamsForBubble(BubbleLayout bubble, int x, int y){ 
     WindowManager.LayoutParams params = new WindowManager.LayoutParams(
       WindowManager.LayoutParams.WRAP_CONTENT, 
       WindowManager.LayoutParams.WRAP_CONTENT, 
       WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION, //!!!! WHEN this is set to TYPE_PHONE the chat head stays on the screen even if the application is onPause. 
       WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, 
       PixelFormat.TRANSPARENT); 
     params.gravity = Gravity.TOP | Gravity.START; 
     params.token = bubble.getApplicationWindowToken(); 
     params.x = x; 
     params.y = y; 
     return params; 
    } 


    //defines the BubblesService Binder service 
    public class BubblesServiceBinder extends Binder { 
     public BubblesService getService(){ 
      return BubblesService.this; 
     } 
    } 

} 

/// LỖI TÔI NHẬN

E/AndroidRuntime: FATAL EXCEPTION: main 
    Process: com.momely.mascapone, PID: 16638 
    android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application 
     at android.view.ViewRootImpl.setView(ViewRootImpl.java:683) 
     at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:342) 
     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:93) 
     at com.momely.bubbles.BubblesService$2.run(BubblesService.java:115) 
     at android.os.Handler.handleCallback(Handler.java:751) 
     at android.os.Handler.dispatchMessage(Handler.java:95) 
     at android.os.Looper.loop(Looper.java:154) 
     at android.app.ActivityThread.main(ActivityThread.java:6119) 
     at java.lang.reflect.Method.invoke(Native Method) 
     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) 
     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) 

Bất cứ lời khuyên về cách tôi có thể giới hạn đầu trò chuyện với các cửa sổ ứng dụng mà không có nó còn lại trên màn hình khi ứng dụng vào Pause?

Z

+0

Tại sao bạn đang mở rộng 'Dịch vụ'? –

+0

Câu hỏi hay. Tôi đoán dịch vụ mở rộng cho phép chúng tôi chạy BubblesService như một dịch vụ mà chúng tôi có thể liên kết với cửa sổ? – Z101

+1

Nice Guess. Đối với điều này, bạn cần phải bắt đầu 'BubblesService' và ràng buộc thành phần giao diện người dùng với nó trước khi truy cập' addBubble' –

Trả lời

2

"bây giờ tôi muốn hạn chế người đứng đầu cuộc trò chuyện với ứng dụng hoạt động."

Tôi thấy hai tùy chọn. Là một hack đơn giản (giữ Dịch vụ) sử dụng Tùy chọn 1.
Lựa chọn 2 phương tiện sao chép BubblesService.java-BubblesLocal.javaBubblesManager.java để BubblesManagerLocal.java, và hack ra tất cả các mã Service. Tôi đề xuất Tùy chọn 1 là những gì bạn muốn (dễ dàng hơn nhiều và bạn có thể bật và tắt). here is an image

Lựa chọn 1

Đơn giản chỉ cần ẩn các bong bóng khi ứng dụng của bạn không hoạt động.
Thêm mã sau vào dự án của bạn (đã kiểm tra, đang hoạt động):

MainActivity.java:

//update ActionBarActivity to AppCompatActivity 
`public class MainActivity extends AppCompatActivity //ActionBarActivity` 
private boolean mStarted = false; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
... 
     initializeBubblesManager(); 
     mStarted = true; 
//------------------------------------------------------------------------------------------------ 
    @Override 
    protected void onResume() 
    { 
     Log.i("MainActivity:","onResume"); 
     super.onResume(); 
     if(mStarted) bubblesManager.showBubbles(); 
    } 
//------------------------------------------------------------------------------------------------ 
    @Override 
    protected void onPause() 
    { 
     Log.i("MainActivity:","onPause"); 
     super.onPause(); 
     if(mStarted) bubblesManager.hideBubbles(); 
    } 
//------------------------------------------------------------------------------------------------ 

BubblesManager.java:

//------------------------------------------------------------------------------------------------ 
    public void showBubbles() 
    { 
     if(bounded && bubbleServiceConnection != null)bubblesService.showBubbles(); 
    }//showBubbles 
//------------------------------------------------------------------------------------------------ 
    public void hideBubbles() 
    { 
     if(bounded && bubbleServiceConnection != null)bubblesService.hideBubbles(); 
    }//hideBubbles 
//------------------------------------------------------------------------------------------------ 

BubblesService.java:

//------------------------------------------------------------------------------------------------ 
    public void showBubbles() 
    { 
     if(bubbles.size() > 0) 
     { 
      for (BubbleLayout bubble : bubbles) 
      { 
       bubble.showBubble(); 
      } 
     } 
    }//showBubbles 
//------------------------------------------------------------------------------------------------ 
    public void hideBubbles() 
    { 
     if(bubbles.size() > 0) 
     { 
      for (BubbleLayout bubble : bubbles) 
      { 
       bubble.hideBubble(); 
      } 
     } 
    }//hideBubbles 
//------------------------------------------------------------------------------------------------ 

BubbleLayout.java:

//------------------------------------------------------------------------------------------------ 
    public void showBubble() 
    { 
      //View.GONE This view is invisible, and it doesn't take any space for layout purposes. 
      //View.INVISIBLE This view is invisible, but it still takes up space for layout purposes. 

     getRootView().setVisibility(View.VISIBLE); 
    }//showBubble 
//------------------------------------------------------------------------------------------------ 
    public void hideBubble() 
    { 
     getRootView().setVisibility(View.INVISIBLE); 
    }//hideBubble 
//------------------------------------------------------------------------------------------------ 
Các vấn đề liên quan