Sử dụng getResource () trong lớp không hoạt động


123

Tôi đang cố gắng sử dụng phương thức getResource trong một lớp không hoạt động. Làm cách nào để có được tham chiếu đến đối tượng "tài nguyên" để tôi có thể truy cập tệp xml được lưu trong thư mục tài nguyên?

Thí dụ:

XmlPullParser xpp = getResources().getXml(R.xml.samplexml);

Thông thường không phải là một ý tưởng tốt để vượt qua Contextcác đối tượng trong Android. Nó có thể dẫn đến rò rỉ bộ nhớ. Xem câu trả lời của tôi cho một giải pháp ít rủi ro hơn.
Jason Crosby

Câu trả lời:


147

Bạn sẽ phải truyền một contextđối tượng cho nó. Hoặc thisnếu bạn có một tham chiếu đến lớp trong một hoạt động, hoặcgetApplicationContext()

public class MyActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        RegularClass regularClass = new RegularClass(this);
    }
}

Sau đó, bạn có thể sử dụng nó trong hàm tạo (hoặc đặt nó thành một biến thể hiện):

public class RegularClass(){
    private Context context;

    public RegularClass(Context current){
        this.context = current;
    }

    public findResource(){
        context.getResources().getXml(R.xml.samplexml);
    }
}

Trường hợp hàm tạo chấp nhận Contextlàm tham số


7
Thông thường không phải là một ý tưởng tốt để vượt qua Contextcác đối tượng trong Android. Nó có thể dẫn đến rò rỉ bộ nhớ.
Jason Crosby

28
Như một quy tắc cơ bản của ngón tay cái chắc chắn, nhưng tôi cảm thấy điều này là hơi sai lệch. Contextcác đối tượng là khó chịu vì nó không rõ ràng ngay lập tức nếu nó là toàn ứng dụng hoặc toàn hoạt động. Rò rỉ bộ nhớ (và sự cố) xảy ra khi bạn cung cấp sai. Ví dụ, việc cung cấp một Activityđối tượng tĩnh cần một Contextđối tượng nói và không bị phá hủy khi Activitydẫn đến sự Activitytồn tại sau onDestroy, vì nó không thể được xử lý do đối tượng tĩnh khác này. Vì vậy, có, nó có thể nguy hiểm, nhưng biết tại sao nó nguy hiểm tôi cảm thấy rất quan trọng để đề cập ở đây.
Dororo

2
^ Dororo, Đây là một trong những bình luận quan trọng nhất mà tôi từng đọc. Sử dụng đúng ngữ cảnh hiếm khi được, thảo luận. Tôi có cảm giác tôi đã có nhiều lỗi không thể giải thích được vì nó!
Jonathan Dunn

@Dororo Vậy bạn có gợi ý thực hành nào không? Chúng ta có nên cố gắng tránh để vượt qua các biến bối cảnh? Vậy thì chúng ta có thể làm gì khi cần một số api từ lớp hoạt động?
Alston

35

Nó không phải là một ý tưởng tốt để vượt qua Contextcác đối tượng xung quanh. Điều này thường sẽ dẫn đến rò rỉ bộ nhớ. Đề nghị của tôi là bạn không làm điều đó. Tôi đã tạo ra nhiều ứng dụng Android mà không phải chuyển ngữ cảnh cho các lớp không hoạt động trong ứng dụng. Một ý tưởng tốt hơn sẽ là lấy các tài nguyên bạn cần truy cập trong khi bạn ở trong Activityhoặc Fragment, và giữ nó trong một lớp khác. Sau đó, bạn có thể sử dụng lớp đó trong bất kỳ lớp nào khác trong ứng dụng của mình để truy cập tài nguyên mà không phải chuyển qua Contextcác đối tượng.


Đây là lời khuyên tốt cảm ơn. Nó có phải là một vấn đề trong SQLiteOpenHelper không? Trong constructor, bạn phải vượt qua một bối cảnh. Nó không còn có sẵn trong các phương thức khác nhưng tôi có thể lưu trữ nó trong một lĩnh vực riêng tư.
Peter

