Làm thế nào tôi có thể có được một nội dung tài nguyên từ một bối cảnh tĩnh?


168

Tôi muốn đọc các chuỗi từ một xmltệp trước khi tôi làm bất cứ điều gì khác như setTexttrên các widget, vậy làm thế nào tôi có thể làm điều đó mà không cần một đối tượng hoạt động để gọi getResources()?

Câu trả lời:


373
  1. Tạo một lớp con của Application, ví dụpublic class App extends Application {
  2. Đặ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"
  3. Trong onCreate()phương thức ví dụ ứ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 mContextvà tạo phương thức tĩnh trả về trường này, ví dụ getContext():

Đâ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;
    }
}

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 đó getResources()(hoặc App.getContext().getResources()).


9
Sơ thẩm của ứng dụng không phải là một giá trị động, làm thế nào vậy @Gangnus? Trong mọi trường hợp - tôi thấy một cách khó khăn là dựa vào thống kê trong Android không có gì ngoài đau đầu. "Bây giờ bạn nhìn thấy nó, bây giờ bạn không"
Bostone

17
Tôi không thể tránh nghĩ rằng đây là một 'hack'. Mặc dù tôi đang sử dụng nó
Illiax

8
Tốt hơn hay tệ hơn là chỉ truyền vào Bối cảnh như là tham số đầu tiên trong mỗi phương thức tĩnh trong ứng dụng của bạn? Cái trước cảm thấy hacky, nhưng cái sau là không cần thiết lặp đi lặp lại.
Dave

12
Các tài liệu nói rằng "Thông thường không cần phải phân lớp Ứng dụng. Trong hầu hết các trường hợp, các singleton 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 bối cảnh toàn cầu (ví dụ để đăng ký máy thu quảng bá), chức năng sẽ 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. " ~ developer.android.com/reference/android/app/Application.html
David d C e Freitas

25
Để tránh rò rỉ bộ nhớ, tốt hơn hết là lưu trữ Ngữ cảnh trong WeakReference: private WeakReference <Context> mContext; Bối cảnh tĩnh công khai getContext () {return mContext.get (); } Điều này sẽ giúp khi ứng dụng gặp sự cố và bạn không thể đặt bối cảnh tĩnh thành null (WeakReference có thể được thu gom rác).
FrankKrumnow

102

Chỉ dành cho tài nguyên hệ thống!

Sử dụng

Resources.getSystem().getString(android.R.string.cancel)

Bạn có thể sử dụng chúng ở mọi nơi trong ứng dụng của mình, ngay cả trong các khai báo hằng tĩnh!


2
Thật tuyệt. Tôi thường không bị xúc phạm ... chỉ khi ai đó sử dụng chữ hoa: P Đùa thôi. Chà, tiêu chuẩn của bạn hoạt động đối với một số tài nguyên như chuỗi và drawable ... tuy nhiên, như tài liệu nói, nó không hoạt động tốt cho những thứ như các biện pháp định hướng, v.v. Ngoài ra, và quan trọng nhất, điều này sẽ không cho phép bạn có được bối cảnh toàn cầu đôi khi hữu ích cho những thứ có thể cần nó (nêu Toaství dụ, lấy SharedPreferenceví dụ, mở cơ sở dữ liệu, như giáo viên ngôn ngữ Latinh của tôi nói: et cetera ).
Cristian

1
Bạn thậm chí không thể giành được hòa bình trên toàn thế giới bởi nó :-). Nhưng nó giúp giải quyết vấn đề được đặt ra bởi câu hỏi ở đây. Tôi không nói rằng nó giải quyết mọi nhiệm vụ, chỉ có điều nó giải quyết nhiệm vụ của nó gần như ở mọi nơi trong ứng dụng. Tôi đã tìm kiếm giải pháp như vậy trong 10 tháng - tất cả thời gian tôi sử dụng Android. Và bây giờ tôi đã tìm thấy nó.
Gangnus

18
Bạn phải cẩn thận ở đây. Đừng cố tìm tài nguyên ứng dụng của bạn bằng phương pháp này. Đọc bản in đẹp: Trả về một đối tượng Tài nguyên được chia sẻ toàn cầu chỉ cung cấp quyền truy cập vào tài nguyên hệ thống (không có tài nguyên ứng dụng) và không được định cấu hình cho màn hình hiện tại (không thể sử dụng đơn vị thứ nguyên, không thay đổi dựa trên hướng, v.v.).
Bostone

4
@ DroidIn.net Trích dẫn: "Nhưng chỉ dành cho tài nguyên hệ thống!". Tôi biết / * thở dài / *
Gangnus

