10.7 WindowManager (Window Management Service)
Category Android Basic Tutorial
Introduction to This Section:
>
This section introduces the WindowManager service provided by Android, which is the most fundamental layer for displaying Views. Toast, Activity, and Dialog all rely on this WindowManager at their core. It is global! The essence of this class is nothing more than invoking methods like addView, removeView, and updateViewLayout to display Views, and using the WindowManager.LayoutParams API to set related attributes!
In this section, let's explore some practical application examples of WindowManager in actual development.
Official API Documentation: WindowManager
1. Some Concepts of WindowManager:
1) Introduction to WindowManager
>
An API provided by Android for interacting with the window manager! We all know that the interfaces of Apps are composed of Acitivty, and Activities are composed of Views. When we want to display an interface, the first thing that comes to mind is: Activity, right? Or perhaps Dialog and Toast.
However, in some cases, the former three may not meet our needs. For example, if we just want to display something simply, using an Activity seems a bit excessive, and Dialog requires a Context object, and Toast cannot be clicked... For the above situations, we can use WindowManager to add Views to the screen or remove Views from the screen! It is an interface that manages the Android window mechanism, the most fundamental layer for displaying Views!
2) How to Obtain a WindowManager Instance
①Obtaining the WindowManager Object :
WindowManager wManager = getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
②Obtaining the WindowManager.LayoutParams Object, Preparing for Subsequent Operations
WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();
2. Examples of Using WindowManager:
Example 1: Obtaining Screen Width and Height
Before Android 4.2, we could use the following method to obtain the screen width and height:
public static int[] getScreenHW(Context context) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = manager.getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
int[] HW = new int[]{width, height};
return HW;
}
The above method has been deprecated since Android 4.2, and we can use another method to obtain the screen width and height:
public static int[] getScreenHW2(Context context) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;
int height = dm.heightPixels;
int[] HW = new int[]{width, height};
return HW;
}
Then we can write two more methods to obtain the width and height, taking the second method of obtaining the screen width and height as an example:
public static int getScreenW(Context context) {
return getScreenHW2(context)[0];
}
public static int getScreenH(Context context) {
return getScreenHW2(context)[1];
}
Of course, if you don't write a separate utility class, you can directly obtain it, for example:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WindowManager wManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wManager.getDefaultDisplay().getMetrics(dm);
Toast.makeText(MainActivity.this, "Current phone screen width and height: " + dm.widthPixels + "*"
+ dm.heightPixels, Toast.LENGTH_SHORT).show();
}
}
Running Result :
Example 2: Setting the Window to Full Screen Display
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getSupportActionBar().hide();
Running Result :
Example 3: Keeping the Screen Always On
public void setKeepScreenOn(Activity activity, boolean keepScreenOn) {
if (keepScreenOn) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} else {
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
Example 4: Implementation of a Simple Floating Box
Running Effect Picture :
Implementation Code :
First, we need a background Service to wait for our operations in the background return true; } }); windowManager.addView(btnView, params); isAdded = true; }
Then, we just need to call the above createWindowView() method in the onCreate() method to start loading the floating box. But we found a problem: it seems that this thing can't be turned off, damn it. Okay, let's analyze the requirements next!
When on the phone's normal interface, that is, the home screen, this thing should be displayed, and when we launch other apps, this floating box should disappear. When we exit the app and return to the home screen, this floating box should reappear!
So first, we need to determine whether the app is on the home screen, so let's add the following code:
/**
* Determine if the current interface is the home screen
*/
public boolean isHome(){
if(mActivityManager == null){
mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
}
List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
return homeList.contains(rti.get(0).topActivity.getPackageName());
}
/**
* Get the package name of the app that belongs to the home screen
* @return Return a list of strings containing all package names
*/
private List<String> getHomes(){
List<String> names = new ArrayList<String>();
PackageManager packageManager = this.getPackageManager();
// Attribute
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
for(ResolveInfo ri : resolveInfo){
names.add(ri.activityInfo.packageName);
}
return names;
}
Okay, next we need to make a series of judgments at regular intervals, such as: whether it is on the home screen, whether the floating box has been loaded, otherwise load it; otherwise, if it is loaded, remove this floating box! Here we use a handler~, because you can't directly update the UI in a child thread, so, you know, we write our own handler to complete the above operations:
// Define a handler to update the interface
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg){
switch(msg.what){
case HANDLE_CHECK_ACTIVITY:
if(isHome()){
if(!isAdded){
windowManager.addView(btnView, params);
isAdded = true;
new Thread(new Runnable(){
public void run(){
for(int i=0;i<10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {e.printStackTrace();}
Message m = new Message();
m.what=2;
mHandler.sendMessage(m);
}
}
}).start();}
} else {
if(isAdded){
windowManager.removeView(btnView);
isAdded = false;
}
}
mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 0);
break;
}
}
};
The last thing to do is to override the Service's onStartCommand() method, which is to make a judgment, take out the data from the Intent, determine whether to add a floating box or to remove a floating box!
@Override
public int onStartCommand(Intent intent, int flags, int startId){
int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW);
switch(operation){
case OPERATION_SHOW:
mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY);
break;
case OPERATION_HIDE:
mHandler.removeMessages(HANDLE_CHECK_ACTIVITY);
break;
}
return super.onStartCommand(intent, flags, startId);
}
Okay, the main work is done, the next is some miscellaneous things, use an Activity to start this Service: MainActivity.java :
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn_on;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindViews();
}
private void bindViews(){
btn_on = (Button) findViewById(R.id.btn_on);
btn_on.setOnClickListener(this);
}
@Override
public void onClick(View v){
switch (v.getId()){
case R.id.btn_on:
Intent mIntent = new Intent(MainActivity.this, MainService.class);
mIntent.putExtra(MainService.OPERATION, MainService.OPERATION_SHOW);
startService(mIntent);
Toast.makeText(MainActivity.this, "Floating box has been turned on~", Toast.LENGTH_SHORT).show();
break;
}
}
}
Then add permissions in AndroidManifest.xml, and register for MainService:
``` <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.GET_TASKS In this section, we have studied the WindowManager in the Android system services. The first three examples may be used more in actual development. It is recommended to write the first example into a utility class, after all, screen width and height are used quite a lot. As for the floating window, understand it if you can, if not, it's also nothing serious. In actual development, you are rarely asked to create a floating window... Well, that's it for this section, thank you.
1.8 Project-Related Analysis (Various Files, Resource Access)
[2.5.1 Implementing Multiple Layouts
5.2.1 Fragment Instance Detailed Lecture - Implementation of Bottom Navigation Bar (Method 1)
5.2.2 Fragment Instance Detailed Lecture - Implementation of Bottom Navigation Bar (Method 2)
5.2.3 Fragment Instance Detailed Lecture - Implementation of Bottom Navigation Bar (Method 3)
5.2.4 Fragment Instance Detailed Lecture - Bottom Navigation Bar + ViewPager Page Switching
6.2 Data Storage and Access - SharedPreferences to Save User Preference Parameters
6.3.1 Data Storage and Access - An Introduction to SQLite Database
6.3.2 Data Storage and Access - Another Look at SQLite Database
7.1.1 Android Network Programming Essentials and Http Protocol Learning
8.3.4 Paint API - Detailed Explanation of Xfermode and PorterDuff (I)
8.3.5 Paint API - Detailed Explanation of Xfermode and PorterDuff (II)
8.3.6 Paint API - Detailed Explanation of Xfermode and PorterDuff (III)
[8.3.7 Paint API - Detailed Explanation of Xfermode and PorterDuff (IV)]
12.2 DrySister Girl Viewing App (First Edition) -- 2. Parsing Backend Data
12.4 DrySister Girl Viewing App (First Edition) -- 4. Adding Data Caching (Integrating SQLite)
12.5 DrySister Girl Viewing App (First Edition) -- 5. Code Review, Adjustment, and Log Class Writing