2
@Peter Có một số lớp yêu cầu bạn phải vượt qua trong một đối tượng bối cảnh. Vì vậy, tốt nhất là cố gắng chỉ sử dụng các lớp như SqLiteOpenHelper trong một hoạt động hoặc đoạn để bạn không phải vượt qua đối tượng bối cảnh. Nếu không thể tránh khỏi, chỉ cần đảm bảo rằng bạn đặt tham chiếu của mình thành đối tượng ngữ cảnh thành null khi hoàn thành để giúp giảm nguy cơ rò rỉ bộ nhớ.
Jason Crosby

1
Vượt qua đối tượng bối cảnh không phải lúc nào cũng xấu, miễn là bạn có thể theo dõi vòng đời của hoạt động. Nếu không thì tốt hơn nên sử dụng bối cảnh Ứng dụng thay vì bối cảnh Hoạt động bằng cách sử dụng getApplicationContext () để tránh rò rỉ bộ nhớ. Xem stackoverflow.com/questions/7144177/ cấp để lấy bối cảnh ứng dụng.
FrozenFire

14

Có một cách nữa mà không tạo ra một đối tượng cũng có. Kiểm tra tài liệu tham khảo . Cảm ơn @cristian. Dưới đây tôi thêm các bước được đề cập trong tài liệu tham khảo ở trên. Đối với tôi, tôi không muốn tạo một đối tượng cho điều đó và truy cập. Vì vậy, tôi đã cố gắng truy cập getResources()mà không tạo ra một đối tượng. Tôi tìm thấy bài này. Vì vậy, tôi nghĩ để thêm nó như là một câu trả lời.

Thực hiện theo các bước để truy cập getResources()trong một lớp không hoạt động without passing a contextthông qua đối tượng.

  • Tạo một lớp con của Application, ví dụ public class App extends Application {. Tham khảo mã bên cạnh các bước.
  • Đặt android:namethuộc tính của <application>thẻ của bạn trong AndroidManifest.xmlđể trỏ đến lớp mới của bạn, ví dụ:android:name=".App"
  • Trong onCreate()phương thức của ứng dụng của bạn, hãy lưu ngữ cảnh của bạn (ví dụ this) vào trường tĩnh có tên appvà tạo một phương thức tĩnh trả về trường này, vd getContext().
  • Bây giờ bạn có thể sử dụng: App.getContext()bất cứ khi nào bạn muốn có được một bối cảnh, và sau đó chúng ta có thể sử dụng App.getContext().getResources()để lấy các giá trị từ các tài nguyên.

Đây là cách nó sẽ trông:

public class App extends Application{

    private static Context mContext;

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

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

5

đây là câu trả lời của tôi

public class WigetControl {
private Resources res;

public WigetControl(Resources res) 
{
    this.res = res;
}

public void setButtonDisable(Button mButton)
{
    mButton.setBackgroundColor(res.getColor(R.color.loginbutton_unclickable));
    mButton.setEnabled(false);
}

}

và cuộc gọi có thể như thế này:

        WigetControl control = new WigetControl(getResources());
        control.setButtonDisable(btNext);

3

điều này có thể được thực hiện bằng cách sử dụng

context.getResources().getXml(R.xml.samplexml);

Vâng, điều này đã làm nên điều kỳ diệu cho tôi. Cảm ơn @ARAsha
Kenny Dabiri

vượt qua Contextcác đối tượng không phải là một thực hành lành mạnh
Vemuri Pavan

3

Chúng ta có thể sử dụng bối cảnh Giống như thử ngay bây giờ Trường hợp cha mẹ là Viewgroup.

Context context = parent.getContext();

1

cũng không cần phải vượt qua bối cảnh và làm tất cả những điều đó ... chỉ cần làm điều này

Context context = parent.getContext();

Chỉnh sửa: trong đó cha mẹ là Viewgroup


3
Tôi hy vọng bạn đã bị hạ thấp vì cho rằng có một biến thành viên 'Viewgroup cha' thuận tiện. Giả định khá ngu ngốc.
arnt

1

Điều này luôn làm việc cho tôi:

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

public class yourClass {

 Context ctx;

 public yourClass (Handler handler, Context context) {
 super(handler);
    ctx = context;
 }

 //Use context (ctx) in your code like this:
 XmlPullParser xpp = ctx.getResources().getXml(R.xml.samplexml);
 //OR
 final Intent intent = new Intent(ctx, MainActivity.class);
 //OR
 NotificationManager notificationManager = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
 //ETC...

}

Không liên quan đến câu hỏi này nhưng ví dụ sử dụng Fragment để truy cập tài nguyên / hoạt động của hệ thống như thế này:

public boolean onQueryTextChange(String newText) {
 Activity activity = getActivity();
 Context context = activity.getApplicationContext();
 returnSomething(newText);
 return false;
}

View customerInfo = getActivity().getLayoutInflater().inflate(R.layout.main_layout_items, itemsLayout, false);
 itemsLayout.addView(customerInfo);

1

Trong ứng dụng hướng dẫn du lịch của khóa học ANdroid cơ bản của Udacity, tôi đã sử dụng khái niệm Mảnh vỡ. Tôi đã bị kẹt trong một thời gian gặp khó khăn để truy cập một số tài nguyên chuỗi được mô tả trong chuỗi, tệp xml. Cuối cùng cũng có giải pháp.

Đây là lớp hoạt động chính

gói com.example.android.tourguidekolkata;

import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState)
{
  //lines of code
   //lines of code
    //lines of code
    YourClass adapter = new YourClass(getSupportFragmentManager(), getApplicationContext()); 
    //lines of code
    // getApplicationContext() method passses the Context of main activity to the class TourFragmentPageAdapter 
}
}

