2009-06-22 29 views
352

Trong bit khác nhau của mã Android Tôi đã nhìn thấy:Sự khác biệt giữa các phương pháp khác nhau để có được một bối cảnh là gì?

public class MyActivity extends Activity { 
    public void method() { 
     mContext = this; // since Activity extends Context 
     mContext = getApplicationContext(); 
     mContext = getBaseContext(); 
    } 
} 

Tuy nhiên tôi không thể tìm thấy bất kỳ lời giải thích đàng hoàng trong số đó là thích hợp hơn, và trong hoàn cảnh nào đó nên được sử dụng.

Con trỏ hướng dẫn về tài liệu này và hướng dẫn về những gì có thể bị phá vỡ nếu chọn sai, sẽ được đánh giá cao.

+2

Liên kết này có thể giúp bạn. Đi qua [this] (http://droidpassion.blogspot.in/2012/03/all-about-context.html) .. – Aju

Trả lời

284

Tôi đồng ý rằng tài liệu rất thưa thớt khi nói đến ngữ cảnh trong Android, nhưng bạn có thể kết hợp với nhau một vài sự kiện từ nhiều nguồn khác nhau.

This blog post vào các nhà phát triển trên blog chính thức của Google Android được viết chủ yếu để giúp rò rỉ bộ nhớ địa chỉ, nhưng cung cấp một số thông tin tốt về bối cảnh cũng như:

Trong một ứng dụng Android thường xuyên, bạn thường có hai loại Bối cảnh, Hoạt động và ứng dụng.

Đọc bài viết thêm một chút nói về sự khác biệt giữa hai và khi bạn có thể muốn xem xét sử dụng bối cảnh ứng dụng (Activity.getApplicationContext()) thay vì sử dụng bối cảnh Hoạt động this). Về cơ bản, ngữ cảnh Ứng dụng được liên kết với Ứng dụng và sẽ luôn giống nhau trong suốt vòng đời của ứng dụng, khi ngữ cảnh Hoạt động được kết hợp với hoạt động và có thể bị phá hủy nhiều lần khi hoạt động bị hủy trong khi thay đổi hướng màn hình và như là.

tôi không thể tìm thấy bất cứ điều gì thực sự khi sử dụng getBaseContext() khác hơn là một bài đăng từ Dianne Hackborn, một trong những kỹ sư của Google làm việc trên Android SDK:

Không sử dụng getBaseContext() , chỉ cần sử dụng Ngữ cảnh mà bạn có.

Đó là từ một bài đăng trên android-developers newsgroup, bạn có thể xem xét đặt câu hỏi của mình ở đó, vì một số người làm việc trên Android theo dõi thực tế nhóm tin tức và câu trả lời.

Vì vậy, tổng thể dường như thích hợp hơn khi sử dụng ngữ cảnh ứng dụng toàn cầu khi có thể.

+11

Khi tôi có hoạt động A có thể bắt đầu hoạt động B, từ đó, có thể khởi động lại A với cờ CLEAR_TOP (và có thể lặp lại chu kỳ này nhiều lần) - Tôi nên sử dụng ngữ cảnh nào trong trường hợp này để tránh tạo ra một đường dẫn rất lớn các bối cảnh được tham chiếu? Diana nói sử dụng 'this' thay vì getBaseContext, nhưng sau đó ... hầu hết thời gian A sẽ được tái sử dụng nhưng có những tình huống khi một đối tượng mới cho A sẽ được tạo ra và sau đó A bị rò rỉ. Vì vậy, có vẻ như getBaseContext là sự lựa chọn thích hợp nhất cho hầu hết các trường hợp. Sau đó, không rõ tại sao 'Không sử dụng getBaseContext()'. Ai đó có thể làm rõ điều này? – JBM

+0

cách truy cập vào đối tượng ngữ cảnh bên trong một lớp không mở rộng Hoạt động? – Cole

+1

@Cole, bạn có thể tạo một lớp, mà chúng ta sẽ gọi là "ExampleClass" ở đây, mà hàm tạo của nó lấy một đối tượng Context và khởi tạo một biến cá thể lớp, "appContext". Sau đó, lớp Activity của bạn (hoặc bất kỳ lớp nào khác cho vấn đề đó) có thể gọi một phương thức ExampleClass để sử dụng biến cá thể ExampleClass '' appContext ''. – Archie1986