1
Tôi đã có một ngoại lệ khi sử dụng: android.content.res.Resource $ NotFoundException: ID tài nguyên chuỗi
vinidog

6

Giải pháp Kotlin của tôi là sử dụng bối cảnh Ứng dụng tĩnh:

class App : Application() {
    companion object {
        lateinit var instance: App private set
    }

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

Và lớp String, mà tôi sử dụng ở mọi nơi:

object Strings {
    fun get(@StringRes stringRes: Int, vararg formatArgs: Any = emptyArray()): String {
        return App.instance.getString(stringRes, *formatArgs)
    }
}

Vì vậy, bạn có thể có một cách rõ ràng để có được chuỗi tài nguyên

Strings.get(R.string.some_string)
Strings.get(R.string.some_string_with_arguments, "Some argument")

Xin đừng xóa câu trả lời này, hãy để tôi giữ một câu.


Giải pháp đơn giản và sạch sẽ, cảm ơn bạn đã chia sẻ mã!
Jeehut

Cảm ơn! Mặc dù đây là một giải pháp được biết đến, Stringsrất hữu ích.
CoolMind

4

Ngoài ra còn có một khả năng khác. Tôi tải các shader OpenGl từ các tài nguyên như thế này:

static private String vertexShaderCode;
static private String fragmentShaderCode;

static {
    vertexShaderCode = readResourceAsString("/res/raw/vertex_shader.glsl");
    fragmentShaderCode = readResourceAsString("/res/raw/fragment_shader.glsl");
}

private static String readResourceAsString(String path) {
    Exception innerException;
    Class<? extends FloorPlanRenderer> aClass = FloorPlanRenderer.class;
    InputStream inputStream = aClass.getResourceAsStream(path);

    byte[] bytes;
    try {
        bytes = new byte[inputStream.available()];
        inputStream.read(bytes);
        return new String(bytes);
    } catch (IOException e) {
        e.printStackTrace();
        innerException = e;
    }
    throw new RuntimeException("Cannot load shader code from resources.", innerException);
}

Như bạn có thể thấy, bạn có thể truy cập bất kỳ tài nguyên nào trong đường dẫn /res/... Thay đổi aClasslớp của bạn. Đây cũng là cách tôi tải tài nguyên trong các bài kiểm tra (androidTests)


1
Giải pháp duy nhất hiệu quả với tôi khi không có Activity (phát triển plugin không có lớp có thể mở rộng Ứng dụng). Cảm ơn bạn +1
itaton

3

Người độc thân:

package com.domain.packagename;

import android.content.Context;

/**
 * Created by Versa on 10.09.15.
 */
public class ApplicationContextSingleton {
    private static PrefsContextSingleton mInstance;
    private Context context;

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

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

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

    public Context getApplicationContext() {
        return context;
    }

}

Khởi tạo Singleton trong Applicationlớp con của bạn :

package com.domain.packagename;

import android.app.Application;

/**
 * Created by Versa on 25.08.15.
 */
public class mApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ApplicationContextSingleton.getInstance().initialize(this);
    }
}

Nếu tôi không sai, điều này mang lại cho bạn một liên kết với applicationContext ở mọi nơi, hãy gọi nó với ApplicationContextSingleton.getInstance.getApplicationContext(); Bạn không nên xóa điều này bất cứ lúc nào, vì khi ứng dụng đóng, dù sao thì nó cũng đi theo.

Hãy nhớ cập nhật AndroidManifest.xmlđể sử dụng Applicationlớp con này :

<?xml version="1.0" encoding="utf-8"?>

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.domain.packagename"
    >

<application
    android:allowBackup="true"
    android:name=".mApplication" <!-- This is the important line -->
    android:label="@string/app_name"
    android:theme="@style/AppTheme"
    android:icon="@drawable/app_icon"
    >

Bây giờ bạn sẽ có thể sử dụng ApplicationContextSingleton.getInstance (). GetApplicationContext (). GetResource () từ bất cứ nơi nào, cũng như rất ít nơi mà các lớp con ứng dụng có thể xóa.

Xin vui lòng cho tôi biết nếu bạn thấy bất cứ điều gì sai ở đây, cảm ơn bạn. :)


2

Giải pháp khác:

Nếu bạn có một lớp con tĩnh trong lớp ngoài không tĩnh, bạn có thể truy cập các tài nguyên từ bên trong lớp con thông qua các biến tĩnh trong lớp bên ngoài, mà bạn khởi tạo khi tạo lớp ngoài. Giống

public class Outerclass {

    static String resource1

    public onCreate() {
        resource1 = getString(R.string.text);
    }

    public static class Innerclass {

        public StringGetter (int num) {
            return resource1; 
        }
    }
}

