Tại sao mở rộng lớp Ứng dụng Android?


168

Một Applicationlớp mở rộng có thể khai báo các biến toàn cục. Có những lý do khác?


Đây chỉ là một ý tưởng ngoài đỉnh đầu của tôi, nhưng bạn sẽ có thể ghi đè onCreate và hiển thị màn hình khởi động một lần thay vì MainActivity, tức là màn hình giới thiệu lần đầu tiên người dùng mở ứng dụng.
btse

Câu trả lời:


29

Trực tiếp, tôi không thể nghĩ ra một kịch bản thực tế trong đó việc mở rộng Ứng dụng hoặc là thích hợp hơn với cách tiếp cận khác hoặc cần thiết để thực hiện một cái gì đó. Nếu bạn có một đối tượng đắt tiền, được sử dụng thường xuyên, bạn có thể khởi tạo nó trong IntentService khi bạn phát hiện ra rằng đối tượng hiện không có mặt. Bản thân ứng dụng chạy trên luồng UI, trong khi IntentService chạy trên luồng của chính nó.

Tôi thích truyền dữ liệu từ Hoạt động sang Hoạt động với Ý định rõ ràng hoặc sử dụng SharedPreferences. Cũng có nhiều cách để truyền dữ liệu từ Fragment sang Activity gốc của nó bằng các giao diện.


39
Có rất nhiều ứng dụng của việc mở rộng lớp ứng dụng. Một điều rất hữu ích là nắm bắt tất cả các trường hợp ngoại lệ trong ứng dụng của bạn. VÌ đây là một cái gì đó có thể rất tiện dụng
png

3
Làm thế nào để bạn làm điều đó ?
serj 22/03/2015

8
+1 cho "prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences". Chúng ta nên luôn luôn loại bỏ trạng thái toàn cầu nhiều nhất có thể và sử dụng các công cụ Android tiêu chuẩn để quản lý trạng thái toàn cầu thay vì các vars / singletons tĩnh, v.v.
Oleksandr Karaberov

9
tại sao? để chuẩn bị cho Android tại một số điểm chạy chúng trong các quy trình khác nhau hoặc bất kỳ thành phần nào và mọi thành phần đều có thể được sử dụng lại bởi bất kỳ ứng dụng nào, trong khi đó có bị hạn chế không? chỉ truyền các đối tượng dữ liệu thay vì tuần tự hóa chúng sẽ tiết kiệm cpu và bộ nhớ. công cụ phân phối cho chuyển giao bên trong quá trình trên cùng một thiết bị không phải là lý tưởng trong bất kỳ cách nào. Tôi thực sự không thấy quan điểm của việc sử dụng dịch vụ nội bộ như thế (chỉ cần thực hiện các luồng khác với mới). thực sự rất nhiều thứ gây nhầm lẫn cho các lập trình viên đến từ đó khá nhiều tất cả các "người trợ giúp" được thêm vào google được thực hiện như thể các hoạt động chạy trên các máy tính riêng biệt.
Lassi Kinnunen

127

Giới thiệu:

nhập mô tả hình ảnh ở đây

  1. Nếu chúng tôi xem xét một apktệp trong điện thoại di động của mình, nó bao gồm nhiều khối hữu ích như, Activitys, Services và các khối khác.
  2. Các thành phần này không liên lạc với nhau thường xuyên và không quên chúng có vòng đời riêng. điều này cho thấy rằng họ có thể hoạt động cùng một lúc và không hoạt động vào thời điểm khác.

Yêu cầu:

  1. Đôi khi, chúng tôi có thể yêu cầu một kịch bản trong đó chúng tôi cần truy cập vào một biến và trạng thái của nó trên toàn bộ Applicationbất kể Activityngười dùng đang sử dụng,
  2. Một ví dụ là người dùng có thể cần truy cập vào một biến chứa thông tin nhân sự của mình (ví dụ như tên) phải được truy cập trên Application,
  3. Chúng ta có thể sử dụng SQLite nhưng việc tạo Cursorvà đóng nó nhiều lần không hiệu quả,
  4. Chúng ta có thể sử dụng Intents để truyền dữ liệu nhưng vụng về và bản thân hoạt động có thể không tồn tại ở một kịch bản nhất định tùy thuộc vào bộ nhớ khả dụng.