Đây là lớp không hoạt động mở rộng FragmentPageAd CHƯƠNG

public class YourClass extends FragmentPagerAdapter {
private String yourStringArray[] = new String[4];
Context context;

public YourClass (FragmentManager fm, Context context)
{
    super(fm);
    this.context = context; // store the context of main activity
    // now you can use this context to access any resource 
    yourStringArray[0] = context.getResources().getString(R.string.tab1);
    yourStringArray[1] = context.getResources().getString(R.string.tab2);
    yourStringArray[2] = context.getResources().getString(R.string.tab3);
    yourStringArray[3] = context.getResources().getString(R.string.tab4);
}
@Override
public Fragment getItem(int position)
 {
 }
@Override
public int getCount() {
return 4;
}

@Override
public CharSequence getPageTitle(int position) {
// Generate title based on item position
return yourStringArras[position];
}
}

0

Trong lớp đơn giản khai báo ngữ cảnh và lấy dữ liệu từ tệp từ thư mục res

public class FileData
{
      private Context context;

        public FileData(Context current){
            this.context = current;
        }
        void  getData()
        {
        InputStream in = context.getResources().openRawResource(R.raw.file11);
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        //write stuff to get Data

        }
}

Trong lớp hoạt động khai báo như thế này

public class MainActivity extends AppCompatActivity 
{
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        FileData fileData=new FileData(this);
     }

}

0

Tôi đến trễ nhưng giải pháp hoàn chỉnh;: Lớp ví dụ, Sử dụng bối cảnh như thế này: -

public class SingletonSampleClass {

    // Your cute context
    private Context context;
    private static SingletonSampleClass instance;

  // Pass as Constructor
    private SingletonSampleClass(Context context) {
        this.context = context;
    }

    public synchronized static SingletonSampleClass getInstance(Context context) {
        if (instance == null) instance = new SingletonSampleClass(context);
        return instance;
    }

//At end, don't forgot to relase memory
    public void onDestroy() {
       if(context != null) {
          context = null; 
       }
    }
}

Cảnh báo (Rò rỉ bộ nhớ)

Làm thế nào để giải quyết điều này?

Tùy chọn 1 : Thay vì chuyển ngữ cảnh hoạt động tức là vào lớp singleton, bạn có thể truyền applicationContext ().

Tùy chọn 2: Nếu bạn thực sự phải sử dụng bối cảnh hoạt động, thì khi hoạt động bị hủy, hãy đảm bảo rằng bối cảnh bạn chuyển đến lớp singleton được đặt thành null.

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


0

trong MainActivity của bạn:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if(ResourcesHelper.resources == null){
             ResourcesHelper.resources = getResources();
        }
    }
}

Tài nguyênHelper:

public class ResourcesHelper {
    public static Resources resources;
}

sau đó sử dụng nó ở mọi nơi

String s = ResourcesHelper.resources.getString(R.string.app_name);
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.