Cách tĩnh để có được 'Bối cảnh' trong Android?


970

Có cách nào để lấy Contextcá thể hiện tại bên trong một phương thức tĩnh không?

Tôi đang tìm kiếm theo cách đó bởi vì tôi ghét lưu phiên bản 'Bối cảnh' mỗi khi nó thay đổi.


57
Không lưu Bối cảnh là một ý tưởng tốt không chỉ vì nó bất tiện, mà hơn thế nữa vì nó có thể dẫn đến rò rỉ bộ nhớ lớn!
Vikram Bod Richla

12
@VikramBod Richla Có, nhưng các câu trả lời dưới đây cho rằng chúng ta đang nói về bối cảnh ứng dụng. Vì vậy, rò rỉ bộ nhớ không phải là một vấn đề, nhưng người dùng chỉ nên sử dụng các giải pháp này trong đó đó là bối cảnh chính xác để sử dụng.
Tom

Nếu bạn phải sử dụng một cách tĩnh để nhận Context, thì có thể có một cách tốt hơn để thiết kế mã.
Anonsage

3
Tài liệu Android khuyên bạn nên chuyển ngữ cảnh cho getters của singletons. developer.android.com/reference/android/app/Application.html
Marco Luglio 14/07/2015

Để thích các singletons và bối cảnh được truyền với getInstance () trên bối cảnh tĩnh, xin vui lòng xem, tôi đã cố gắng giải thích lý do của tôi ở đây được hỗ trợ với mã làm việc: stackoverflow.com/a/38967293/4469112
Alessio

Câu trả lời:


1302

Làm cái này:

Trong tệp Bản kê khai Android, khai báo như sau.

<application android:name="com.xyz.MyApplication">

</application>

Sau đó viết lớp:

public class MyApplication extends Application {

    private static Context context;

    public void onCreate() {
        super.onCreate();
        MyApplication.context = getApplicationContext();
    }

    public static Context getAppContext() {
        return MyApplication.context;
    }
}

Bây giờ mọi nơi gọi MyApplication.getAppContext()để có được bối cảnh ứng dụng của bạn tĩnh.


81
Có bất kỳ nhược điểm của phương pháp này? Điều này có vẻ như gian lận. (Một vụ hack?)
jjnguy

203
Nhược điểm là không có gì đảm bảo rằng onCreate () không tĩnh sẽ được gọi trước khi một số mã khởi tạo tĩnh cố gắng tìm nạp đối tượng Ngữ cảnh của bạn. Điều đó có nghĩa là mã gọi của bạn sẽ cần sẵn sàng để xử lý các giá trị null, loại này sẽ đánh bại toàn bộ điểm của câu hỏi này.
Melinda Green

8
Cũng có thể .. chúng ta có nên khai báo static contextbiến này là volatile?
Vladimir Sorokin

14
@Tom Đây không phải là trường hợp thành viên dữ liệu tĩnh ban đầu được tĩnh. Trong mã đã cho, thành viên tĩnh đang được khởi tạo không tĩnh trong onCreate (). Ngay cả dữ liệu khởi tạo tĩnh cũng không đủ tốt trong trường hợp này vì không có gì đảm bảo rằng việc khởi tạo tĩnh của lớp đã cho sẽ xảy ra trước khi nó được truy cập trong quá trình khởi tạo tĩnh của một số lớp khác.
Melinda Green

10
@MelindaGreen Theo tài liệu cho Ứng dụng, onCreate () được gọi trước khi bất kỳ hoạt động, dịch vụ hoặc người nhận (không bao gồm nhà cung cấp nội dung) đã được tạo. Vì vậy, giải pháp này có an toàn không, miễn là bạn không cố truy cập getAppContext () từ nhà cung cấp nội dung?
Magnus W

86

Phần lớn các ứng dụng muốn có một phương thức thuận tiện để lấy bối cảnh ứng dụng tạo lớp riêng của chúng mở rộng android.app.Application.

HƯỚNG DẪN

Bạn có thể thực hiện điều này bằng cách trước tiên tạo một lớp trong dự án của bạn như sau:

import android.app.Application;
import android.content.Context;

public class App extends Application {

    private static Application sApplication;

    public static Application getApplication() {
        return sApplication;
    }

    public static Context getContext() {
        return getApplication().getApplicationContext();
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sApplication = this;
    }
}

Sau đó, trong AndroidManifest của bạn, bạn nên chỉ định tên của lớp trong thẻ của AndroidManifest.xml:

<application 
    ...
    android:name="com.example.App" >
    ...
</application>

Sau đó, bạn có thể truy xuất bối cảnh ứng dụng trong bất kỳ phương thức tĩnh nào bằng cách sử dụng như sau:

public static void someMethod() {
    Context context = App.getContext();
}

CẢNH BÁO

Trước khi thêm một cái gì đó như trên vào dự án của bạn, bạn nên xem xét tài liệu nói gì:

Thông thường không cần phải phân lớp Ứng dụng. Trong hầu hết các tình huống, singletons tĩnh có thể cung cấp chức năng tương tự theo cách mô đun hơn. Nếu singleton của bạn cần một bối cảnh toàn cầu (ví dụ để đăng ký máy thu quảng bá), chức năng truy xuất nó có thể được cung cấp một Ngữ cảnh sử dụng Context.getApplicationContext () khi lần đầu tiên xây dựng singleton.


SỬA CHỮA

Ngoài ra còn có một cách khác để có được bối cảnh ứng dụng bằng cách sử dụng sự phản chiếu. Sự phản chiếu thường bị xem thường trong Android và cá nhân tôi nghĩ rằng điều này không nên được sử dụng trong sản xuất.

Để lấy lại bối cảnh ứng dụng, chúng ta phải gọi một phương thức trên một lớp ẩn ( ActivityThread ) đã có sẵn từ API 1:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.ActivityThread")
            .getMethod("currentApplication").invoke(null, (Object[]) null);
}

Có thêm một lớp ẩn ( AppGlobals ) cung cấp một cách để có được bối cảnh ứng dụng theo cách tĩnh. Nó được sử dụng bối cảnh ActivityThreadđể thực sự không có sự khác biệt giữa phương pháp sau và phương pháp được đăng ở trên:

public static Application getApplicationUsingReflection() throws Exception {
    return (Application) Class.forName("android.app.AppGlobals")
            .getMethod("getInitialApplication").invoke(null, (Object[]) null);
} 

Chúc mừng mã hóa!


56

Giả sử chúng ta đang nói về việc lấy Bối cảnh ứng dụng, tôi đã triển khai nó theo đề xuất của @Rohit Ghatol Ứng dụng mở rộng. Điều gì đã xảy ra sau đó, không có gì đảm bảo rằng bối cảnh được truy xuất theo cách như vậy sẽ luôn là không có giá trị. Tại thời điểm bạn cần, thường là vì bạn muốn khởi tạo một người trợ giúp hoặc nhận tài nguyên mà bạn không thể trì hoãn kịp thời; xử lý các trường hợp null sẽ không giúp bạn. Vì vậy, tôi hiểu rằng về cơ bản tôi đã chiến đấu chống lại kiến ​​trúc Android, như đã nêu trong các tài liệu

Lưu ý: Thông thường không cần phải phân lớp Ứng dụng. Trong hầu hết các tình huống, singletons tĩnh có thể cung cấp cùng chức năng theo cách mô đun hơn. Nếu singleton của bạn cần một bối cảnh toàn cầu (ví dụ để đăng ký máy thu quảng bá), hãy bao gồm Context.getApplicationContext () làm đối số Ngữ cảnh khi gọi phương thức getInstance () của singleton.

và được giải thích bởi Dianne Hackborn

Lý do duy nhất khiến Ứng dụng tồn tại như một thứ bạn có thể rút ra là vì trong quá trình phát triển trước 1.0, một trong những nhà phát triển ứng dụng của chúng tôi đã liên tục làm phiền tôi về việc cần phải có một đối tượng ứng dụng cấp cao nhất mà họ có thể xuất phát để họ có thể có "bình thường hơn" "Đối với họ mô hình ứng dụng, và cuối cùng tôi đã nhượng bộ. Tôi sẽ hối hận mãi mãi về cái đó. :)

