Phát hiện nút trang chủ nhấn trong Android


94

Điều này đã khiến tôi phát điên trong một thời gian.

Có cách nào để phát hiện một cách đáng tin cậy nếu nút trang chủ đã được nhấn trong ứng dụng Android không?

Không đạt được điều đó, có cách nào hiệu quả để cho biết điều gì đã khiến một hoạt động chuyển sang trạng thái Tạm dừng không? tức là Chúng tôi có thể phát hiện xem nó có phải là do một hoạt động mới khởi chạy hay do nhấn back / home.

Một gợi ý mà tôi đã thấy là ghi đè onPause () và gọi isFinishing () nhưng điều này sẽ trả về false khi nhấn nút home giống như khi một hoạt động mới đang bắt đầu, vì vậy điều này không thể phân biệt giữa hai.

Bất kỳ giúp đỡ nhiều đánh giá cao.

** Cập nhật **: Cảm ơn @ android-đói về liên kết này: https://nishandroid.blogspot.com/

Đánh giá cao phương pháp sau:

@Override
public void onAttachedToWindow() {
    super.onAttachedToWindow();
    this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);           
}

Sau đó, sự kiện sau SẼ được kích hoạt cho các lần nhấn nút trang chủ:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {     

    if(keyCode == KeyEvent.KEYCODE_HOME)
    {
       //The Code Want to Perform. 
    }
});

Tôi không chắc liệu có bất kỳ tác dụng phụ nào với dòng này hay không:

this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);   

Vì vậy, có vẻ như trái với suy nghĩ thông thường, trên thực tế, bạn có thể nghe thấy phím home. Đáng lo ngại là bạn có thể trả về false và không cần dùng phím home.

Cập nhật : Đúng như dự kiến, có một số ảnh hưởng từ phía này - có vẻ như video được nhúng và bản đồ google không hiển thị khi bật chế độ này.

Cập nhật : Được cho là bản hack này không còn hoạt động kể từ Android 4.0 trở đi


Vấn đề của tôi không phải là ngụy trang giữa phím quay lại và phím nhà nhưng tôi muốn hoàn thành ứng dụng cho cả hai trường hợp. Mà tôi đã sử dụng Activity.onUserLeaveHint().
harism

Vấn đề duy nhất là onUserLeaveHint () cũng sẽ kích hoạt khi tôi bắt đầu một hoạt động từ hoạt động đã nói, tôi chỉ muốn biết nếu quay lại hay trang chủ đã được nhấn. Cảm ơn bạn đã gợi ý mặc dù
Dean hoang dã

Điều đó đúng, nhưng thật không may, theo như tôi biết, đó là nơi duy nhất để nhận bất kỳ thông tin nào về việc sử dụng phím Home. Làm cho vấn đề trở nên khó khăn hơn khi thu thập các giả định sai, trong số rất nhiều có thể được nhận ra một cách dễ dàng, nhưng vẫn làm cho nhiệm vụ nghe có vẻ dễ dàng khá phức tạp.
harism

2
@DeanWild: bạn đã đọc cái này chưa: nisha113a5.blogspot.com
Pratik Bhat

2
Hằng số TYPE_KEYGUARD đã bị xóa khỏi WindowManager.LayoutParams trong Android 5.0
theb1uro

Câu trả lời:


136

Mã sau phù hợp với tôi :)

HomeWatcher mHomeWatcher = new HomeWatcher(this);
mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() {
    @Override
    public void onHomePressed() {
        // do something here...
    }
    @Override
    public void onHomeLongPressed() {
    }
});
mHomeWatcher.startWatch();
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;

public class HomeWatcher {

    static final String TAG = "hg";
    private Context mContext;
    private IntentFilter mFilter;
    private OnHomePressedListener mListener;
    private InnerReceiver mReceiver;

    public HomeWatcher(Context context) {
        mContext = context;
        mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    }

    public void setOnHomePressedListener(OnHomePressedListener listener) {
        mListener = listener;
        mReceiver = new InnerReceiver();
    }

    public void startWatch() {
        if (mReceiver != null) {
            mContext.registerReceiver(mReceiver, mFilter);
        }
    }

