Bất cứ khi nào chương trình phát của tôi được thực hiện, tôi muốn hiển thị cảnh báo cho hoạt động tiền cảnh.
Bất cứ khi nào chương trình phát của tôi được thực hiện, tôi muốn hiển thị cảnh báo cho hoạt động tiền cảnh.
Câu trả lời:
Biết rằng ActivityManager quản lý Activity , vì vậy chúng tôi có thể lấy thông tin từ ActivityManager . Chúng tôi nhận được hoạt động chạy nền trước hiện tại bằng cách
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
CẬP NHẬT 2018/10/03 getRastyT
Nhiệm vụ () bị ĐỔI . xem các giải pháp dưới đây.
Phương pháp này không được chấp nhận ở cấp độ API 21. Kể từ Build.VERSION_CODES.LOLLIPOP, phương pháp này không còn khả dụng cho các ứng dụng của bên thứ ba: việc giới thiệu các khoảng cách trung tâm tài liệu có nghĩa là nó có thể rò rỉ thông tin cá nhân cho người gọi. Để tương thích ngược, nó vẫn sẽ trả về một tập hợp con dữ liệu nhỏ: ít nhất là các tác vụ riêng của người gọi và có thể một số tác vụ khác như nhà được biết là không nhạy cảm.
( Lưu ý: Một API chính thức đã được thêm vào API 14: Xem câu trả lời này https://stackoverflow.com/a/29786451/119733 )
KHÔNG SỬ DỤNG câu trả lời PREVIOUS (waqas716).
Bạn sẽ gặp vấn đề rò rỉ bộ nhớ, vì tham chiếu tĩnh cho hoạt động. Để biết thêm chi tiết, hãy xem liên kết sau http://android-developers.blogspot.fr/2009/01/avoiding-memory-leaks.html
Để tránh điều này, bạn nên quản lý các hoạt động tham khảo. Thêm tên của ứng dụng trong tệp kê khai:
<application
android:name=".MyApp"
....
</application>
Lớp ứng dụng của bạn:
public class MyApp extends Application {
public void onCreate() {
super.onCreate();
}
private Activity mCurrentActivity = null;
public Activity getCurrentActivity(){
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity){
this.mCurrentActivity = mCurrentActivity;
}
}
Tạo một hoạt động mới:
public class MyBaseActivity extends Activity {
protected MyApp mMyApp;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMyApp = (MyApp)this.getApplicationContext();
}
protected void onResume() {
super.onResume();
mMyApp.setCurrentActivity(this);
}
protected void onPause() {
clearReferences();
super.onPause();
}
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = mMyApp.getCurrentActivity();
if (this.equals(currActivity))
mMyApp.setCurrentActivity(null);
}
}
Vì vậy, bây giờ thay vì mở rộng lớp Activity cho các hoạt động của bạn, chỉ cần mở rộng MyBaseActivity. Bây giờ, bạn có thể nhận hoạt động hiện tại của mình từ ứng dụng hoặc bối cảnh Hoạt động như thế:
Activity currentActivity = ((MyApp)context.getApplicationContext()).getCurrentActivity();
WeakReferences
trong Android, GC thu thập chúng nhanh hơn bạn nghĩ.
WeakReference
không được khuyên dùng cho bộ nhớ đệm, đây không phải là bộ nhớ đệm, đó là ý mCurrentActivity
chí chỉ có một tham chiếu đến nó khi nó còn tồn tại nên WeakReference
sẽ không bao giờ được thu thập trong khi ở Activity
trên cùng. Tuy nhiên, những gì @NachoColoma đề xuất là sai vì WeakReference
vẫn có thể tham chiếu một hoạt động không được nối lại (không còn sống / không ở trên cùng) nếu biến không bị xóa!
Application .ActivityLifecycleCallbacks
, điều này sẽ tập trung hơn và bạn sẽ không phải thêm bất kỳ mã quản lý nào trong tất cả các hoạt động của mình. Đồng thời xem developer.android.com/reference/android/app/
Tôi mở rộng trên đầu câu trả lời của @ gezdy.
Trong mọi Hoạt động, thay vì phải "đăng ký" với Application
mã hóa thủ công, chúng tôi có thể sử dụng API sau kể từ cấp 14, để giúp chúng tôi đạt được mục đích tương tự với ít mã hóa thủ công hơn.
public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)
Trong Application.ActivityLifecycleCallbacks
, bạn có thể nhận Activity
được "đính kèm" hoặc "tách rời" này Application
.
Tuy nhiên, kỹ thuật này chỉ khả dụng kể từ API cấp 14.
implements Application.ActivityLifecycleCallbacks
và thêm các phương thức để thực hiện điều đó. Sau đó, trong hàm tạo của lớp đó (hoặc onCreate hoặc init hoặc phương thức khác chạy khi cá thể đang hoạt động / sẵn sàng), đặt getApplication().registerActivityLifecycleCallbacks(this);
làm dòng cuối cùng.
Cập nhật 2 : Có một api chính thức được thêm vào cho điều này, vui lòng sử dụng ActivityLifecycleCallbacks thay thế.
CẬP NHẬT:
Như được chỉ ra bởi @gezdy, và tôi rất biết ơn về điều đó. cũng đặt tham chiếu thành null cho hoạt động hiện tại, thay vì chỉ cập nhật trên mỗi onResume đặt thành null trên mọi onDestroy của Activity để tránh sự cố rò rỉ bộ nhớ.
Trước đây tôi cần chức năng tương tự và đây là phương pháp tôi đạt được điều này. Trong mọi hoạt động của bạn ghi đè lên các phương pháp vòng đời.
@Override
protected void onResume() {
super.onResume();
appConstantsObj.setCurrentActivity(this);
}
@Override
protected void onPause() {
clearReferences();
super.onPause();
}
@Override
protected void onDestroy() {
clearReferences();
super.onDestroy();
}
private void clearReferences(){
Activity currActivity = appConstantsObj.getCurrentActivity();
if (this.equals(currActivity))
appConstantsObj.setCurrentActivity(null);
}
Bây giờ trong lớp phát sóng của bạn, bạn có thể truy cập hoạt động hiện tại để hiển thị cảnh báo về nó.
Application
chỉ được tạo một lần và không bao giờ rác được thu thập chính xác như một biến tĩnh.
clearReferences()
để (this.equals(currActivity))
.
@lockwobr Cảm ơn đã cập nhật
Điều này không hoạt động 100% thời gian trong phiên bản api 16, nếu bạn đọc mã trên github, chức năng "currentActivityThread" đã thay đổi trong Kitkat, vì vậy tôi muốn nói phiên bản 19ish, loại phiên bản api khó khớp với phiên bản api .
Có quyền truy cập vào hiện tại Activity
là rất tiện dụng. Sẽ không tốt nếu có một getActivity
phương thức tĩnh trả về Hoạt động hiện tại mà không có câu hỏi không cần thiết?
Các Activity
lớp học là rất hữu ích. Nó cho phép truy cập vào luồng UI, khung nhìn, tài nguyên và nhiều thứ khác. Vô số phương thức yêu cầu a Context
, nhưng làm thế nào để có được con trỏ? Đây là một số cách:
ActivityThread
. Lớp này có quyền truy cập vào tất cả các Hoạt động và, thậm chí còn tốt hơn, có một phương thức tĩnh để có được hiện tại ActivityThread
. Chỉ có một vấn đề nhỏ - danh sách Hoạt động có quyền truy cập gói.Dễ dàng giải quyết bằng phản xạ:
public static Activity getActivity() {
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map<Object, Object> activities = (Map<Object, Object>) activitiesField.get(activityThread);
if (activities == null)
return null;
for (Object activityRecord : activities.values()) {
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord)) {
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
Activity activity = (Activity) activityField.get(activityRecord);
return activity;
}
}
return null;
}
Một phương pháp như vậy có thể được sử dụng ở bất cứ đâu trong ứng dụng và nó thuận tiện hơn nhiều so với tất cả các phương pháp được đề cập. Hơn nữa, có vẻ như nó không an toàn như vẻ ngoài của nó. Nó không giới thiệu bất kỳ rò rỉ tiềm năng mới hoặc con trỏ null.
Đoạn mã trên thiếu xử lý ngoại lệ và giả định một cách ngây thơ rằng Hoạt động đầu tiên đang chạy là hoạt động chúng tôi đang tìm kiếm. Bạn có thể muốn thêm một số kiểm tra bổ sung.
Map
giao diện thay thế HashMap
hoặc ArrayMap
. Tôi đã chỉnh sửa câu trả lời @AZ_.
Tôi đã làm như sau trong Kotlin
Chỉnh sửa lớp ứng dụng như sau
class FTApplication: MultiDexApplication() {
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
}
init {
instance = this
}
val mFTActivityLifecycleCallbacks = FTActivityLifecycleCallbacks()
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(mFTActivityLifecycleCallbacks)
}
companion object {
private var instance: FTApplication? = null
fun currentActivity(): Activity? {
return instance!!.mFTActivityLifecycleCallbacks.currentActivity
}
}
}
Tạo lớp ActivityLifecyclCallbacks
class FTActivityLifecycleCallbacks: Application.ActivityLifecycleCallbacks {
var currentActivity: Activity? = null
override fun onActivityPaused(activity: Activity?) {
currentActivity = activity
}
override fun onActivityResumed(activity: Activity?) {
currentActivity = activity
}
override fun onActivityStarted(activity: Activity?) {
currentActivity = activity
}
override fun onActivityDestroyed(activity: Activity?) {
}
override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {
}
override fun onActivityStopped(activity: Activity?) {
}
override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {
currentActivity = activity
}
}
bây giờ bạn có thể sử dụng nó trong bất kỳ lớp nào bằng cách gọi như sau: FTApplication.currentActivity()
getCienActivity () cũng có trong ReactContextBaseJavaModule.
(Vì câu hỏi này ban đầu được hỏi, nhiều ứng dụng Android cũng có thành phần ReactNative - ứng dụng lai.)
lớp ReactContext trong ReactNative có toàn bộ logic để duy trì mCienActivity được trả về trong getCienActivity ().
Lưu ý: Tôi muốn getCienActivity () được triển khai trong lớp Ứng dụng Android.
Tôi không thể tìm ra giải pháp mà nhóm chúng tôi sẽ hài lòng vì vậy chúng tôi tự lăn lộn. Chúng tôi sử dụng ActivityLifecycleCallbacks
để theo dõi hoạt động hiện tại và sau đó phơi bày thông qua một dịch vụ. Thêm chi tiết tại đây: https://stackoverflow.com/a/38650587/10793
Để tương thích ngược:
ComponentName cn;
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
cn = am.getAppTasks().get(0).getTaskInfo().topActivity;
} else {
//noinspection deprecation
cn = am.getRunningTasks(1).get(0).topActivity;
}
WeakReference
tay cầm từ một Application
lớp - trong khi ComponentName
yêu cầu phải xác định xem mong muốn Activity
có nằm trên danh sách tác vụ đang chạy hay không. Và nếu điều này không trả lời đầy đủ câu hỏi, câu trả lời được chấp nhận cũng không.
topActivity
chỉ khả dụng từ Android Q
Cá nhân tôi đã làm như "Cheok Yan Cheng" đã nói, nhưng tôi đã sử dụng "Danh sách" để có "Backstack" cho tất cả các hoạt động của mình.
Nếu bạn muốn kiểm tra Hoạt động hiện tại nào, bạn chỉ cần lấy lớp hoạt động cuối cùng trong danh sách.
Tạo một ứng dụng mở rộng "Ứng dụng" và thực hiện điều này:
public class MyApplication extends Application implements Application.ActivityLifecycleCallbacks,
EndSyncReceiver.IEndSyncCallback {
private List<Class> mActivitiesBackStack;
private EndSyncReceiver mReceiver;
private Merlin mMerlin;
private boolean isMerlinBound;
private boolean isReceiverRegistered;
@Override
public void onCreate() {
super.onCreate();
[....]
RealmHelper.initInstance();
initMyMerlin();
bindMerlin();
initEndSyncReceiver();
mActivitiesBackStack = new ArrayList<>();
}
/* START Override ActivityLifecycleCallbacks Methods */
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
mActivitiesBackStack.add(activity.getClass());
}
@Override
public void onActivityStarted(Activity activity) {
if(!isMerlinBound){
bindMerlin();
}
if(!isReceiverRegistered){
registerEndSyncReceiver();
}
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
if(!AppUtils.isAppOnForeground(this)){
if(isMerlinBound) {
unbindMerlin();
}
if(isReceiverRegistered){
unregisterReceiver(mReceiver);
}
if(RealmHelper.getInstance() != null){
RealmHelper.getInstance().close();
RealmHelper.getInstance().logRealmInstanceCount("AppInBackground");
RealmHelper.setMyInstance(null);
}
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if(mActivitiesBackStack.contains(activity.getClass())){
mActivitiesBackStack.remove(activity.getClass());
}
}
/* END Override ActivityLifecycleCallbacks Methods */
/* START Override IEndSyncCallback Methods */
@Override
public void onEndSync(Intent intent) {
Constants.SyncType syncType = null;
if(intent.hasExtra(Constants.INTENT_DATA_SYNC_TYPE)){
syncType = (Constants.SyncType) intent.getSerializableExtra(Constants.INTENT_DATA_SYNC_TYPE);
}
if(syncType != null){
checkSyncType(syncType);
}
}
/* END IEndSyncCallback Methods */
private void checkSyncType(Constants.SyncType){
[...]
if( mActivitiesBackStack.contains(ActivityClass.class) ){
doOperation() }
}
}
Trong trường hợp của tôi, tôi đã sử dụng "Application.ActivityLifecyclCallbacks" để:
Bind / Unbind Merlin Instance (được sử dụng để nhận sự kiện khi ứng dụng bị mất hoặc nhận kết nối, ví dụ như khi bạn đóng dữ liệu di động hoặc khi bạn mở nó). Nó rất hữu ích sau khi hành động mục đích "OnConnectivityChanged" bị vô hiệu hóa. Để biết thêm thông tin về MERLINE xem: LIÊN KẾT THÔNG TIN MERNET
Đóng Trường hợp thực tế cuối cùng của tôi khi đóng ứng dụng; Tôi sẽ khởi tạo nó trong một cơ sở BaseActivity được mở rộng từ tất cả các hoạt động khác và có Instance RealmHelper riêng. Để biết thêm thông tin về REALM, hãy xem: LINK INFO INFO Ví dụ: Tôi có một ví dụ "RealmHelper" tĩnh bên trong lớp "RealmHelper" của tôi, được khởi tạo trong ứng dụng "onCreate" của tôi. Tôi có một dịch vụ đồng bộ hóa trong đó tôi tạo ra "RealmHelper" mới vì Realm là "Liên kết theo luồng" và Trường hợp Realm không thể hoạt động trong một Chủ đề khác. Vì vậy, để tuân theo Tài liệu về Vương quốc "Bạn cần phải đóng tất cả các thực thể đã mở để tránh rò rỉ tài nguyên hệ thống", để thực hiện điều này, tôi đã sử dụng "Application.ActivityLifecyclCallbacks" như bạn có thể thấy.
Cuối cùng, tôi có một trình nhận được kích hoạt khi tôi hoàn thành để đồng bộ hóa ứng dụng của mình, sau đó khi kết thúc đồng bộ hóa, nó sẽ gọi phương thức "IEndSyncCallback" "onEndSync" trong đó tôi tìm nếu tôi có Lớp hoạt động cụ thể trong Danh sách ActivityBackStack của mình vì tôi cần để cập nhật dữ liệu trên chế độ xem nếu đồng bộ hóa cập nhật chúng và tôi có thể cần thực hiện các thao tác khác sau khi đồng bộ hóa ứng dụng.
Đó là tất cả, hy vọng điều này là hữu ích. Gặp bạn :)
Câu trả lời của waqas716 là tốt. Tôi đã tạo một cách giải quyết cho một trường hợp cụ thể đòi hỏi ít mã và bảo trì hơn.
Tôi đã tìm thấy một công việc cụ thể xung quanh bằng cách có một phương thức tĩnh tìm nạp một khung nhìn từ hoạt động mà tôi nghi ngờ là ở phía trước. Bạn có thể lặp qua tất cả các hoạt động và kiểm tra nếu bạn muốn hoặc lấy tên hoạt động từ câu trả lời của martin không
ActivityManager am = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
Sau đó tôi kiểm tra xem khung nhìn không phải là null và lấy bối cảnh thông qua getContext ().
View v = SuspectedActivity.get_view();
if(v != null)
{
// an example for using this context for something not
// permissible in global application context.
v.getContext().startActivity(new Intent("rubberduck.com.activities.SomeOtherActivity"));
}
getRunningTasks
: "Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, ..."
trong developer.android.com/reference/android/app/,
Tôi không thích bất kỳ câu trả lời nào khác. ActivityManager không có nghĩa là được sử dụng để có được hoạt động hiện tại. Siêu đẳng cấp và tùy thuộc vào onDestroy cũng dễ vỡ và không phải là thiết kế tốt nhất.
Thành thật mà nói, điều tốt nhất tôi nghĩ ra cho đến nay chỉ là duy trì một enum trong Ứng dụng của mình, được đặt khi một hoạt động được tạo.
Một khuyến nghị khác có thể là tránh sử dụng nhiều hoạt động nếu có thể. Điều này có thể được thực hiện bằng cách sử dụng các đoạn hoặc trong chế độ xem tùy chỉnh tùy chọn của tôi.
Một giải pháp khá đơn giản là tạo một lớp trình quản lý đơn, trong đó bạn có thể lưu trữ một tham chiếu đến một hoặc nhiều Hoạt động hoặc bất kỳ thứ gì khác mà bạn muốn truy cập trong toàn bộ ứng dụng.
Gọi UberManager.getInstance().setMainActivity( activity );
trong hoạt động chính của onCreate.
Gọi UberManager.getInstance().getMainActivity();
bất cứ nơi nào trong ứng dụng của bạn để lấy nó. (Tôi đang sử dụng điều này để có thể sử dụng Toast từ một luồng không phải UI.)
Đảm bảo bạn thêm một cuộc gọi đến UberManager.getInstance().cleanup();
khi ứng dụng của bạn đang bị hủy.
import android.app.Activity;
public class UberManager
{
private static UberManager instance = new UberManager();
private Activity mainActivity = null;
private UberManager()
{
}
public static UberManager getInstance()
{
return instance;
}
public void setMainActivity( Activity mainActivity )
{
this.mainActivity = mainActivity;
}
public Activity getMainActivity()
{
return mainActivity;
}
public void cleanup()
{
mainActivity = null;
}
}
Tôi thích trễ 3 năm nhưng dù sao tôi cũng sẽ trả lời trong trường hợp ai đó thấy điều này giống như tôi.
Tôi đã giải quyết điều này bằng cách sử dụng đơn giản:
if (getIntent().toString().contains("MainActivity")) {
// Do stuff if the current activity is MainActivity
}
Lưu ý rằng "getIntent (). ToString ()" bao gồm một loạt các văn bản khác như tên gói của bạn và bất kỳ bộ lọc mục đích nào cho hoạt động của bạn. Về mặt kỹ thuật, chúng tôi đang kiểm tra mục đích hiện tại, không phải hoạt động, nhưng kết quả là như nhau. Chỉ cần sử dụng ví dụ Log.d ("test", getIntent (). ToString ()); nếu bạn muốn xem tất cả các văn bản. Giải pháp này hơi rắc rối nhưng mã của bạn sạch sẽ hơn nhiều và chức năng cũng vậy.