Công dụng của lớp ứng dụng:

  1. Truy cập vào các biến trên Application,
  2. Bạn có thể sử dụng Applicationđể bắt đầu một số thứ nhất định như phân tích, v.v. vì lớp ứng dụng được khởi động trước khi Activitys hoặc Servicess đang được chạy,
  3. Có một phương thức ghi đè được gọi là onConfigurationChanged () được kích hoạt khi cấu hình ứng dụng được thay đổi (ngang sang dọc & ngược lại),
  4. Ngoài ra còn có một sự kiện được gọi là onLowMemory () được kích hoạt khi thiết bị Android thiếu bộ nhớ.

Trong phần Yêu cầu của bạn, tại sao không sử dụng SharedPreferences?

Trong ví dụ đầu tiên như để lưu thông tin cá nhân, SharedPreferences có thể được sử dụng. Nhưng những ví dụ bạn đưa ra trong phần cuối đã xóa tan nghi ngờ của tôi. Cảm ơn!
Saurabh Singh

63

Lớp ứng dụng là đối tượng có vòng đời đầy đủ của ứng dụng của bạn. Đây là lớp cao nhất của bạn như là một ứng dụng. ví dụ sử dụng có thể:

  • Bạn có thể thêm những gì bạn cần khi ứng dụng được khởi động bằng cách ghi đè onCreate trong lớp Ứng dụng.

  • lưu trữ các biến toàn cục nhảy từ Hoạt động này sang Hoạt động khác. Giống như Asynctask.

    Vân vân


4
Sử dụng Ứng dụng làm nơi bán phá giá cho các biến toàn cầu của ứng dụng là một mùi mã lớn. Bạn nên sử dụng các lớp tùy chỉnh, cụ thể hơn của riêng bạn dưới dạng singletons hoặc với các biến tĩnh để thực hiện việc này.
Austin

5
@Austin tại sao lại có mùi?
Relm

1
Vâng, tại sao có mùi? Như đã nói trước đây, lớp Ứng dụng nằm ở đầu phân cấp và tôi có thể đặt cược tiền ăn trưa của mình, rằng một lớp đơn lẻ tùy chỉnh nằm bên dưới nó. Vì vậy, nếu bị xô đẩy và điện thoại của bạn thiếu bộ nhớ, tôi sẽ nói rằng singleton tùy chỉnh là thứ đầu tiên bị giết, thay vì lớp Ứng dụng (về cơ bản là toàn bộ ứng dụng của bạn).
Starwave

31

Đôi khi bạn muốn lưu trữ dữ liệu, như các biến toàn cục cần được truy cập từ nhiều Hoạt động - đôi khi ở mọi nơi trong ứng dụng. Trong trường hợp này, đối tượng Ứng dụng sẽ giúp bạn.

Ví dụ: nếu bạn muốn nhận dữ liệu xác thực cơ bản cho từng yêu cầu http , bạn có thể triển khai các phương thức cho dữ liệu xác thực trong đối tượng ứng dụng.

Sau này, bạn có thể lấy tên người dùng và mật khẩu trong bất kỳ hoạt động nào như thế này:

MyApplication mApplication = (MyApplication)getApplicationContext();
String username = mApplication.getUsername();
String password = mApplication.getPassword();

Và cuối cùng, hãy nhớ sử dụng đối tượng Ứng dụng làm đối tượng đơn lẻ:

 public class MyApplication extends Application {
    private static MyApplication singleton;

    public MyApplication getInstance(){
        return singleton;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        singleton = this;
    }
}

Để biết thêm thông tin, xin vui lòng bấm vào Lớp ứng dụng


2
vui lòng giải thích cho tôi điều này, tại sao chúng ta cần phải tạo đối tượng singleton một cách rõ ràng của một lớp Ứng dụng, theo như tôi biết, chính nó là một singleton. Chúng ta có thể tạo nhiều đối tượng ứng dụng không, nếu có thể thì làm thế nào? và hậu quả là gì? Vui lòng giải thích.
Syed Raza Mehdi

