1. 程式人生 > >Android之Java反射使用:阻止AlertDialog的dismiss事件

Android之Java反射使用:阻止AlertDialog的dismiss事件

知識點:

1、利用反射,阻止AlertDialog每次的dismiss事件;

在使用AlertDialog的時候,我們設定positive,negative和neutral的button,在點選之後,即使不手動呼叫dismiss方法,系統都會自動的幫我們dismiss掉了。

但是我這裡可能點選了之後,還有一些時間比較長的工作處理之後,才能夠dismiss掉此AlertDialog;那麼這就是一個問題了。我們先直接看怎麼來阻止這個系統的dismiss事件。

話不多述,我們直接先上程式碼,看看如何操作的,然後在稍微看看原始碼,一探究竟:

首先是來一個button,設定點選事件,彈出dialog

@Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_rDialog:
                showDialog();
                break;
        }
    }

然後在activity裡頭,建立showDialog方法,如下:
/**
     * 利用反射,阻止dialog點選確定或者取消按鈕,總是會使得dialog消失的結果
     */
    void showDialog() {
        AlertDialog alertDialog = new AlertDialog.Builder(this)
                .setTitle("title")
                .setMessage("content")
                .setIcon(R.drawable.__leak_canary_icon)
                .setPositiveButton(R.string.ok,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                //就算阻止了dialog的dismiss事件,這裡呼叫dismiss也還是可以dismiss掉dialog的
//                                dialog.dismiss();
                            }
                        })
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                }).create();
        alertDialog.setCanceledOnTouchOutside(false);

        setDialogCancelable(alertDialog);