    public void stopWatch() {
        if (mReceiver != null) {
            mContext.unregisterReceiver(mReceiver);
        }
    }

    class InnerReceiver extends BroadcastReceiver {
        final String SYSTEM_DIALOG_REASON_KEY = "reason";
        final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
        final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
        final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
                String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);
                if (reason != null) {
                    Log.e(TAG, "action:" + action + ",reason:" + reason);
                    if (mListener != null) {
                        if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
                            mListener.onHomePressed();
                        } else if (reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
                            mListener.onHomeLongPressed();
                        }
                    }
                }
            }
        }
    }
}
public interface OnHomePressedListener {
    void onHomePressed();
    void onHomeLongPressed();
}

3
onHomeLongPressedThực tế của bạn dường như tương ứng với việc mở hoạt động hệ thống "Gần đây". Trên điện thoại của tôi, điều đó được kích hoạt bằng cách nhấn nút gần đây bên cạnh nút trang chủ, vì vậy giả định của mã của bạn về việc đó là một lần nhấn giữ nhà không phải lúc nào cũng chính xác.
Sam

tại sao nó không hoạt động đối với tôi, tôi đã làm giống hệt như vậy ngoại trừ đăng ký chương trình phát sóng thông qua tệp kê khai.
Farhan

Đã đăng ký trong lớp ứng dụng, Đang làm việc cho đến nay .. +1, tôi tự hỏi lợi nhuận là gì? Ý tôi là, chúng ta sẽ bỏ sót trường hợp ban đầu nào ..: ^)
Farhan

1
đôi khi ý định.getStringExtra (SYSTEM_DIALOG_REASON_KEY); trả về null. Tôi muốn biết chuyện gì đang xảy ra ??
Fakher

1
Lý do báo chí dài hiện được gọi làfinal String SYSTEM_DIALOG_REASON_LONG_PRESS = "assist"
JWqvist

49

Đây là một câu hỏi cũ nhưng nó có thể giúp ích cho ai đó.

@Override
protected void onUserLeaveHint()
{
    Log.d("onUserLeaveHint","Home button pressed");
    super.onUserLeaveHint();
}

Theo tài liệu, phương thức onUserLeaveHint () được gọi khi người dùng nhấp vào nút trang chủ HOẶC khi có thứ gì đó làm gián đoạn ứng dụng của bạn (như cuộc gọi đến).

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


26
Không chính xác !!! Điều đó hoạt động khi nhấn nút home nhưng nó cũng hoạt động khi Swiching Activity with Intent !!
Nikunj Paradva

Điều này sẽ thực thi trước onStop () luôn luôn, ngay cả khi hoạt động khác ở trên cùng hoặc người dùng buộc rời khỏi hoạt động hoặc nhấp vào nút trang chủ ...
Navas pk

7

Không thể phát hiện và / hoặc chặn nút HOME từ bên trong ứng dụng Android. Điều này được tích hợp trong hệ thống để ngăn chặn các ứng dụng độc hại không thể thoát ra.


kiểm tra câu trả lời được chấp nhận, nó là có thể. Tuy nhiên, chưa được thử nghiệm trên nhiều thiết bị.
Dean Wild,

Yeah ... ứng dụng của tôi bị lỗi.
Jeremy Logan

những gì về trình khởi chạy / ứng dụng thay thế nhà? Tôi đang xây dựng một và tôi muốn đi đến màn hình đầu tiên khi nhấp chuột người dùng gia đình
lisovaccaro

Đối với Trình khởi chạy, hãy sử dụng điều này: @Override được bảo vệ void onNewIntent (Ý định có ý định) {super.onNewIntent (ý định); / * Làm những gì bạn muốn * /}
Ton

Trình khởi chạy @lisovaccaro và hoặc các thay thế tại nhà vẫn không được google hỗ trợ (src diane hackborn) và do đó bạn không thể ngăn người dùng nhấp vào nút home. Bạn vẫn có thể thêm chế độ xem của mình dưới dạng hộp thoại cảnh báo hệ thống, hộp thoại này sẽ phủ lên mọi thứ. Nhưng các lần nhấp vào nút trang chủ sẽ đi qua nó.
JacksOnF1re

7