Cô cũng đang đề xuất giải pháp cho vấn đề này:

Nếu những gì bạn muốn là một số trạng thái toàn cầu có thể được chia sẻ trên các phần khác nhau của ứng dụng của bạn, hãy sử dụng một singleton. [...] Và điều này dẫn đến cách bạn nên quản lý những thứ này một cách tự nhiên hơn - khởi tạo chúng theo yêu cầu.

Vì vậy, những gì tôi đã làm là thoát khỏi việc mở rộng Ứng dụng và chuyển trực tiếp ngữ cảnh đến getInstance () của trình trợ giúp đơn lẻ, đồng thời lưu tham chiếu đến ngữ cảnh ứng dụng trong hàm tạo riêng:

private static MyHelper instance;
private final Context mContext;    

private MyHelper(@NonNull Context context) {
    mContext = context.getApplicationContext();
}

public static MyHelper getInstance(@NonNull Context context) {
    synchronized(MyHelper.class) {
        if (instance == null) {
            instance = new MyHelper(context);
        }
        return instance;
    }
}

người gọi sau đó sẽ chuyển một bối cảnh cục bộ cho người trợ giúp:

Helper.getInstance(myCtx).doSomething();

Vì vậy, để trả lời đúng câu hỏi này: có nhiều cách để truy cập Bối cảnh ứng dụng một cách tĩnh, nhưng tất cả chúng đều không được khuyến khích và bạn nên chuyển ngữ cảnh cục bộ sang getInstance () của singleton.


Đối với bất kỳ ai quan tâm, bạn có thể đọc phiên bản chi tiết hơn tại blog fwd


1
@Alessio Phương pháp này không dẫn đến rò rỉ bộ nhớ
Phillip Kigenyi

2
@codephillip Tôi không hiểu bạn đang nói về cái gì. Các singleton tham chiếu bối cảnh ứng dụng lấy từ hoạt động được thông qua, không phải hoạt động máy chủ. Điều đó là hợp pháp và nó sẽ không gây rò rỉ bộ nhớ. Đó là điểm chính của blog tôi đã viết. Nếu bạn thực sự nghĩ rằng bạn đúng, xin vui lòng gửi cho tôi một mã mẫu để tôi có thể tái tạo rò rỉ bộ nhớ mà bạn đang nói đến, bởi vì đó không phải là trường hợp.
Alessio

1
Tôi nghĩ rằng @KigenyiPhillip là chính xác và điều này vẫn thể hiện sự rò rỉ tài nguyên. Hình ảnh biểu đồ tham chiếu sau cuộc gọi đầu tiên của bạn đến getInstance(ctx). Bạn có một gốc instanceloại GC MyHelper, có một trường mContextloại riêng Context, tham chiếu đến bối cảnh ứng dụng được thu thập thông qua bối cảnh được truyền tới getInstance(). instancekhông bao giờ được đặt lần thứ hai, cũng không bị xóa, do đó, GC sẽ không bao giờ bắt được appcontext được tham chiếu bởi instance. Bạn không rò rỉ bất kỳ hoạt động nào vì vậy IMO chi phí thấp.
Đánh dấu McKenna

1
@MarkMcKenna khi bạn nêu "có một trường riêng mContext thuộc loại Bối cảnh, tham chiếu đến bối cảnh ứng dụng", vì vậy, rõ ràng với bạn rằng mContext là một tham chiếu đến bối cảnh ứng dụng, không phải cho bất kỳ bối cảnh nào. Trong tài liệu getApplicationContext () bạn đọc: "Bối cảnh có vòng đời tách biệt với bối cảnh hiện tại, được gắn với vòng đời của quy trình thay vì thành phần hiện tại". Làm thế nào điều này có thể tạo ra một rò rỉ bộ nhớ? Bối cảnh ứng dụng chỉ là GC'd khi quá trình thoát.
Alessio