//        setDialogIsCanceled(alertDialog, false);
        /* 顯示對話方塊 */
        alertDialog.show();
    }

    /**
     * 通過重新設定一個button處理類,達到點選確定按鈕不dismiss掉dialog的效果
     *
     * @param alertDialog alertDialog
     */
    void setDialogCancelable(AlertDialog alertDialog) {
        try {
            Field field = alertDialog.getClass().getDeclaredField("mAlert");
            field.setAccessible(true);
            /* 獲得mAlert變數的值 */
            Object obj = field.get(alertDialog);
            field = obj.getClass().getDeclaredField("mHandler");
            field.setAccessible(true);
            /* 修改mHandler變數的值,使用新的ButtonHandler類 */
            field.set(obj, new IButtonHandler(alertDialog));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 通過獲取mShowing欄位,修改它的值,達到點選確定按鈕不dismiss掉dialog的效果
     * 但是好像是沒有用的,不起效果
     *
     * @param alertDialog alertDialog
     * @param isCanceled  isCanceled false=此dialog已經關閉了,反之則是為關閉
     */
    void setDialogIsCanceled(AlertDialog alertDialog, boolean isCanceled) {
        try {
            /* 這裡有一個層級關係需要記住,看欄位是屬於父類,還是屬於父類的父類 */
            Field field = alertDialog.getClass()
                    .getSuperclass().getSuperclass().getDeclaredField("mShowing");
            field.setAccessible(true);
            /* 將mShowing變數設為false,表示對話方塊已關閉 */
            field.set(alertDialog, isCanceled);
            alertDialog.dismiss();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


還有涉及到一個IButtonHandler  的類

package com.yaojt.ui.reflect;

import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;

import java.lang.ref.WeakReference;

/**
 * desc:自定義的dialog點選按鈕事件處理機制
 * <p>
 * author:kuyu.yaojt (tanksu)
 * <p>
 * email:[email protected]
* <p> * date:17/3/7 */ public class IButtonHandler extends Handler { /* 使用弱引用,避免記憶體洩漏 */ private WeakReference<DialogInterface> mDialog; /** * 構造方法 * * @param dialog dialog */ public IButtonHandler(DialogInterface dialog) { mDialog = new WeakReference<>(dialog); } @Override public void handleMessage(Message msg) { switch (msg.what) { case DialogInterface.BUTTON_POSITIVE: case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEUTRAL: ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what); break; /** * AlertController,最終都會呼叫以下程式碼,並且傳入MSG_DISMISS_DIALOG標誌 * // Post a message so we dismiss after the above handlers are executed mHandler.obtainMessage(IButtonHandler.MSG_DISMISS_DIALOG, mDialog) .sendToTarget(); 然後到下面程式碼 //以下是原始的ButtonHandler類 可以看到最後的最後,都會走到這一個入口裡去了 導致所有的dialog方法都會被dismiss掉,只要攔截這個就可以了。做法就是重新定義一個ButtonHandler 設定取代原來的ButtonHandler例項即可。有一點不好那就是會影響到所有的dialog。 但是我們在確定監聽裡頭是呼叫dismiss,是可以dismiss掉dialog的 其實就是不要dismiss的這個方法入口 private static final class IButtonHandler extends Handler { // Button clicks have Message.what as the BUTTON{1,2,3} constant private static final int MSG_DISMISS_DIALOG = 1; private WeakReference<DialogInterface> mDialog; public IButtonHandler(DialogInterface dialog) { mDialog = new WeakReference<>(dialog); } @Override public void handleMessage(Message msg) { switch (msg.what) { case DialogInterface.BUTTON_POSITIVE: case DialogInterface.BUTTON_NEGATIVE: case DialogInterface.BUTTON_NEUTRAL: ((DialogInterface.OnClickListener) msg.obj).onClick(mDialog.get(), msg.what); break; case MSG_DISMISS_DIALOG: ((DialogInterface) msg.obj).dismiss(); } } } */ } } }


程式碼就是以上這些,都有註釋的了。

反射確實挺好用的,可以在執行時動態地載入一個類,然後呼叫執行類裡面的方法,在高階開發中,這個是必須的技能,要好好學習。

另外,這個也是有風險的做法,其他人也可以使用這個來獲取到你的類的相關資訊,然後做一些壞事什麼的。

相關推薦

AndroidJava反射使用阻止AlertDialog的dismiss事件

知識點: 1、利用反射,阻止AlertDialog每次的dismiss事件; 在使用AlertDialog的時候,我們設定positive,negative和neutral的button,在點選之後,即使不手動呼叫dismiss方法,系統都會自動的幫我們dismiss掉了

Android系統原理與原始碼分析(1)利用Java反射技術阻止通過按鈕關閉對話方塊

本文為原創,如需轉載,請註明作者和出處,謝謝!     眾所周知,AlertDialog類用於顯示對話方塊。關於AlertDialog的基本用法在這裡就不詳細介紹了,網上有很多,讀者可以自己搜尋。那

java反射加載成員方法

pri ssi ID otf cati sys leg tar security java反射:加載成員方法 package com.ma.reflection; import java.lang.reflect.InvocationTargetException; i

面試題------Java 反射機制

orange 是不是 rac 匿名對象 結果 創建 一起 使用 edi 一、反射機制概述 Java 反射機制是在運行狀態中,對於任意一個類,都能夠獲得這個類的所有屬性和方法,對於任意一個對象都能夠調用它的任意一個屬性和方法。這種在運行時動態的獲取信息以及動態調用對象

Java反射如何正確理解,不如手寫一個(反射包分析、樓主親測)

Java反射機制、動態代理是基於什麼原理? 這個問題可謂是老生常談的一個熱門問題了,如果沒有深入的思考還真的是很難回到上來。那麼今天我們一起來看看,如何正確清晰的認識這個熱門卻又說簡單又不簡單說複雜又比較複雜的問題。 一、什麼是反射 反射機制是Java語言提供的一種基礎功能

大白話說Java反射入門、使用、原理

  java的反射機制就是增加程式的靈活性,避免將程式寫死到程式碼裡, 例如: 例項化一個 person()物件, 不使用反射, new person(); 如果想變成 例項化 其他類, 那麼必須修改原始碼,並重新編譯。 使用反射: class.forName

深入理解 Java 反射Class (反射的入口)

什麼是 Reflection 反射,為什麼要用它 Java 強型別語言,但是我們在執行時有了解、修改資訊的需求,包括類資訊、成員資訊以及陣列資訊。 Java 中 Reflection 和 Introspection 區別? 說起反射,還有一個相似的概念 ‘Introspec

Android面試——java基礎String各種方式建立時,做==運算結果

先看結果後分析 String s1 = "MileIsGoodBoy";//在常量池中 String s2 = new String("MileIsGoodBoy");//堆中 String s3 = "MileIs";/

Java反射Class類的使用

通過Java反射機制,可以在程式中訪問已經轉載到JVM中的Java物件的描述,實現訪問、檢測和修改描述Java物件本身資訊的功能。Java反射機制的功能十分強大,在java.lang.reflect包中提供了對該功能的支援。 所有Java類均繼承了Object類,在Object類中定義了一個

Java反射使用Annotation功能

Java中提供了Annotaion(註釋)功能,該功能可用於類、構造方法、成員變數、方法、引數等的宣告中。該功能並不影響程式的執行,但是會對編譯器警告等輔助工具產生影響。 1、定義Annotation型別 在定義Annotation型別時,也需要用到用來定義介面的interface關鍵字

深入理解AndroidJava虛擬機器Dalvik

一、背景這個選題很大,但並不是一開始就有這麼高大上的追求。最初之時,只是源於對Xposed的好奇。Xposed幾乎是定製ROM的神器軟體技術架構或者說方法了。它到底是怎麼實現呢?我本意就是想搞明白Xposed的實現原理,但隨著程式碼研究的深入,我發現如果不瞭解虛擬機器的實現,

java反射動態載入類

    我們在程式設計時也許會遇到這樣的問題,當我們在定義兩個類物件時,如果其中一個類不存在,或者類的方法找不到,那麼即使另外一個類以及其類方法是存在並且正確的,我們在執行時也會報錯,如以下這個問題: if("Word".equals(ar

自學AndroidUI元件(二)Fragment的基本使用(上)

本篇為UI元件的第二篇,主要探討關於Fragment的基本使用,包括簡單的原理以及建立、修改、刪除等操作。 在本篇文章中,你將瞭解到: 1.什麼是Fragment。 2.Fragmen

深入理解AndroidJava Security第一部分

深入理解Android之Java Security(第一部分)從事Android工作4年以來,只有前1年不到的時間是用C++在開發東西(主要是開發DLNA元件,目前我已將它們全部開源,參考http://

Android使用 Java 反射實現 API Hook

文章內容來自https://www.jianshu.com/p/4f6d20076922 部落格主要起到學習和記錄的作用 直接貼程式碼了 private void hookOnClickListener(View view) { try {

java 反射 當Timestamp型別的屬性值為null時,設定預設值

import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Timestamp; class Person {

Spring IOC原理Java反射機制

1、反射概念以及為什麼要使用反射 我們考慮一個場景,如果我們在程式執行時,一個物件想要檢視自己所擁有的成員屬性,該如何操作? 那再考慮這樣另一個場景,如果我們想要在執行期獲得某個類Class的資訊如它

androidjava反射修改Activity的元件view的佈局或者屬性

原因:正所謂技術來源於需求,同時推動需求 , 研究的出發點是,PM發現app的某一個view的元件有些問題,view座標或者顏色、字型大小等,需要rd去修改,但是呢這個元件是第三方的sdk中內建,並沒有提供 對應的介面或者方法,怎麼辦? 以前是這樣的: 方法:反射

Androidjava執行緒池總結

執行緒池 Android培訓實戰教程裡面,耗時的網路操作,都會開子執行緒,在程式裡面直接開過多的執行緒會消耗過多的資源,在眾多的開源框架中也總能看到執行緒池的蹤影,所以執行緒池是必須要會把握的一個知識點; 執行緒執行機制 ·         開啟執行緒過多,會消耗cpu

深入理解AndroidJava Security第二部分(Final)

深入理解Android之Java Security(第二部分,最後)程式碼路徑:Security.java:libcore/lunl/src/main/java/java/security/TrustedCertificateStore.java:libcore /crypt