Tôi cần bắt đầu / dừng nhạc nền trong ứng dụng của mình khi hoạt động đầu tiên mở và đóng hoặc khi bất kỳ hoạt động nào bị tạm dừng bằng nút trang chủ và sau đó tiếp tục lại từ trình quản lý tác vụ. Việc phát lại thuần túy dừng / tiếp tục Activity.onPause()Activity.onResume()làm gián đoạn nhạc một lúc, vì vậy tôi phải viết mã sau:

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

  // start playback here (if not playing already)
}

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

  ActivityManager manager = (ActivityManager) this.getSystemService(Activity.ACTIVITY_SERVICE);
  List<ActivityManager.RunningTaskInfo> tasks = manager.getRunningTasks(Integer.MAX_VALUE);
  boolean is_finishing = this.isFinishing();
  boolean is_last = false;
  boolean is_topmost = false;
  for (ActivityManager.RunningTaskInfo task : tasks) {
    if (task.topActivity.getPackageName().startsWith("cz.matelier.skolasmyku")) {
      is_last = task.numRunning == 1;
      is_topmost = task.topActivity.equals(this.getComponentName());
      break;
    }
  }

  if ((is_finishing && is_last) || (!is_finishing && is_topmost && !mIsStarting)) {
    mIsStarting = false;
    // stop playback here
  }
}

Điều này chỉ làm gián đoạn quá trình phát lại khi ứng dụng (tất cả các hoạt động của ứng dụng) bị đóng hoặc khi nút trang chủ được nhấn. Rất tiếc, tôi đã không quản lý để thay đổi thứ tự các lệnh gọi của onPause()phương thức của hoạt động bắt đầu và onResume()của hoạt động bắt đầu khi Activity.startActivity()được gọi (hoặc phát hiện trong onPause()hoạt động đó đang khởi chạy hoạt động khác theo cách khác) vì vậy trường hợp này phải được xử lý đặc biệt:

private boolean mIsStarting;

@Override
public void startActivity(Intent intent) {
  mIsStarting = true;
  super.startActivity(intent);
}

Một nhược điểm khác là điều này yêu cầu GET_TASKSquyền được thêm vào AndroidManifest.xml:

<uses-permission
  android:name="android.permission.GET_TASKS"/>

Việc sửa đổi mã này mà nó chỉ phản ứng khi nhấn nút trang chủ là đơn giản.


4

Ghi đè onUserLeaveHint()trong hoạt động. Sẽ không bao giờ có bất kỳ lệnh gọi lại nào đối với hoạt động khi một hoạt động mới đi qua nó hoặc người dùng nhấn lại.


4
nó còn được gọi là cũng có khi đi từ một hoạt động khác trong phạm vi ứng dụng
Amir Uval

3

onUserLeaveHint ();

ghi đè phương thức lớp hoạt động này. Thao tác này sẽ phát hiện ra lần bấm phím home. Phương thức này được gọi ngay trước lệnh gọi lại onPause () của hoạt động, nhưng nó sẽ không được gọi khi một hoạt động bị gián đoạn giống như hoạt động trong cuộc gọi xuất hiện ở nền trước, ngoài những gián đoạn đó, nó sẽ gọi khi người dùng nhấp vào phím home.

@Override
protected void onUserLeaveHint() {
    super.onUserLeaveHint();
    Log.d(TAG, "home key clicked");
}

2

Cố gắng tạo bộ đếm cho mỗi màn hình. Nếu người dùng chạm vào TRANG CHỦ, thì bộ đếm sẽ bằng không.

public void onStart() {
  super.onStart();
  counter++;
}

public void onStop() {
  super.onStop();
  counter--;    
  if (counter == 0) {
      // Do..
  }
}

3
Nếu bạn có nghĩa là bộ đếm ứng dụng toàn cầu, nó sẽ bằng 0 trong một thời điểm khi một hoạt động được chuyển sang ngăn xếp phía sau và một hoạt động khác đang được chuyển lên trên cùng hoặc khi hoạt động cao nhất kết thúc và hoạt động ngăn xếp trở lại đang được chuyển lên trên cùng, đây là nơi thông thường khi bạn muốn phản ứng khi nhấn nút trang chủ. Nếu bạn có nghĩa là bộ đếm toàn bộ hoạt động, nó sẽ bằng 0 bất kỳ lúc nào hoạt động không hiển thị (không nhất thiết là do nhấn nút trang chủ). Giải pháp duy nhất là trì hoãn phản ứng của bạn bằng cách sử dụng bộ đếm thời gian để bỏ qua quá trình chuyển đổi này nhưng độ trễ cần thiết có thể không dự đoán được hoặc không mong muốn.
Blackhex