Không, có lẽ chỉ có một lớp ứng dụng. developer.android.com/guide/topics/manifest/
Mạnh

Vậy thì tại sao chúng ta cần duy trì rõ ràng đối tượng singleton của nó? Hệ điều hành không duy trì nó cho chúng ta? Trên thực tế tôi đã gặp một mã trong đó có một đối tượng ứng dụng được tạo trong lớp hoạt động và nó không được đề cập trong bảng kê khai. Tôi nghĩ điều này là sai, tôi cũng tò mò tại sao chúng ta tạo ra đối tượng singleton tĩnh. Những gì bạn nghĩ là cách tiếp cận tốt nhất. Cảm ơn vì đã trả lời.
Syed Raza Mehdi

1
cảm ơn tôi đã tìm thấy câu trả lời của mình ở đây trên link này developer.android.com/reference/android/app/Application.html
Syed Raza Mehdi

Đối tượng * singleton * ở đâu trong đó
Tiến sĩ aNdRO

8

Lớp Ứng dụng là một singleton mà bạn có thể truy cập từ bất kỳ hoạt động nào hoặc bất kỳ nơi nào khác mà bạn có một đối tượng Ngữ cảnh.

Bạn cũng có được một chút vòng đời.

Bạn có thể sử dụng phương thức onCreate của Ứng dụng để khởi tạo các đối tượng đắt tiền nhưng được sử dụng thường xuyên như trình trợ giúp phân tích. Sau đó, bạn có thể truy cập và sử dụng các đối tượng ở khắp mọi nơi.


6
"Bạn cũng có được một chút vòng đời." bạn có thể muốn điều chỉnh lại nó.
wtsang02

2
Tôi có nghĩa là bạn nhận được một số cuộc gọi vòng đời, nhưng không nhiều như với một hoạt động hoặc đoạn. Ví dụ, không có onDestroy () cho lớp Ứng dụng.
Jon F Hancock

Là lớp tự động này được tạo ra?
Konstantin Konopko 19/03/2015

Đúng. Miễn là bạn chỉ định chính xác trong AndroidManifest.xml.
Jon F Hancock

Không, nó không được tạo tự động. Bạn phải tạo nó và sau đó khai báo nó trong tệp kê khai của bạn
Ojonugwa Jude Ochalifu

7

Sử dụng tốt nhất các lớp ứng dụng. Ví dụ: Giả sử bạn cần khởi động lại trình quản lý báo thức khi khởi động xong.

public class BaseJuiceApplication extends Application implements BootListener {

    public static BaseJuiceApplication instance = null;

    public static Context getInstance() {
        if (null == instance) {
            instance = new BaseJuiceApplication();
        }
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();


    }

    @Override
    public void onBootCompleted(Context context, Intent intent) {
        new PushService().scheduleService(getInstance());
        //startToNotify(context);
    }

Tôi tự hỏi tại sao chúng ta cần tạo một tham chiếu tĩnh của đối tượng ứng dụng, trong đó chúng ta có thể lấy nó bằng cách sử dụng getApplication () và gõ nó vào lớp ứng dụng. Theo như tôi hiểu thì khái niệm này là lớp ứng dụng được tạo bởi chính HĐH và nó chỉ nên có một thể hiện được duy trì bởi HĐH. Vui lòng giải thích, cảm ơn.
Syed Raza Mehdi

Bạn hoàn toàn đúng. Gọi getApplication từ bất kỳ thành phần ứng dụng nào trong ứng dụng của bạn sẽ trả về một thể hiện có nguồn gốc Ứng dụng duy nhất là ứng dụng của bạn. Điều này được xử lý nội bộ bởi khung Android. Tất cả những gì bạn cần làm là truyền phiên bản trả về cho lớp tùy chỉnh của bạn mở rộng Ứng dụng. Bạn cũng cần thiết lập bảng kê khai của mình cho phù hợp để lớp thích hợp được sử dụng bởi khung công tác Android để khởi tạo thể hiện.
Matt Welke

5

Không phải là một câu trả lời mà là một quan sát : hãy nhớ rằng dữ liệu trong đối tượng ứng dụng mở rộng không nên được gắn với một thể hiện của một hoạt động, vì có thể bạn có hai phiên bản của cùng một hoạt động chạy cùng một lúc (một trong tiền cảnh và một không nhìn thấy được) .

Ví dụ: bạn bắt đầu hoạt động bình thường thông qua trình khởi chạy, sau đó "thu nhỏ" nó. Sau đó, bạn bắt đầu một ứng dụng khác (ví dụ: Trình tác vụ) khởi động một phiên bản khác của activitiy của bạn, ví dụ để tạo lối tắt, vì ứng dụng của bạn hỗ trợ android.intent.action.CREATE_SHORTCUT. Nếu lối tắt sau đó được tạo và lệnh gọi hoạt động tạo lối tắt này đã sửa đổi dữ liệu của đối tượng ứng dụng, thì hoạt động đang chạy trong nền sẽ bắt đầu sử dụng đối tượng ứng dụng đã sửa đổi này khi nó được đưa trở lại nền trước.


4

Tôi thấy rằng câu hỏi này đang thiếu một câu trả lời. Tôi mở rộng Applicationvì tôi sử dụng triển khai Bill Pugh Singleton ( xem tài liệu tham khảo ) và một số người độc thân của tôi cần bối cảnh. Các Applicationhình lớp như thế này:

public class MyApplication extends Application {