1
@Alessio nếu bạn chấp nhận rằng một tham chiếu đến bối cảnh ứng dụng không đủ điều kiện như một sự rò rỉ tài nguyên, sau đó bạn có thể đơn giản hóa này bằng cách đăng một tài liệu tham khảo tĩnh để thisApplication.onCreate(), mà làm cho câu trả lời được chấp nhận hơn.
Đánh dấu McKenna


38

Đây là một cách không có giấy tờ để nhận Ứng dụng (là Ngữ cảnh) từ bất kỳ đâu trong luồng UI. Nó dựa vào phương thức tĩnh ẩn ActivityThread.currentApplication(). Nó nên hoạt động ít nhất trên Android 4.x.

try {
    final Class<?> activityThreadClass =
            Class.forName("android.app.ActivityThread");
    final Method method = activityThreadClass.getMethod("currentApplication");
    return (Application) method.invoke(null, (Object[]) null);
} catch (final ClassNotFoundException e) {
    // handle exception
} catch (final NoSuchMethodException e) {
    // handle exception
} catch (final IllegalArgumentException e) {
    // handle exception
} catch (final IllegalAccessException e) {
    // handle exception
} catch (final InvocationTargetException e) {
    // handle exception
}

Lưu ý rằng phương thức này có thể trả về null, ví dụ như khi bạn gọi phương thức bên ngoài luồng UI hoặc ứng dụng không bị ràng buộc với luồng.

Vẫn tốt hơn khi sử dụng giải pháp của @RohitGhatol nếu bạn có thể thay đổi mã Ứng dụng.


1
Tôi đã sử dụng phương pháp KennyTM ở trên, nhưng đôi khi phương thức trả về null. Có một số thay thế khác cho điều này? Giống như nếu chúng ta có một null ở đây, chúng ta có thể lấy bối cảnh từ nơi khác. Trong trường hợp của tôi, onCreate () của Ứng dụng không được gọi. Nhưng phương pháp trên được gọi trước nó. Trợ giúp Plzzz
AndroidGuy

Điều này sẽ không luôn luôn hoạt động trong trường hợp GC làm sạch tất cả những thứ liên quan đến hoạt động.
AlexVPerl

32

Nó phụ thuộc vào những gì bạn đang sử dụng bối cảnh cho. Tôi có thể nghĩ về ít nhất một nhược điểm của phương pháp đó:

Nếu bạn đang cố gắng tạo một AlertDialogvới AlertDialog.Builder, Applicationbối cảnh sẽ không hoạt động. Tôi tin rằng bạn cần bối cảnh cho hiện tại Activity...


6
Đúng rồi. Nếu bạn sử dụng bối cảnh ứng dụng cho điều đó, bạn có thể thấy hộp thoại của mình bị ẩn dưới các hoạt động nền trước.
Nate

3
+1 trước hết. Và lỗi có thể xảy ra là Không thể bắt đầu hoạt động ElementInfo {com.samples / com.MyActivity}: android.view.WindowManager $ BadTokenException: Không thể thêm cửa sổ - token null không dành cho ứng dụng
Govind

15

Cách của Kotlin :

Rõ ràng:

<application android:name="MyApplication">

</application>

MyApplication.kt

class MyApplication: Application() {

    override fun onCreate() {
        super.onCreate()
        instance = this
    }

    companion object {
        lateinit var instance: MyApplication
            private set
    }
}

Sau đó bạn có thể truy cập vào tài sản thông qua MyApplication.instance


11

Nếu bạn mở để sử dụng RoboGuice , bạn có thể đưa ngữ cảnh vào bất kỳ lớp nào bạn muốn. Đây là một ví dụ nhỏ về cách thực hiện với RoboGuice 2.0 (bản beta 4 tại thời điểm viết bài này)

import android.content.Context;
import android.os.Build;
import roboguice.inject.ContextSingleton;

import javax.inject.Inject;

@ContextSingleton
public class DataManager {
    @Inject
    public DataManager(Context context) {
            Properties properties = new Properties();
            properties.load(context.getResources().getAssets().open("data.properties"));
        } catch (IOException e) {
        }
    }
}