1

Tôi đã gặp sự cố này và vì ghi đè phương thức onKeyDown () không thực hiện được gì vì hệ thống android cơ bản không gọi phương thức này, tôi đã giải quyết vấn đề này bằng cách ghi đè onBackPressed () và tôi đã đặt giá trị boolean ở đó thành false , bởi vì tôi đã nhấn lại, hãy để tôi cho bạn biết ý tôi trong mã:

import android.util.Log;
public class HomeButtonActivity extends Activity {
    boolean homePressed = false;
    // override onCreate() here.

    @Override
    public void onBackPressed() {
        homePressed = false; // simply set homePressed to false
    }

    @Overide
    public void onResume() {
        super.onResume();
        homePressed = true; // default: other wise onBackPressed will set it to false
    }

    @Override
    public void onPause() {
        super.onPause();
        if(homePressed) { Log.i("homePressed", "yay"); }
    }

Vì vậy, lý do tại sao điều này hoạt động là vì cách duy nhất để điều hướng bên ngoài hoạt động này là bằng cách nhấn back hoặc home, vì vậy nếu nhấn back thì tôi biết nguyên nhân không phải ở nhà, nhưng nếu không thì nguyên nhân là ở nhà, do đó tôi đặt boolean mặc định giá trị cho nhà Được nhấn là đúng. Tuy nhiên, điều này sẽ chỉ hoạt động với một trường hợp hoạt động duy nhất trong ứng dụng của bạn vì nếu không, bạn có nhiều khả năng khiến phương thức onPause () được gọi.


trên thực tế khi bạn đi đến các hoạt động khác, các phương pháp được gọi là onpause
Fakher

Đó là lý do tại sao tôi đã tuyên bố rõ ràng rằng điều này sẽ chỉ hoạt động nếu ứng dụng của bạn chỉ kết hợp một hoạt động duy nhất!
Moshe Rabaev

Và điều gì sẽ xảy ra nếu nhiều hoạt động không liên quan đang chạy cùng một lúc và người dùng chỉ đơn giản là chuyển đổi giữa chúng? Các thiết bị Android hiện đại hỗ trợ đa tác vụ. Với mã này, có vẻ như việc chuyển trở lại ứng dụng của bạn sẽ được đặt homePressedthành true và sau đó chuyển sang ứng dụng khác sẽ nghĩ rằng Màn hình chính đã được nhấn trong khi thực sự không phải vậy.
Remy Lebeau

1

Kể từ API 14, bạn có thể sử dụng hàm onTrimMemory()và kiểm tra cờ TRIM_MEMORY_UI_HIDDEN. Điều này sẽ cho bạn biết rằng Ứng dụng của bạn đang ở chế độ nền.

Vì vậy, trong lớp Ứng dụng tùy chỉnh của bạn, bạn có thể viết một cái gì đó như:

override fun onTrimMemory(level: Int) {
    if (level == TRIM_MEMORY_UI_HIDDEN) {
        // Application going to background, do something
    }
}

Để nghiên cứu sâu hơn về vấn đề này, tôi mời bạn đọc bài viết này: http://www.developerphil.com/no-you-can-not-override-the-home-button-but-you-dont-have -đến/


1
Bài viết hay - giải pháp thay thế hữu ích có thể làm được những gì hầu hết mọi người cần
Dean Wild

Giải pháp tốt. Bạn có biết cách đặt lại cờ khi ứng dụng quay trở lại nền không? Ví dụ: nếu tôi tạo một isInBackground boolean, tôi muốn đặt lại nó về sau khi chúng tôi quay trở lại từ nền.
MikeOscarEcho


0

Vì bạn chỉ muốn hoạt động gốc được hiển thị lại khi ứng dụng được khởi chạy, có thể bạn có thể nhận được hành vi này bằng cách thay đổi chế độ khởi chạy, v.v. trong tệp kê khai?

Ví dụ: bạn đã thử áp dụng thuộc tính android: clearTaskOnLaunch = "true" cho hoạt động khởi chạy của mình chưa, có lẽ song song với android: launcMode = "singleInstance" ?

Tasks và Back Stack là một tài nguyên tuyệt vời để điều chỉnh loại hành vi này.


Đây có vẻ là giải pháp thanh lịch nhất nhưng tôi thấy nó không đáng tin cậy lắm. Sau một vài gần / chu kỳ mở / tạm dừng các ứng dụng sẽ bắt đầu chỉ tiếp tục chứ không phải khởi động lại hoàn toàn
Dean hoang dã

0

Thay đổi hoạt động của phím home là một ý tưởng tồi. Đây là lý do tại sao Google không cho phép bạn ghi đè phím home. Nói chung, tôi sẽ không gặp rắc rối với phím home. Bạn cần cung cấp cho người dùng một cách để thoát khỏi ứng dụng của bạn nếu ứng dụng đó trở thành cỏ dại vì bất kỳ lý do gì.

Tôi hình dung rằng bất kỳ công việc nào xung quanh sẽ có tác dụng phụ không mong muốn.


1
Bạn hoàn toàn đúng nhưng một số khách hàng sẽ không chấp nhận câu trả lời và không hiểu tại sao họ không nên vi phạm các nguyên tắc.
Dean Wild,

Vấn đề là ngay cả khi bạn không muốn theo dõi hành vi của nút trang chủ, đôi khi bạn phải phản ứng khác nhau về tình huống ứng dụng được chuyển đến quay lại do nhấn nút trang chủ khác với tình huống hoạt động hiện tại của bạn bị tạm dừng vì máy quét. lý do. Vấn đề tương tự là với thực tế là Application.onDestroy () không thể được sử dụng cho các bản dựng poduction. Các ví dụ như vậy là tạm dừng trò chơi khi người dùng ẩn sự thích thú, dừng nhạc nền, v.v.
Blackhex

0

Gần đây, tôi đang cố gắng phát hiện nút nhấn màn hình chính vì tôi cần nó hoạt động giống như phương pháp " onBackPressed () ". Để thực hiện việc này, tôi phải ghi đè phương thức " onSupportNavigateUp () " như sau:

override fun onSupportNavigateUp(): Boolean {
    onBackPressed()
    return true
}

Nó hoạt động hoàn hảo. =)