6

Trước tiên, tôi đồng ý rằng chúng tôi nên sử dụng appcontext bất cứ khi nào có thể. sau đó "này" trong hoạt động. Tôi chưa bao giờ có nhu cầu về basecontext.

Trong các thử nghiệm của tôi, trong hầu hết các trường hợp, chúng có thể được hoán đổi cho nhau. Trong hầu hết các trường hợp, lý do bạn muốn nắm giữ ngữ cảnh là truy cập các tệp, tùy chọn, cơ sở dữ liệu, vv. Các dữ liệu này cuối cùng được phản ánh dưới dạng tệp trong thư mục dữ liệu cá nhân của ứng dụng (/ data/data /). Bất kể bạn sử dụng ngữ cảnh nào, chúng sẽ được ánh xạ tới cùng một thư mục/tập tin, do đó bạn không sao.

Đó là những gì tôi đã quan sát. Có thể có những trường hợp bạn nên phân biệt chúng.

3

Trong một số trường hợp, bạn có thể sử dụng ngữ cảnh Hoạt động trong ngữ cảnh ứng dụng khi chạy một thứ gì đó trong chuỗi. Khi thread hoàn thành việc thực hiện và bạn cần trả lại kết quả về hoạt động của người gọi, bạn cần bối cảnh đó với một trình xử lý.

((YourActivity) context).yourCallbackMethod(yourResultFromThread, ...); 
0

tôi đã chỉ được sử dụng này và getBaseContext khi nướng từ một onClick (Noob rất xanh cho cả Java và Android). Tôi sử dụng điều này khi trình nhấp chuột của tôi trực tiếp trong hoạt động và phải sử dụng getBaseContext trong trình nhấp chuột ẩn danh bên trong. Tôi đoán đó là khá nhiều các trick với getBaseContext, nó có lẽ là trở về bối cảnh của hoạt động trong đó lớp bên trong đang ẩn.

+0

Điều này là sai, nó trả về bối cảnh cơ sở của hoạt động.Để có được hoạt động (một trong những bạn muốn sử dụng như bối cảnh) từ một lớp bên trong vô danh sử dụng một cái gì đó như 'MyActivity.this'. Sử dụng bối cảnh cơ sở như bạn mô tả có lẽ sẽ không gây ra vấn đề nhưng nó là sai. – nickmartens1980

12

Tôi đã đọc chủ đề này cách đây vài ngày, tự hỏi mình cùng một câu hỏi. Quyết định của tôi sau khi đọc điều này rất đơn giản: luôn sử dụng applicationContext.

Tuy nhiên, tôi gặp phải một vấn đề với điều này, tôi đã dành một vài giờ để tìm thấy nó, và một vài giây để giải quyết nó ... (thay đổi một từ ...)

Tôi đang sử dụng một LayoutInflater để thổi phồng một chế độ xem có chứa Spinner.

Vì vậy, đây là hai khả năng:

1)

LayoutInflater layoutInflater = LayoutInflater.from(this.getApplicationContext()); 

2)

LayoutInflater layoutInflater = LayoutInflater.from(this.getBaseContext()); 

Sau đó, tôi đang làm một cái gì đó như thế này:

// managing views part 
    View view = ContactViewer.mLayoutInflater.inflate(R.layout.aViewContainingASpinner, theParentView, false); 
    Spinner spinner = (Spinner) view.findViewById(R.id.theSpinnerId); 
    String[] myStringArray = new String[] {"sweet","love"}; 

    // managing adapter part 
    // The context used here don't have any importance -- both work. 
    ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this.getApplicationContext(), myStringArray, android.R.layout.simple_spinner_item); 
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 
    spinner.setAdapter(adapter); 

    theParentView.addView(view); 

Những gì tôi chú ý: Nếu bạn khởi tạo linearLayout của bạn với applicationContext, sau đó khi bạn click vào spinner trong hoạt động của bạn, bạn sẽ có một ngoại lệ chưa được bắt, đến từ máy ảo dalvik (không phải từ mã của bạn, đó là lý do tại sao tôi đã dành rất nhiều thời gian để tìm sai lầm...).