8

Tôi đã sử dụng điều này tại một số điểm:

ActivityThread at = ActivityThread.systemMain();
Context context = at.getSystemContext();

Đây là một bối cảnh hợp lệ tôi đã sử dụng để nhận các dịch vụ hệ thống và làm việc.

Nhưng, tôi chỉ sử dụng nó trong các sửa đổi khung / cơ sở và không thử nó trong các ứng dụng Android.

Một cảnh báo mà bạn phải biết: Khi đăng ký máy thu phát với bối cảnh này, nó sẽ không hoạt động và bạn sẽ nhận được:

java.lang.SecurityException: Đưa ra gói người gọi android không chạy trong tiến trình ProcessRecord


7

Kotlin

open class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        mInstance = this
    }

    companion object {
        lateinit var mInstance: MyApp
        fun getContext(): Context? {
            return mInstance.applicationContext
        }
    }
}

và có được bối cảnh như

MyApp.mInstance

hoặc là

MyApp.getContext()

4

Bạn có thể sử dụng như sau:

MainActivity.this.getApplicationContext();

MainActivity.java:

...
public class MainActivity ... {
    static MainActivity ma;
...
    public void onCreate(Bundle b) {
         super...
         ma=this;
         ...

Bất kỳ lớp nào khác:

public ...
    public ANY_METHOD... {
         Context c = MainActivity.ma.getApplicationContext();

3
Điều này chỉ hoạt động nếu bạn ở trong một lớp bên trong, điều mà hầu như không xảy ra trong OP.
Richard J. Ross III

3
Điều này sẽ hoạt động miễn là ANY_METHOD được gọi sau khi MainActivity được tạo, nhưng việc giữ các tham chiếu tĩnh cho các hoạt động gần như chắc chắn sẽ gây rò rỉ bộ nhớ (như các câu trả lời khác cho câu hỏi của OP đã đề cập), vì vậy nếu bạn thực sự phải giữ tham chiếu tĩnh, hãy sử dụng ứng dụng chỉ bối cảnh.
handtwerk

1
Nội tâm là ác. Điều tồi tệ nhất là rất nhiều người làm điều đó cho
AsyncT Nhiệm vụ

4

Nếu bạn không muốn sửa đổi tệp kê khai, bạn có thể lưu trữ ngữ cảnh theo cách thủ công trong một biến tĩnh trong hoạt động ban đầu của mình:

public class App {
    private static Context context;

    public static void setContext(Context cntxt) {
        context = cntxt;
    }

    public static Context getContext() {
        return context;
    }
}

Và chỉ đặt bối cảnh khi hoạt động (hoặc hoạt động) của bạn bắt đầu:

// MainActivity

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Set Context
    App.setContext(getApplicationContext());

    // Other stuff
}

Lưu ý: Giống như tất cả các câu trả lời khác, đây là một rò rỉ bộ nhớ tiềm năng.


1
Chính xác thì nó sẽ bị rò rỉ vì bối cảnh trong trường hợp này bị ràng buộc với ứng dụng? Nếu ứng dụng chết, mọi thứ khác cũng vậy.
TheRealChx101

3

Tôi nghĩ rằng bạn cần một cơ thể cho getAppContext()phương pháp:

public static Context getAppContext()
   return MyApplication.context; 

3

Theo nguồn này, bạn có thể có được Ngữ cảnh của riêng mình bằng cách mở rộng ContextWrapper

public class SomeClass extends ContextWrapper {

    public SomeClass(Context base) {
      super(base);
    }

    public void someMethod() {
        // notice how I can use "this" for Context
        // this works because this class has it's own Context just like an Activity or Service
        startActivity(this, SomeRealActivity.class);

        //would require context too
        File cacheDir = getCacheDir();
    }
}

JavaDoc cho ContextWrapper

Việc triển khai ủy quyền của Ngữ cảnh chỉ đơn giản là ủy thác tất cả các cuộc gọi của nó đến một Ngữ cảnh khác. Có thể được phân lớp để sửa đổi hành vi mà không thay đổi Ngữ cảnh gốc.


1
Hay đấy. Tốt để tìm hiểu về ContextWrapper. Tuy nhiên, nếu bạn cần chuyển trong ngữ cảnh ứng dụng cho hàm tạo này, bạn vẫn cần lấy nó từ đâu đó.
jk7

2

Nếu bạn vì một lý do nào đó muốn bối cảnh Ứng dụng trong bất kỳ lớp nào, không chỉ những ứng dụng / hoạt động mở rộng, có thể cho một số lớp nhà máy hoặc người trợ giúp. Bạn có thể thêm các singleton sau vào ứng dụng của bạn.

public class GlobalAppContextSingleton {
    private static GlobalAppContextSingleton mInstance;
    private Context context;

    public static GlobalAppContextSingleton getInstance() {
        if (mInstance == null) mInstance = getSync();
        return mInstance;
    }

    private static synchronized GlobalAppContextSingleton getSync() {
        if (mInstance == null) mInstance = 
                new GlobalAppContextSingleton();
        return mInstance;
    }

    public void initialize(Context context) {
        this.context = context;
    }

    public Context getApplicationContext() {
        return context;
    }
}

sau đó khởi tạo nó trong onCreate của lớp ứng dụng của bạn với

GlobalAppContextSingleton.getInstance().initialize(this);

sử dụng nó bất cứ nơi nào bằng cách gọi

GlobalAppContextSingleton.getInstance().getApplicationContext()

Tôi không đề xuất cách tiếp cận này cho bất cứ điều gì trừ bối cảnh ứng dụng. Vì nó có thể gây rò rỉ bộ nhớ.


Nó không giống như các tên lớp / phương thức được đặt trong đá, giữ nó dài và (hy vọng) mô tả cho một câu hỏi và trả lời, rút ​​ngắn nó để sử dụng cho riêng tôi.
Versa

1

Tôi sử dụng một biến thể của mẫu thiết kế Singleton để giúp tôi điều này.

import android.app.Activity;
import android.content.Context;

public class ApplicationContextSingleton {
    private static Activity gContext;

    public static void setContext( Activity activity) {
        gContext = activity;
    }

    public static Activity getActivity() {
        return gContext;
    }

    public static Context getContext() {
        return gContext;
    }
}

Sau đó tôi gọi hoạt độngApplicationContextSingleton.setContext( this ); của mình.onCreate () và trong onDestroy () ;ApplicationContextSingleton.setContext( null );


Nếu tất cả những gì bạn cần là ngữ cảnh, bạn có thể gọi Activity.getApplicationContext (); Điều đó có thể được giữ tĩnh mà không phải lo lắng về rò rỉ.
MinceMan

2
điều này sẽ tạo ra rò rỉ bộ nhớ
BlueWizard

1

Tôi vừa phát hành một khung lấy cảm hứng từ jQuery cho Android có tên Vapor API nhằm mục đích làm cho việc phát triển ứng dụng trở nên đơn giản hơn.

Lớp $mặt tiền trung tâm duy trì một WeakReference(liên kết đến bài đăng blog Java tuyệt vời về điều này của Ethan Nicholas) đến Activitybối cảnh hiện tại mà bạn có thể truy xuất bằng cách gọi:

$.act()

Một WeakReferenceduy trì một tài liệu tham khảo mà không ngăn chặn bộ sưu tập rác lấy lại đối tượng ban đầu, vì vậy bạn không nên có vấn đề với rò rỉ bộ nhớ.

Nhược điểm của khóa học là bạn gặp rủi ro $.act()có thể trả về null. Mặc dù vậy, tôi chưa bắt gặp kịch bản này, vì vậy có lẽ đó chỉ là một rủi ro tối thiểu, đáng nói.

Bạn cũng có thể đặt bối cảnh theo cách thủ công nếu bạn không sử dụng VaporActivitylàm Activitylớp của mình :

$.act(Activity);

Ngoài ra, phần lớn khung API Vapor sử dụng bối cảnh được lưu trữ này vốn có nghĩa là bạn hoàn toàn không cần phải lưu trữ nó nếu bạn quyết định sử dụng khung. Kiểm tra trang web để biết thêm thông tin và mẫu.

Tôi hy vọng điều đó sẽ giúp :)


1
Rõ ràng điều này chỉ bị hạ thấp .. một lời giải thích sẽ tốt đẹp!?
Darius

1
Tôi đã không đánh giá thấp điều này, nhưng Javascript không liên quan gì đến câu hỏi, điều đó sẽ giải thích bất kỳ sự hạ thấp nào bạn có thể có! Chúc mừng.
Ernani Joppert

Điều đó sẽ khá vô lý khi nó được lấy cảm hứng từ một số khía cạnh của jQuery như giao diện trôi chảy và trừu tượng hóa của nó .. đó là những nguyên tắc không thể tin được của ngôn ngữ cơ bản!
Darius

1
Vì vậy, bạn đang hạ thấp nó bởi vì nó được lấy cảm hứng từ ngữ nghĩa API của một khung không nằm trên cùng một nền tảng?! Tôi nghĩ rằng các bạn bỏ lỡ quan điểm áp dụng các nguyên tắc bất khả tri của nền tảng .....................................
Darius

3
câu trả lời này hoàn toàn không liên quan đến JavaScript. Đọc câu trả lời trước khi bạn downvote: /
BlueWizard

1

Câu trả lời của Rohit có vẻ đúng. Tuy nhiên, lưu ý rằng "Chạy ngay lập tức" của AndroidStudio phụ thuộc vào việc không có static Contextthuộc tính trong mã của bạn, theo như tôi biết.


1
Bạn đúng rồi. Và nó cũng sẽ dẫn đến rò rỉ bộ nhớ!
user1506104

1

trong Kotlin, việc đặt Bối cảnh / Bối cảnh ứng dụng vào đối tượng đồng hành vẫn tạo ra cảnh báo Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run)