Tôi đã sử dụng nó cho Hàm getPageTitle (vị trí int) của FragmentPagerAd CHƯƠNG tĩnh trong FragmentActivity của tôi rất hữu ích vì I8N.


2

Đường tắt

Tôi sử dụng App.getRes()thay vì App.getContext().getResources()(như @Cristian đã trả lời)

Nó rất đơn giản để sử dụng bất cứ nơi nào trong mã của bạn!

Vì vậy, đây là một giải pháp độc đáo mà bạn có thể truy cập tài nguyên từ bất cứ nơi nào như thế Util class.

(1) Tạo hoặc chỉnh sửa Applicationlớp của bạn .

import android.app.Application;
import android.content.res.Resources;

public class App extends Application {
    private static App mInstance;
    private static Resources res;


    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
        res = getResources();
    }

    public static App getInstance() {
        return mInstance;
    }

    public static Resources getResourses() {
        return res;
    }

}

(2) Thêm trường tên vào manifest.xml <applicationthẻ của bạn . (hoặc Bỏ qua phần này nếu đã có)

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

Bây giờ bạn tốt để đi.

Sử dụng App.getRes().getString(R.string.some_id)bất cứ nơi nào trong mã.


0

Tôi nghĩ rằng, nhiều cách là có thể. Nhưng đôi khi, tôi sử dụng giải pháp này. (toàn cầu):

    import android.content.Context;

    import <your package>.R;

    public class XmlVar {

        private XmlVar() {
        }

        private static String _write_success;

        public static String write_success() {
            return _write_success;
        }


        public static void Init(Context c) {
            _write_success = c.getResources().getString(R.string.write_success);
        }
    }
//After activity created:
cont = this.getApplicationContext();
XmlVar.Init(cont);
//And use everywhere
XmlVar.write_success();

0

Tôi tải shader cho openGL ES từ hàm tĩnh.

Hãy nhớ rằng bạn phải sử dụng chữ thường cho tên tệp và thư mục của mình, nếu không thao tác sẽ không thành công

public class MyGLRenderer implements GLSurfaceView.Renderer {

    ...

    public static int loadShader() {
        //    Read file as input stream
        InputStream inputStream = MyGLRenderer.class.getResourceAsStream("/res/raw/vertex_shader.txt");

        //    Convert input stream to string
        Scanner s = new Scanner(inputStream).useDelimiter("\\A");
        String shaderCode = s.hasNext() ? s.next() : "";
    }

    ...

}

0
public Static Resources mResources;

 @Override
     public void onCreate()
     {
           mResources = getResources();
     }

Vâng, vấn đề là, getResource () cần một bối cảnh. Vì vậy, điều này có lẽ không thực sự là một sự giải quyết cho "không có đối tượng hoạt động" (trong đó bạn đã đăng phương thức onCreate ())
Tobias Reich

0

Tôi đang sử dụng API cấp 27 và tìm thấy một giải pháp tốt nhất sau khi vật lộn khoảng hai ngày. Nếu bạn muốn đọc tệp xml từ một lớp không xuất phát từ Hoạt động hoặc Ứng dụng thì hãy làm như sau.

  1. Đặt tệp testdata.xml trong thư mục tài sản.

  2. Viết đoạn mã sau để lấy tài liệu testdata được phân tích cú pháp.

        InputStream inputStream = this.getClass().getResourceAsStream("/assets/testdata.xml");
    
        // create a new DocumentBuilderFactory
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        // use the factory to create a documentbuilder
        DocumentBuilder builder = factory.newDocumentBuilder();
        // create a new document from input stream
        Document doc = builder.parse(inputStream);

-1

Trong lớp của bạn, nơi bạn triển khai hàm tĩnh , bạn có thể gọi một phương thức private \ public từ lớp này. Phương thức private \ public có thể truy cập vào getResource .

ví dụ:

public class Text {

   public static void setColor(EditText et) {
      et.resetColor(); // it works

      // ERROR
      et.setTextColor(getResources().getColor(R.color.Black)); // ERROR
   }

   // set the color to be black when reset
   private void resetColor() {
       setTextColor(getResources().getColor(R.color.Black));
   }
}

và từ lớp \ hoạt động khác, bạn có thể gọi:

Text.setColor('some EditText you initialized');

-1

nếu bạn có một bối cảnh, tôi có nghĩa là bên trong;

public void onReceive(Context context, Intent intent){

}

bạn có thể sử dụng mã này để lấy tài nguyên:

context.getResources().getString(R.string.app_name);

2
Tiêu đề của câu hỏi nói trong một bối cảnh tĩnh. Mà câu trả lời của bạn không bao gồm.
Rune Schjellerup Philosof
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.