Nếu bạn sử dụng baseContext, thì không sao, menu ngữ cảnh sẽ mở ra và bạn sẽ có thể chọn trong số các lựa chọn của mình.

Vì vậy, đây là kết luận của tôi: Tôi cho rằng (tôi đã không kiểm tra nó hơn nữa) so với baseContext là cần thiết khi giao dịch với ContextMenu trong hoạt động của bạn ...

thử nghiệm đã được thực hiện mã hóa với API 8 và thử nghiệm trên HTC Desire, android 2.3.3.

Tôi hy vọng nhận xét của tôi đã không chán bạn cho đến nay, và chúc bạn mọi điều tốt đẹp nhất. Chúc mừng mã hóa ;-)

+0

Tôi đã luôn sử dụng "điều này" khi tạo chế độ xem trong một hoạt động. Trên cơ sở rằng nếu hoạt động khởi động lại, các chế độ xem được làm lại và có thể có một ngữ cảnh mới để sử dụng để làm cho các lượt xem trở lại. Nhược điểm như được đăng trong blog của nhà phát triển là trong khi một ImageView được định nghĩa là drawable/bitmap được sử dụng có thể treo vào ngữ cảnh đó. Tuy nhiên đó là những gì tôi làm vào lúc này. Về mã ở nơi khác trong ứng dụng (các lớp bình thường), tôi chỉ sử dụng ngữ cảnh ứng dụng vì nó không cụ thể cho bất kỳ hoạt động hoặc các phần tử giao diện người dùng nào. – JonWillis

41

Đây là những gì tôi đã tìm thấy liên quan đến việc sử dụng các context:

1). Trong phạm vi Activity, sử dụng this để tăng bố cục và menu, đăng ký menu ngữ cảnh, khởi chạy tiện ích, bắt đầu các hoạt động khác, tạo Intent mới trong một Activity, tùy chọn instantiating hoặc các phương pháp khác có sẵn trong Activity.

Inflate bố trí:

View mView = this.getLayoutInflater().inflate(R.layout.myLayout, myViewGroup); 

Bơm menu:

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    super.onCreateOptionsMenu(menu); 
    this.getMenuInflater().inflate(R.menu.mymenu, menu); 
    return true; 
} 

Register menu ngữ cảnh:

this.registerForContextMenu(myView); 

nhanh chóng phụ tùng:

TextView myTextView = (TextView) this.findViewById(R.id.myTextView); 

Bắt đầu một Activity:

Intent mIntent = new Intent(this, MyActivity.class); 
this.startActivity(mIntent); 

sở thích nhanh chóng:

SharedPreferences mSharedPreferences = this.getPreferenceManager().getSharedPreferences(); 

2). Đối với lớp ứng dụng rộng, sử dụng getApplicationContext() vì ngữ cảnh này tồn tại trong thời gian tồn tại của ứng dụng.

Lấy tên của gói Android hiện tại:

public class MyApplication extends Application {  
    public static String getPackageName() { 
     String packageName = null; 
     try { 
      PackageInfo mPackageInfo = getApplicationContext().getPackageManager().getPackageInfo(getApplicationContext().getPackageName(), 0); 
      packageName = mPackageInfo.packageName; 
     } catch (NameNotFoundException e) { 
      // Log error here. 
     } 
     return packageName; 
    } 
} 

Bind một lớp ứng dụng rộng:

Intent mIntent = new Intent(this, MyPersistent.class); 
MyServiceConnection mServiceConnection = new MyServiceConnection(); 
if (mServiceConnection != null) { 
    getApplicationContext().bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE); 
} 

3). Đối với Thính giả và các loại khác của các lớp học Android (ví dụ ContentObserver), sử dụng một bối cảnh thay như:

mContext = this; // Example 1 
mContext = context; // Example 2 

nơi this hoặc context là bối cảnh của một lớp (Hoạt động, vv). thay

Activity bối cảnh:

public class MyActivity extends Activity { 
    private Context mContext; 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState);   
     mContext = this; 
    } 
} 

Listener bối cảnh thay:

public class MyLocationListener implements LocationListener { 
    private Context mContext; 
    public MyLocationListener(Context context) { 
     mContext = context; 
    } 
} 

ContentObserver bối cảnh thay:

public class MyContentObserver extends ContentObserver { 
    private Context mContext; 
    public MyContentObserver(Handler handler, Context context) { 
     super(handler); 
     mContext = context; 
    } 
} 