0

Câu trả lời của Jack là hoàn toàn phù hợp cho clicksự kiện trong khi longClickđang xem xét là khi menubấm nút.

Nhân tiện, nếu có ai đang tự hỏi làm thế nào để thực hiện qua kotlin,

class HomeButtonReceiver(private var context: Context,private var listener: OnHomeButtonClickListener) {
    private val mFilter: IntentFilter = IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
    private var mReceiver: InnerReceiver = InnerReceiver()

    fun startWatch() {
        context.registerReceiver(mReceiver, mFilter)
    }

    fun stopWatch() {
        context.unregisterReceiver(mReceiver)
    }

    inner class InnerReceiver: BroadcastReceiver() {
        private val systemDialogReasonKey = "reason"
        private val systemDialogReasonHomeKey = "homekey"
        override fun onReceive(context: Context?, intent: Intent?) {
            val action = intent?.action
            if (action == Intent.ACTION_CLOSE_SYSTEM_DIALOGS) {
                val reason = intent.getStringExtra(systemDialogReasonKey)
                if (reason != null && reason == systemDialogReasonHomeKey) {
                    listener.onHomeButtonClick()
                }
            }
        }
    } 
}

0

nhập mô tả hình ảnh ở đây Phím Home của Android được xử lý bởi lớp khung, bạn không thể xử lý điều này ở cấp lớp ứng dụng. Bởi vì hành động của nút trang chủ đã được xác định ở cấp độ bên dưới. Nhưng nếu bạn đang phát triển ROM tùy chỉnh của mình, thì có thể. Google đã hạn chế các chức năng ghi đè NÚT TRANG CHỦ vì lý do bảo mật.


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.