    private static final String TAG = MyApplication.class.getSimpleName();

    private static MyApplication sInstance;

    @Contract(pure = true)
    @Nullable
    public static Context getAppContext() {
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate() called");
        sInstance = this;
    }
}

Và những người độc thân trông như thế này:

public class DataManager {

    private static final String TAG = DataManager.class.getSimpleName();

    @Contract(pure = true)
    public static DataManager getInstance() {
        return InstanceHolder.INSTANCE;
    }

    private DataManager() {
        doStuffRequiringContext(MyApplication.getAppContext());
    }

    private static final class InstanceHolder {
        @SuppressLint("StaticFieldLeak")
        private static final DataManager INSTANCE = new DataManager();
    }
}

Bằng cách này, tôi không cần phải có ngữ cảnh mỗi khi tôi sử dụng một singleton và được khởi tạo đồng bộ hóa lười biếng với số lượng mã tối thiểu.

Mẹo: cập nhật mẫu singleton của Android Studio tiết kiệm rất nhiều thời gian.


3

Tôi nghĩ rằng bạn có thể sử dụng lớp Ứng dụng cho nhiều thứ, nhưng tất cả chúng đều gắn liền với nhu cầu của bạn để thực hiện một số thứ TRƯỚC KHI bất kỳ Hoạt động hoặc Dịch vụ nào của bạn được bắt đầu. Ví dụ, trong ứng dụng của tôi, tôi sử dụng phông chữ tùy chỉnh. Thay vì gọi

Typeface.createFromAsset()

từ mọi Hoạt động để lấy tham chiếu cho phông chữ của tôi từ thư mục Tài sản (điều này rất tệ vì nó sẽ dẫn đến rò rỉ bộ nhớ vì bạn đang giữ tham chiếu đến tài sản mỗi khi bạn gọi phương thức đó), tôi thực hiện điều này từ onCreate()phương thức trong lớp Ứng dụng của mình :

private App appInstance;
Typeface quickSandRegular;
...
public void onCreate() {
    super.onCreate();

    appInstance = this;
    quicksandRegular = Typeface.createFromAsset(getApplicationContext().getAssets(),
                       "fonts/Quicksand-Regular.otf");
   ...
   }

Bây giờ, tôi cũng có một phương thức được định nghĩa như thế này:

public static App getAppInstance() {
    return appInstance;
}

và điều này:

public Typeface getQuickSandRegular() {
    return quicksandRegular;
}

Vì vậy, từ bất cứ nơi nào trong ứng dụng của tôi, tất cả những gì tôi phải làm là:

App.getAppInstance().getQuickSandRegular()

Một cách sử dụng khác cho lớp Ứng dụng đối với tôi là kiểm tra xem thiết bị có được kết nối với Internet TRƯỚC các hoạt động và dịch vụ yêu cầu kết nối thực sự bắt đầu và thực hiện các hành động cần thiết hay không.


1
Nói hay lắm. Rất tốt đẹp phá vỡ.
Oluwatobi Adenekan

3

Nguồn: https://github.com/codepath/android_guides/wiki/Under Hiểu-the-Assroid-Ứng dụng-Kính

Trong nhiều ứng dụng, không cần phải làm việc trực tiếp với lớp ứng dụng. Tuy nhiên, có một vài cách sử dụng được chấp nhận của một lớp ứng dụng tùy chỉnh:

  • Các tác vụ chuyên biệt cần chạy trước khi tạo hoạt động đầu tiên của bạn
  • Khởi tạo toàn cầu cần được chia sẻ trên tất cả các thành phần (báo cáo sự cố, sự tồn tại)
  • Các phương thức tĩnh để dễ dàng truy cập vào dữ liệu bất biến tĩnh như đối tượng máy khách mạng chung

Bạn không bao giờ nên lưu trữ dữ liệu cá thể có thể thay đổi bên trong đối tượng Ứng dụng vì nếu bạn cho rằng dữ liệu của mình sẽ ở đó, ứng dụng của bạn chắc chắn sẽ gặp sự cố tại một số điểm với NullPulumException. Đối tượng ứng dụng không được đảm bảo ở lại trong bộ nhớ mãi mãi, nó sẽ bị giết. Trái với suy nghĩ của nhiều người, ứng dụng sẽ không được khởi động lại từ đầu. Android sẽ tạo một đối tượng Ứng dụng mới và bắt đầu hoạt động mà người dùng trước đó đã ảo tưởng rằng ứng dụng này không bao giờ bị giết ngay từ đầu.


1

Bạn có thể truy cập các biến vào bất kỳ lớp nào mà không cần tạo đối tượng, nếu nó được mở rộng bởi Ứng dụng. Chúng có thể được gọi trên toàn cầu và trạng thái của chúng được duy trì cho đến khi ứng dụng không bị giết.


1

Việc sử dụng ứng dụng mở rộng chỉ làm cho ứng dụng của bạn chắc chắn cho bất kỳ loại hoạt động nào bạn muốn trong suốt thời gian chạy ứng dụng. Bây giờ nó có thể là bất kỳ loại biến nào và giả sử nếu bạn muốn tìm nạp một số dữ liệu từ máy chủ thì bạn có thể đặt asynctask của mình vào ứng dụng để nó sẽ tìm nạp mỗi lần và liên tục, để bạn sẽ tự động nhận được dữ liệu cập nhật .. Sử dụng liên kết này để có thêm kiến ​​thức ....

http://www.intridea.com/blog/2011/5/24/how-to-use-application-object-of-android


nó không phải là một luồng, vì vậy "cho bất kỳ loại hoạt động nào bạn muốn trong suốt thời gian chạy ứng dụng của bạn." là không đúng sự thật.
Lassi Kinnunen

1

Để thêm vào các câu trả lời khác nói rằng bạn có thể muốn lưu trữ các biến trong phạm vi ứng dụng, cho mọi luồng xử lý dài hoặc các đối tượng khác cần liên kết với ứng dụng của bạn khi bạn KHÔNG sử dụng một hoạt động (ứng dụng không phải là một hoạt động) .. chẳng hạn như không thể yêu cầu một dịch vụ bị ràng buộc .. sau đó ràng buộc với thể hiện của ứng dụng được ưu tiên. Cảnh báo rõ ràng duy nhất với phương pháp này là các đối tượng tồn tại miễn là ứng dụng còn sống, do đó cần phải kiểm soát nhiều bộ nhớ hơn nếu không bạn sẽ gặp phải các vấn đề liên quan đến bộ nhớ như rò rỉ.

Một thứ khác mà bạn có thể thấy hữu ích là theo thứ tự các thao tác, ứng dụng sẽ khởi động trước khi có bất kỳ hoạt động nào. Trong khung thời gian này, bạn có thể chuẩn bị bất kỳ công việc vệ sinh cần thiết nào sẽ xảy ra trước hoạt động đầu tiên của bạn nếu bạn muốn.

2018-10-19 11:31:55.246 8643-8643/: application created
2018-10-19 11:31:55.630 8643-8643/: activity created
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.