4). Đối với BroadcastReceiver (bao gồm cả máy thu được nhúng/được nhúng), hãy sử dụng ngữ cảnh của người nhận.

ngoài BroadcastReceiver:

public class MyBroadcastReceiver extends BroadcastReceiver { 
    @Override 
    public void onReceive(Context context, Intent intent) { 
     final String action = intent.getAction(); 
     if (action.equals(Intent.ACTION_SCREEN_OFF)) { 
      sendReceiverAction(context, true); 
     } 
     private static void sendReceiverAction(Context context, boolean state) { 
      Intent mIntent = new Intent(context.getClass().getName() + "." + context.getString(R.string.receiver_action)); 
      mIntent.putExtra("extra", state); 
      context.sendBroadcast(mIntent, null); 
     } 
    } 
} 

inlined/Embedded BroadcastReceiver:

public class MyActivity extends Activity { 
    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      final boolean connected = intent.getBooleanExtra(context.getString(R.string.connected), false); 
      if (connected) { 
       // Do something. 
      } 
     } 
    }; 
} 

5). Đối với Dịch vụ, sử dụng ngữ cảnh riêng của dịch vụ.

public class MyService extends Service { 
    private BroadcastReceiver mBroadcastReceiver; 
    @Override 
    public void onCreate() { 
     super.onCreate(); 
     registerReceiver(); 
    } 
    private void registerReceiver() { 
     IntentFilter mIntentFilter = new IntentFilter(); 
     mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF); 
     this.mBroadcastReceiver = new MyBroadcastReceiver(); 
     this.registerReceiver(this.mBroadcastReceiver, mIntentFilter); 
    } 
} 

6). Đối với bánh mì nướng, thường sử dụng getApplicationContext(), nhưng nếu có thể, sử dụng bối cảnh truyền từ một hoạt động, dịch vụ vv

Sử dụng bối cảnh của ứng dụng:

Toast mToast = Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG); 
mToast.show(); 

Sử dụng bối cảnh truyền từ một nguồn :

public static void showLongToast(Context context, String message) { 
    if (context != null && message != null) { 
     Toast mToast = Toast.makeText(context, message, Toast.LENGTH_LONG); 
     mToast.show(); 
    } 
} 

Và cuối cùng, không sử dụng getBaseContext() như tư vấn bởi các nhà phát triển khuôn khổ của Android.

CẬP NHẬT: Thêm ví dụ về việc sử dụng Context.

+1

Thay vì mContext người ta có thể sử dụng 'OuterClass.this'; xem nhận xét trong http://stackoverflow.com/questions/9605459/android-why-must-use-getbasecontext-instead-of-this –

+2

+1 cho câu trả lời hữu ích như vậy! Tôi đồng ý rằng câu trả lời được chấp nhận là tốt như câu trả lời được chấp nhận, nhưng thánh molly câu trả lời này là siêu thông tin! Cảm ơn tất cả những ví dụ đó, họ đã giúp tôi hiểu rõ hơn về cách sử dụng ngữ cảnh nói chung. Tôi thậm chí đã sao chép câu trả lời của bạn vào một tệp văn bản trên máy tính của tôi làm tài liệu tham khảo. – Ryan

1

Nói cách đơn giản

getApplicationContext() như tên phương pháp gợi ý sẽ làm cho ứng dụng của bạn biết chi tiết rộng ứng dụng mà bạn có thể truy cập từ bất cứ nơi nào trong ứng dụng. Vì vậy, bạn có thể tận dụng điều này trong dịch vụ ràng buộc, đăng ký phát sóng, vv Application context sẽ vẫn còn cho đến khi thoát ứng dụng.

getActivity() hoặc this sẽ làm cho ứng dụng của bạn biết về màn hình hiện tại cũng hiển thị chi tiết cấp ứng dụng do application context cung cấp. Vì vậy, bất cứ điều gì bạn muốn biết về màn hình hiện tại như WindowActionBarFragementmanger và do đó có sẵn với ngữ cảnh này. Về cơ bản và Activity mở rộng Context. Ngữ cảnh này sẽ vẫn còn cho đến khi thành phần (hoạt động) hiện tại còn sống

Các vấn đề liên quan