Toast analysis-implement Toast and toast Analysis

Source: Internet
Author: User

Toast analysis-implement Toast and toast Analysis
After android 4.0, a function is added: Disable notifications and Toast from an application. The specific operation is to open the application installation list and find the application to be blocked (long-Press the notification and click "application information" to pop up to jump to the application information interface ), cancel the allowed push message (display notification. After the product finds this function, it is determined to block it. Limited capabilities, do not know how to break the notification blocking, implement a Toast or a small case by yourself ~~

The Toast implementation quickly came up with two solutions: Dialog and WindowManager ). Dialog is suspected that the cost may be relatively high, so I did not try it. Let's look at the floating window directly, and finally find that Toast is also implemented using the floating window. It is easy to use the floating window. You can get the WindowManager and then addView/removeView. Since we have decided to implement it again, we can make it easier-how to call it more conveniently-simply provide a static method. Then the implementation details are displayed. I believe some of my friends, like me, do not know much about Toast. Here we mainly refer to Toast's practical strategies, till now, I have not studied in detail what kind of strategy it shows. Below is a summary:

1. The same message will cancel the previous one, and the last one will display the specified time. Different messages will be displayed serially (or each application can only display a certain amount of Toast, only the display time is updated when the queue is in use );

2. The display time can only be specified. The settings are invalid;

3. Support custom display content;

4. the main interface is not displayed on the front-end. If other threads are used, you need to implement message queue by yourself.

The above is not necessarily true if you observe and guess by yourself. You are welcome to correct the mistakes. You don't have to follow the original style to achieve your own implementation. You can write what you want to do if you want to meet product requirements, make it nice, and make it beautiful ~~


First, let's take a look at the use of Toast:

Toast.makeText(getApplicationContext(), "hello world", Toast.LENGTH_LONG).show();
The simplest Toast call should also be the most common one.

Next, naturally there will be various other ideas, such as custom display content, do not want to input Context every time, the reality is at a specified location, control the display time, and so on. Look at the above line of code. Toast. make (...) returns a Toast object, so let's see what we can do after getting this object:

MToast. setDuration (Toast. LENGTH_SHORT); // display the time of mToast. setText ("hello world"); // may res idmToast. setGravity (Gravity. LEFT | Gravity. (TOP, 50,300); mToast. setMargin (0.5f, 0.5f); mToast. setView (tvMsg); // specify the displayed viewmToast. cancel (); // cancel displaying mToast. show (); // display

This is the case for non-getXXX () methods. In addition to the commonly used show/cancel, let's take a look at the remaining methods.

SetText (): Needless to say, the displayed content supports string and string resource ID.

SetGravity (): This is the alignment mode displayed. The following two parameters are the x/y offset of the preceding alignment mode. For example, the code above sets the alignment to the upper left corner of the screen, and offsets 50 to the right and 300 to the bottom.

SetMargin (): margin, that is, the margin. For example, if Gravity is set to display in the upper left corner and the two values are set to 0.5f, the upper left corner of Toast is actually in the center of the screen.

SetView (): sets the display content view, which can be customized at this time.

Now that we know so much, we can write a custom Toast:

private void bolgToast() {LinearLayout llMain = new LinearLayout(getApplicationContext());llMain.setOrientation(LinearLayout.VERTICAL);llMain.setBackgroundColor(Color.BLACK);llMain.setGravity(Gravity.CENTER);ImageView ivIcon = new ImageView(getApplicationContext());ivIcon.setImageResource(R.drawable.ic_launcher);llMain.addView(ivIcon);TextView tvMsg = new TextView(getApplicationContext());tvMsg.setText("hello word");tvMsg.setTextSize(18);llMain.addView(tvMsg);Toast mToast = new Toast(getApplicationContext());mToast.setView(llMain);mToast.show();}
The final effect is as follows:



It should be okay ~~ The following is a few simple questions:

1. Sometimes Toast may be called in a non-main thread, and the system may report the following error to you:

08-09 00:01:36.353: E/AndroidRuntime(24817): java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
This error is obvious. We may need to implement the message system of the current thread. Many examples on the Internet tell us that we can write like this:

New Thread (new Runnable () {@ Overridepublic void run () {Looper. prepare (); Toast. makeText (getApplicationContext (), "hello ttdevs", Toast. LENGTH_LONG ). show (); logoff. loop (); // This statement is not only required for prepare, but also for Toast }}). start ();

In fact, I have always been curious about the meaning of this writing. You can also write the following statement:

new Thread(new Runnable() {@Overridepublic void run() {new Thread(new Runnable() {Handler mHandler = new Handler(Looper.getMainLooper()) {@Overridepublic void dispatchMessage(Message msg) {Toast.makeText(getApplicationContext(), "hello ttdevs", Toast.LENGTH_LONG).show();}};@Overridepublic void run() {mHandler.sendEmptyMessage(0);}}).start();}}).start();
The results are the same (a piece of test code written in the activity, can you understand why Thread Nesting is used to simulate the problem? (?)).

2. Sometimes you may encounter the following problems:

08-09 00:17:28.053: E/AndroidRuntime(26441): Caused by: java.lang.RuntimeException: This Toast was not created with Toast.makeText()
My test code is as follows:

Toast mToast = new Toast(getApplicationContext());mToast.setText(String.valueOf(Math.random()));mToast.show();
We can only honestly use Toast. makeText () to construct a Toast. The specific cause will be analyzed later.

3. RuntimeException: setView must have been called. This problem occurs when cancel () is called before show (). Do you still remember the cancel method? View the source code. We can see that:

        final Runnable mHide = new Runnable() {            @Override            public void run() {                handleHide();                // Don't do this in handleHide() because it is also invoked by handleShow()                mNextView = null;            }        };
After hiding the image, mNextView is set to null.

Next we will analyze the source code of Toast (the latest version 4.4). Other versions, such as 2.2, may be quite different from this version. You can analyze it yourself. First, let's take a look at the most common makeText () method:

    /**     * Make a standard toast that just contains a text view.     *     * @param context  The context to use.  Usually your {@link android.app.Application}     *                 or {@link android.app.Activity} object.     * @param text     The text to show.  Can be formatted text.     * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or     *                 {@link #LENGTH_LONG}     *     */    public static Toast makeText(Context context, CharSequence text, int duration) {        Toast result = new Toast(context);        LayoutInflater inflate = (LayoutInflater)                context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);        View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);        TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);        tv.setText(text);                result.mNextView = v;        result.mDuration = duration;        return result;    }
This method returns a standard Toast with only one TextView. First, create a Toast object using the default Toast constructor. Set the view and display time for the Toast. R. layout. transient_notification is a simple linear layout with a nested TextView. You can view the source code by yourself. Then, you can set the display time. It is not a time value for long and short, it is a static flag constant such as 0/1, which simply explains why the duration we passed in is invalid. Next, let's look at the Toast constructor:

    /**     * Construct an empty Toast object.  You must call {@link #setView} before you     * can call {@link #show}.     *     * @param context  The context to use.  Usually your {@link android.app.Application}     *                 or {@link android.app.Activity} object.     */    public Toast(Context context) {        mContext = context;        mTN = new TN();        mTN.mY = context.getResources().getDimensionPixelSize(                com.android.internal.R.dimen.toast_y_offset);        mTN.mGravity = context.getResources().getInteger(                com.android.internal.R.integer.config_toastDefaultGravity);    }
The key part is to create an TN object and continue to follow up:


The above is the structure and constructor of TN. This constructor is relatively simple. Modify the parameters of WindowManager. LayoutParams. If you have made a floating window, it is relatively simple here. Curious LayoutParams. TYOE_TOAST, this type exists, and immediately comes to mind whether Toast is blocked based on this Type, but through testing, it is found that it is not. This comment makes me feel like the most intense: This shoshould be changed to use a Dialog, with a Theme. Toast defined that sets up the layout params appropriately. Why does This comment appear? Why not use dialog to implement this annotation? The following is an attempt:


Theme. Toast is not found. I don't know if it is in the system or not, and I don't want to use it for users. However, this also indicates that the dialog implementation may be correct. Now, let's get there. It's hard to continue with the limited capabilities.

Return to the Toast above to see our common show () method:

    /**     * Show the view for the specified duration.     */    public void show() {        if (mNextView == null) {            throw new RuntimeException("setView must have been called");        }        INotificationManager service = getService();        String pkg = mContext.getPackageName();        TN tn = mTN;        tn.mNextView = mNextView;        try {            service.enqueueToast(pkg, tn, mDuration);        } catch (RemoteException e) {            // Empty        }    }
The key part cannot be followed. It is worth noting that this RuntimeException: setView must have been called. If we encounter this error message, we should know that the View of Toast is null. In combination with the TN code, you may naturally think that the actual display should be TN. show (). The handler will eventually execute the following method:

        public void handleShow() {            if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView                    + " mNextView=" + mNextView);            if (mView != mNextView) {                // remove the old view if necessary                handleHide();                mView = mNextView;                Context context = mView.getContext().getApplicationContext();                if (context == null) {                    context = mView.getContext();                }                mWM = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);                // We can resolve the Gravity here by using the Locale for getting                // the layout direction                final Configuration config = mView.getContext().getResources().getConfiguration();                final int gravity = Gravity.getAbsoluteGravity(mGravity, config.getLayoutDirection());                mParams.gravity = gravity;                if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {                    mParams.horizontalWeight = 1.0f;                }                if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {                    mParams.verticalWeight = 1.0f;                }                mParams.x = mX;                mParams.y = mY;                mParams.verticalMargin = mVerticalMargin;                mParams.horizontalMargin = mHorizontalMargin;                if (mView.getParent() != null) {                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);                    mWM.removeView(mView);                }                if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);                mWM.addView(mView, mParams);                trySendAccessibilityEvent();            }        }
The entire idea is still relatively simple, the preparation conditions, and finally call the addView method of WindowManager to display our View on the interface. Like handleHide (), remove our View from the interface. It is worth noting that when we use hide, our View will be set to null.
Finally, let's summarize Toast. First, we need to construct a Toast object by using new Toast or Toast. makeText to store the required data. When show is executed, the data is transmitted to the Android Notification system, which is responsible for processing the corresponding logic and finally displayed on the interface through WindowManager. Through the above analysis, we should also know the same Notification system for Toast and Notification. We did not carefully analyze the implementation differences of each version. If you have any problems, you can look at the corresponding Toast source code to find a specific solution. Two references are provided below:

1. http://blog.csdn.net/ameyume/article/details/7714491

2. http://www.imooo.com/yidongkaifa/android/1009042.htm

Finally, let's talk about our own Toast: add your Toast to a message queue using a show method, and then cyclically retrieve the display content in the message queue. Hiding is also accomplished through a special message. When a Message Queue reaches a certain size, we adopt the simplest logic: clearing the queue. In addition, as a global task, we need to initialize and recycle it. We recommend that you complete the initialization in application.

The Code is as follows (BaseThread can be viewed in my top article ):

Public class ToastUtil extends BaseThread {private static final int SHOW_TIME = 2000; // display time private static final int QUEUE_SIZE = 120; // queue size private static final int QUEUE_SIZE_LIMIT = 100; // limit the queue size to private static final int FLAG_SHOW = 1000; // display private static final int FLAG_HIDE = 1001; // hide private static final int FLAG_CLEAR = 1002; // clear the private static final String QUITMSG = "@ bian _ # feng _ $ Market _ % toast _ & quit _ * flag "; // exit flag private static BlockingQueue <String> mMsgQueue = new ArrayBlockingQueue <String> (QUEUE_SIZE ); // message cache queue private static ToastUtil mToast; private WindowManager mWindowManager; private WindowManager. layoutParams mParams; private View toastView; private TextView tvAlert; @ SuppressLint ("InflateParams") private ToastUtil (Context context) {mWindowManager = (WindowManager) co Ntext. getSystemService (Context. WINDOW_SERVICE); mParams = new WindowManager. layoutParams (); mParams. type = WindowManager. layoutParams. TYPE_TOAST; // TYPE_SYSTEM_OVERLAYmParams.windowAnimations = android. r. style. animation_Toast; mParams. format = PixelFormat. TRANSLUCENT; mParams. width = WindowManager. layoutParams. WRAP_CONTENT; mParams. height = WindowManager. layoutParams. WRAP_CONTENT; mParams. gravity = Grav Ity. CENTER_HORIZONTAL | Gravity. TOP; mParams. alpha = 1f; // transparency, 0 Full Transparent, 1 non-transparent mParams. verticalMargin = 0.75f; mParams. flags = WindowManager. layoutParams. FLAG_KEEP_SCREEN_ON | WindowManager. layoutParams. FLAG_NOT_FOCUSABLE | WindowManager. layoutParams. FLAG_NOT_TOUCHABLE; toastView = LayoutInflater. from (context ). inflate (R. layout. layout_toast, null); tvAlert = (TextView) toastView. findViewById (R. id. tvAlert); start ();}/*** Initialize message display ** @ param context */public static void init (Context context) {if (null = mToast) {mToast = new ToastUtil (context) ;}} private Handler mHandler = new Handler (logoff. getmainlogoff () {public void handleMessage (android. OS. message msg) {int what = msg. what; switch (what) {case FLAG_SHOW: String str = msg. obj. toString (); if (! TextUtils. isEmpty (str) {showMsg (str);} break; case FLAG_HIDE: hideMsg (); break; case FLAG_CLEAR: showMsg ("Operation exception, too many messages"); break; default: break ;};}; private void showMsg (String msg) {try {tvAlert. setText (msg); if (null = toastView. getParent () {mWindowManager. addView (toastView, mParams) ;}} catch (Exception e) {e. printStackTrace () ;}} private void hideMsg () {try {if (null! = ToastView. getParent () {mWindowManager. removeView (toastView);} catch (Exception e) {e. printStackTrace () ;}}/** Display message ** @ param msg * display content */public static void show (String msg) {try {mMsgQueue. put (msg); // block} catch (Exception e) {e. printStackTrace () ;}} public static void show (Context context, int id) {try {mMsgQueue. put (context. getResources (). getString (id); // block} catch (Exception e) {e. printStackTrace () ;}}/*** exit */public static void eixt () {try {mMsgQueue. put (QUITMSG);} catch (Exception e) {e. printStackTrace () ;}@ Overridepublic void execute () {try {String msgStr = mMsgQueue. take (); if (QUITMSG. equals (msgStr) {exitToast (); return;} Message msg = mHandler. obtainMessage (); if (null = msg) {msg = new Message ();} msg. what = FLAG_SHOW; msg. obj = msgStr; mHandler. sendMessage (msg); Thread. sleep (SHOW_TIME); if (mMsgQueue. size () = 0) {mHandler. sendEmptyMessage (FLAG_HIDE);} if (mMsgQueue. size ()> QUEUE_SIZE_LIMIT) {mMsgQueue. clear (); mHandler. sendEmptyMessage (FLAG_CLEAR); Thread. sleep (SHOW_TIME); mHandler. sendEmptyMessage (FLAG_HIDE);} System. out. println (">>>>>" + mMsgQueue. size ();} catch (Exception e) {e. printStackTrace (); mHandler. sendEmptyMessage (FLAG_HIDE) ;}}/*** exit, clear memory */private void exitToast () {try {hideMsg (); quit (); mMsgQueue. clear (); mMsgQueue = null; mToast = null;} catch (Exception e) {e. printStackTrace ();}}}



A problem about toast in android Development

I have not studied toast. Toast should be the type of message queue.

You can write a view floating on the top of the screen. Use this view to display information.
There are a lot of floating box code on the Internet.

Android programming question. There is a button in the figure. You can click the button and use Toast to display your own name.

// Copy to the onCreate directory. The layout xml is not written. If necessary, you can write the layout by yourself and then use the find button to obtain the layout, currently, this is the entire avti.pdf is a buttonButton B = new Button (this); B. setText ("name"); B. setOnClickListener (new OnClickListener () {@ Override public void onClick (View v) {Toast. makeText (MainActivity. this, "XXX", Toast. LENGTH_LONG ). show () ;}}); setContentView (B );

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.