hoặc nếu bạn sử dụng một cái gì đó như thế này:

    companion object {
        lateinit var instance: MyApp
    }

Nó chỉ đơn giản là đánh lừa việc không phát hiện ra rò rỉ bộ nhớ, đối tượng Ứng dụng vẫn có thể tạo ra rò rỉ bộ nhớ, vì lớp Ứng dụng và hậu duệ của nó là một Ngữ cảnh.

Ngoài ra, bạn có thể sử dụng giao diện chức năng hoặc thuộc tính Chức năng để giúp bạn có được bối cảnh ứng dụng của mình.

Đơn giản chỉ cần tạo một lớp đối tượng:

object CoreHelper {
    lateinit var contextGetter: () -> Context
}

hoặc bạn có thể sử dụng nó an toàn hơn bằng cách sử dụng loại nullable:

object CoreHelper {
    var contextGetter: (() -> Context)? = null
}

và trong lớp Ứng dụng của bạn thêm dòng này:


class MyApp: Application() {

    override fun onCreate() {
        super.onCreate()
        CoreHelper.contextGetter = {
            this
        }
    }
}

và trong bảng kê khai của bạn, hãy khai báo tên ứng dụng . MyApp


    <application
            android:name=".MyApp"

Khi bạn muốn có được bối cảnh chỉ cần gọi:

CoreHelper.contextGetter()

// or if you use the nullable version
CoreHelper.contextGetter?.invoke()

Hy vọng nó sẽ giúp.


Lớp đối tượng của corercper này sẽ được khởi tạo và có thể được sử dụng thông qua các hoạt động ở giai đoạn sau? Xin lỗi tôi mới biết về kotlin
Tiến sĩ aNdRO

đúng chính xác.
Hayi Nukman

-1

Hãy thử một cái gì đó như thế này

import androidx.appcompat.app.AppCompatActivity;  
import android.content.Context; 
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {
    private static Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context = getApplicationContext();
    }

    public static void getContext(View view){
        Toast.makeText(context, "Got my context!",
                    Toast.LENGTH_LONG).show();    
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.