Android development tips never close Toast info box of long time display instead of system closed

  • 2020-05-09 19:18:49
  • OfStack

The reason the Toast message box closes automatically after a fixed time is because there is an Toast queue in the system. The system will take one Toast from the queue in turn and display it. After 1 display period, close again, and then display the next Toast message box. Until all Toast in the Toast queue are displayed. Sometimes the Toast message box needs to be displayed for a long time until it needs to be turned off by code, rather than having the system automatically turn off the Toast message box. This is too much for Toast itself, since the Toast class does not provide this functionality. Still, there are more ways than problems. You can do this with some special processing, and it's not that complicated.

As you can see from section 7.3.1, the Toast message box needs to be displayed by calling the Toast.show method. Let's take a look at the source code for the show method.
 
publicvoidshow(){ 
if(mNextView==null){ 
thrownewRuntimeException("setViewmusthavebeencalled"); 
} 
INotificationManagerservice=getService(); 
Stringpkg=mContext.getPackageName(); 
TNtn=mTN; 
try{ 
// The current Toast To join the Toast The queue  
service.enqueueToast(pkg,tn,mDuration); 
}catch(RemoteExceptione){ 
//Empty 
} 
} 

The code for the show method is not complex, and you can easily find the following code.
 
service.enqueueToast(pkg,tn,mDuration); 

It is easy to infer from the code above that its function is to add the current Toast to the system's Toast queue. Here, you should think. Although the surface function of the show method is to display the Toast message box, the actual function of the show method is to add Toast to the queue, and then the system displays the Toast message box according to the Toast queue. After further thinking, we can boldly make a preliminary plan. Since the system's Toast queue can display the Toast message box, why can't we display it ourselves? So you can control the display and closing of the Toast message box. Of course, this stops us from calling the show method to display the Toast message box (because the show method enqueues Toast, so we can't control Toast).

Now that the preliminary plan has been drawn up, let's carry it out. If there are any other show methods under the Toast class, look for 1. The result is an TN class, which is an embedded class of Toast. There is one show method in the TN class. TN is a subclass of ITransientNotification.Stub. A preliminary inference is made from the show method in ITransientNotification and TN classes (since Transient means "ephemeral" in Chinese) that the system has obtained Toast objects from the Toast queue, displays Toast using the show method of TN objects, and closes Toast using the TN.hide method. First of all, this is hypothetical. We don't know if this is feasible yet! Of course, this is also the general method of scientific research, which is to infer or hypothesize first, and then prove the inference or hypothesis.

Now the key step 1 is to get the TN object. Unfortunately, TN is declared to be of type private and is not externally accessible. But don't worry. There is one mTN variable in the Toast class. Although not the public variable, it can still be accessed through reflection techniques. The mTN variable is initialized when the Toast object is created. Therefore, as soon as you get the mTN variable, you get the TN object. The code below shows an Toast message box that will never close automatically.
 
// First create 1 a Toast object  
Toasttoast=Toast.makeText(this," never-disappearing Toast",Toast.LENGTH_SHORT); 
// Set up the Toast The position of the message box (shown horizontally centered at the top of the screen)  
toast.setGravity(Gravity.TOP|Gravity.CENTER_HORIZONTAL,0,0); 
try 
{ 
// from Toast Get in object mTN variable  
Fieldfield=toast.getClass().getDeclaredField("mTN"); 
field.setAccessible(true); 
Objectobj=field.get(toast); 
//TN object show methods  
Methodmethod=obj.getClass().getDeclaredMethod("show",null); 
// call show Method to display Toast Message box  
method.invoke(obj,null); 
} 
catch(Exceptione) 
{ 
} 

try{... } catch (...). {... The code in the} statement is the key. The mTN variable was obtained by using the Toast object created in advance. Then the show method of TN object is obtained by using reflection technique.
Closing Toast is similar to displaying Toast, but you need to get the hide method. The code is as follows:
 
try 
{ 
// Need to put the previous code in obj Variables become class variables. This makes it accessible in multiple places  
Methodmethod=obj.getClass().getDeclaredMethod("hide",null); 
method.invoke(obj,null); 
} 
catch(Exceptione) 
{ 
} 

The code above already perfectly implements the ability to control the display and shutdown of the Toast message box through the code. But for a more complete implementation, you can find a file called ITransientNotification.aidl in the AndroidSDK source code (which is the AIDL service definition file, described in more detail below) and build an android.app package in the src directory of the Android project and put this file in the package. ADT then automatically generates an android.app package in the gen directory, which contains an ITransientNotification.java file. Since AndroidSDK's built-in ItransientNotification interface is an internal resource that cannot be accessed by external programs, the mTN variable obtained from the Toast object can only be converted into the ITransientNotification object just generated. This eliminates the need for reflection technology to obtain the show and hide methods. The modified code to display and close the Toast message box is as follows:
 
ITransientNotificationnotification=(ITransientNotification)field.get(toast); 
// According to Toast Message box  
notification.show(); 
// Shut down Toast Message box  
notification.hide(); 

Related articles: