Cách phát hiện người dùng không hoạt động trong Android


101

Người dùng khởi động ứng dụng của tôi và đăng nhập.
Chọn Thời gian chờ của phiên là 5 phút.
Thực hiện một số thao tác trên ứng dụng. (tất cả ở phía trước)
Bây giờ Người dùng đưa Myapp xuống nền và khởi động một số ứng dụng khác.
----> Đồng hồ đếm ngược bắt đầu và đăng xuất người dùng sau 5 phút
HOẶC người dùng TẮT màn hình.
----> Đồng hồ đếm ngược bắt đầu và đăng xuất người dùng sau 5 phút

Tôi muốn hành vi tương tự ngay cả khi ứng dụng ở nền trước nhưng người dùng không tương tác với ứng dụng trong một thời gian dài, chẳng hạn 6-7 phút. Giả sử màn hình luôn BẬT. Tôi muốn phát hiện loại người dùng không hoạt động (Không tương tác với ứng dụng mặc dù ứng dụng ở nền trước) và bắt đầu đồng hồ đếm ngược của tôi.


1
Bạn có thể luôn để bộ đếm thời gian đó chạy và đặt lại nó bất cứ khi nào người dùng làm điều gì đó không?
Kyle P

Câu trả lời:


111

Tôi đã đưa ra một giải pháp mà tôi thấy khá đơn giản dựa trên câu trả lời của Fredrik Wallenius. Đây là một lớp hoạt động cơ sở cần được mở rộng bởi tất cả các hoạt động.

public class MyBaseActivity extends Activity {

    public static final long DISCONNECT_TIMEOUT = 300000; // 5 min = 5 * 60 * 1000 ms


    private static Handler disconnectHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            // todo
            return true;
        }
    });

    private static Runnable disconnectCallback = new Runnable() {
        @Override
        public void run() {
            // Perform any required operation on disconnect
        }
    };

    public void resetDisconnectTimer(){
        disconnectHandler.removeCallbacks(disconnectCallback);
        disconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
    }

    public void stopDisconnectTimer(){
        disconnectHandler.removeCallbacks(disconnectCallback);
    }

    @Override
    public void onUserInteraction(){
        resetDisconnectTimer();
    }

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

    @Override
    public void onStop() {
        super.onStop();
        stopDisconnectTimer();
    }
}

3
Điều này sẽ tạo ra nhiều bản sao của HandlerRunnablecho mỗi bản Activityđược tạo. Nếu chúng tôi chuyển đổi hai thành viên này thành static, điều này sẽ được tránh. Ngoài ra, bạn có thể cho tôi biết tại sao bạn lại gọi stopDisconnectTimer()đến onStop()không? '
Gaurav Bhor,

@Gaurav Trong trường hợp của tôi, điều này chỉ được triển khai trong một hoạt động (do đó, tôi không hiểu vấn đề với công cụ staticsửa đổi). Đối với onStop(), từ những gì tôi nhớ, tôi gọi onBackPressed()để quay lại màn hình đăng nhập trong lệnh gọi lại ngắt kết nối mà lần lượt gọi onStop()phương thức. Khi người dùng quay lại màn hình đăng nhập theo cách thủ công, bằng cách nhấn trở lại, bộ hẹn giờ cần được dừng lại cũng như khi stopDisconnectTimer()vào onStop(). Tôi đoán phần này tùy thuộc vào nhu cầu của bạn và cách thực hiện.
gfrigon

@gfrigon có thể chuyển hướng người dùng đến hoạt động đăng nhập không?
Apostrofix vào

@Apostrifix, Tất nhiên là có thể. Trong trường hợp của tôi, chỉ có một hoạt động: gọi onBackPressed()đủ mạch. Nếu bạn có nhiều hoạt động trong ngăn xếp của mình, bạn chỉ cần tạo ý định cho vấn đề đó. Bạn có thể muốn nhìn vào câu trả lời sau đây để xóa các nhiệm vụ hoạt động (và ngăn chặn người dùng từ tái kết nối trên một mặt sau): stackoverflow.com/questions/7075349/...
gfrigon

Công việc tuyệt vời! Tôi đã thêm getter và setter cho runnable và sau đó đặt nó trong lớp mở rộng nếu cần bằng cách sử dụng phương thức onCreate ... hoàn hảo, một lần nữa, cảm ơn bạn.
CrandellWS

90

Tôi không biết cách theo dõi hoạt động không hoạt động nhưng có một cách để theo dõi hoạt động của người dùng. Bạn có thể nhận được một cuộc gọi lại được gọi onUserInteraction()trong các hoạt động của mình, được gọi mỗi khi người dùng thực hiện bất kỳ tương tác nào với ứng dụng. Tôi khuyên bạn nên làm điều gì đó như thế này:

@Override
public void onUserInteraction(){
    MyTimerClass.getInstance().resetTimer();
}

Nếu ứng dụng của bạn chứa nhiều hoạt động, tại sao không đặt phương thức này trong một siêu lớp trừu tượng (mở rộng Activity) và sau đó để tất cả các hoạt động của bạn mở rộng nó.


1
Vâng, đây là một cách thực hiện ... nhưng ứng dụng của tôi có 30 hoạt động khác nhau và sẽ có quá nhiều tương tác khi người dùng đang hoạt động ... vì vậy mỗi lần đặt lại bộ hẹn giờ sẽ là một hoạt động tốn kém ... mà tại trường hợp xấu nhất có thể từ 50 đến 60 lần trong một phút.
Akh

3
Tôi chưa hẹn giờ nhưng tôi muốn nói là đặt lại bộ hẹn giờ như thế này lastInteraction = System.currentTimeMillis (); sẽ mất 2 mili giây. Làm điều đó 60 lần một phút và bạn "thả lỏng" 120ms. Trong số 60000.
Fredrik Wallenius

1
Fredrik ... Tôi cũng đang sử dụng đề xuất của bạn để đáp ứng trường hợp này .. Thời gian chờ màn hình được đặt thành tối đa 30 phút trên thiết bị. MyApp shd timeout sau 15 phút ... Nếu người dùng không chạm vào bất kỳ thứ gì trên màn hình từ hơn 1 phút thì tôi sẽ bắt đầu hẹn giờ Đăng xuất 15 phút .... Trong trường hợp này, tôi sẽ kiểm tra sự khác biệt (lastInteractionTime và System.currentTimeMills ( )) là hơn 1 phút ... sau đó cháy ..
Akh

3
Tuy nhiên, onUserInteraction () không được gọi trong một số trường hợp (hộp thoại không gọi nó và cuộn trong spinners) có cách nào giải quyết được những tình huống này không?
AndroidNoob

bạn có thể chia sẻ MyTimerClass của bạn không?
Sibelius Seraphini

19

Tôi nghĩ bạn nên sử dụng mã này, đây là thời gian chờ phiên nhàn rỗi 5 phút: ->

Handler handler;
Runnable r;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    handler = new Handler();
    r = new Runnable() {

       @Override
       public void run() {
            // TODO Auto-generated method stub
            Toast.makeText(MainActivity.this, "user is inactive from last 5 minutes",Toast.LENGTH_SHORT).show();
        }
    };
    startHandler();
}
@Override
public void onUserInteraction() {
     // TODO Auto-generated method stub
     super.onUserInteraction();
     stopHandler();//stop first and then start
     startHandler();
}
public void stopHandler() {
    handler.removeCallbacks(r);
}
public void startHandler() {
    handler.postDelayed(r, 5*60*1000); //for 5 minutes 
}

Bạn đã cứu mạng tôi với onUserInteraction
codezombie

10
public class MyApplication extends Application {
      private int lastInteractionTime;
      private Boolean isScreenOff = false; 
      public void onCreate() {
        super.onCreate();
        // ......   
        startUserInactivityDetectThread(); // start the thread to detect inactivity
        new ScreenReceiver();  // creating receive SCREEN_OFF and SCREEN_ON broadcast msgs from the device.
      }

      public void startUserInactivityDetectThread() {
        new Thread(new Runnable() {
          @Override
          public void run() {
            while(true) {
              Thread.sleep(15000); // checks every 15sec for inactivity
              if(isScreenOff || getLastInteractionTime()> 120000 ||  !isInForeGrnd)
                {
                  //...... means USER has been INACTIVE over a period of
                  // and you do your stuff like log the user out 
                }
              }
          }
        }).start();
      }

      public long getLastInteractionTime() {
        return lastInteractionTime;
      }

      public void setLastInteractionTime(int lastInteractionTime) {
        this.lastInteractionTime = lastInteractionTime;
      }

      private class ScreenReceiver extends BroadcastReceiver {

        protected ScreenReceiver() {
           // register receiver that handles screen on and screen off logic
           IntentFilter filter = new IntentFilter();
           filter.addAction(Intent.ACTION_SCREEN_ON);
           filter.addAction(Intent.ACTION_SCREEN_OFF);
           registerReceiver(this, filter);
        }

        @Override
        public void onReceive(Context context, Intent intent) {
          if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            isScreenOff = true;
          } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            isScreenOff = false;
          }
        }
      }
    }

isInForeGrnd ===> logic không được hiển thị ở đây vì nó nằm ngoài phạm vi của câu hỏi

Bạn có thể mở khóa cho cpu bằng cách sử dụng mã thiết bị bên dưới-

  if(isScreenOff || getLastInteractionTime()> 120000 ||  !isInForeGrnd)
    {
      //...... means USER has been INACTIVE over a period of
      // and you do your stuff like log the user out 

      PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);

      boolean isScreenOn = pm.isScreenOn();
      Log.e("screen on.................................", "" + isScreenOn);

      if (isScreenOn == false) {

        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "MyLock");

        wl.acquire(10000);
        PowerManager.WakeLock wl_cpu = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyCpuLock");

        wl_cpu.acquire(10000);
      }
    }

4
@Nappy: Vậy vui lòng giải thích cách làm đúng. Nhận xét của bạn là mơ hồ và thiếu quyết đoán.
Akh

2
@AKh: Các câu trả lời khác đã cho thấy các khả năng. Trong giải pháp của bạn, tôi không thể thấy bất kỳ lợi ích nào từ việc bỏ phiếu sau mỗi 15 giây. Nó sẽ có tác dụng tương tự, khi bạn bắt đầu hẹn giờ trên "ACTION_SCREEN_OFF" với thời lượng ngẫu nhiên từ 0-15 giây. Điều này chỉ không có ý nghĩa ..
Nappy

1
@Nappy: Cứ sau 15 giây, tôi không chỉ kiểm tra SCREEN_ON hoặc SCREEN_OFF mà còn cả thời gian tương tác cuối cùng của người dùng và trạng thái nền trước của ứng dụng. Dựa trên ba yếu tố này, tôi đưa ra quyết định hợp lý về mức độ tích cực của người dùng tương tác với ứng dụng.
Akh

Hãy hoàn thành bình luận của bạn. .... "nếu boolean isScreenof của bạn là?" Và trạng thái foregrnd của ứng dụng cũng phải được tính đến.
Akh

1
Mã này chứa đầy lỗi, một số biến không được khởi tạo.
Big.Child

8
@Override
public void onUserInteraction() {
    super.onUserInteraction();
    delayedIdle(IDLE_DELAY_MINUTES);
}

Handler _idleHandler = new Handler();
Runnable _idleRunnable = new Runnable() {
    @Override
    public void run() {
        //handle your IDLE state
    }
};

private void delayedIdle(int delayMinutes) {
    _idleHandler.removeCallbacks(_idleRunnable);
    _idleHandler.postDelayed(_idleRunnable, (delayMinutes * 1000 * 60));
}

Đây là cơ sở của giải pháp, phần còn lại có thể được sửa đổi tùy thuộc vào nhu cầu từng phần và độ phức tạp của kiến ​​trúc ứng dụng của bạn! Cảm ơn vì câu trả lời!
Hack06

Làm thế nào để áp dụng điều này trong lớp ứng dụng
Gaju Kollur

6

Không có khái niệm "người dùng không hoạt động" ở cấp hệ điều hành, ngoài ACTION_SCREEN_OFFACTION_USER_PRESENTchương trình phát sóng. Bạn sẽ phải xác định "không hoạt động" bằng cách nào đó trong ứng dụng của riêng bạn.


6

Thậm chí bạn có thể quản lý yêu cầu của bạn với @gfrigon hoặc @AKh giải pháp.

Nhưng đây là giải pháp miễn phí Timer and Handlers cho việc này. Tôi đã có giải pháp Timer được quản lý tốt cho việc này. Nhưng tôi đã triển khai thành công giải pháp miễn phí Timer và Handler.

Đầu tiên, tôi cho bạn biết bạn phải quản lý những gì nếu bạn sử dụng Bộ hẹn giờ hoặc Bộ xử lý.

  • Nếu ứng dụng của bạn bị giết bởi người dùng hoặc bởi trình tối ưu hóa, ứng dụng của bạn sẽ không bao giờ tự động đăng xuất, vì tất cả các lệnh gọi lại của bạn đều bị hủy. ( Quản lý một số Trình quản lý báo động hoặc Dịch vụ? )
  • Có tốt không để có bộ đếm thời gian trong mỗi lớp cơ sở? Bạn đang tạo nhiều luồng chỉ để gọi quy trình đăng xuất ( Quản lý Trình xử lý tĩnh hoặc Bộ hẹn giờ ở cấp ứng dụng? ).
  • Điều gì xảy ra nếu người dùng đang ở chế độ nền, Trình xử lý của bạn sẽ bắt đầu Hoạt động đăng nhập nếu người dùng đang thực hiện một số công việc khác bên ngoài ứng dụng của bạn. ( Quản lý nền trước hay nền ứng dụng? ).
  • Điều gì sẽ xảy ra nếu màn hình tự động tắt. ( Quản lý tắt màn hình trên bộ thu phát sóng? )

Cuối cùng, tôi đã triển khai một giải pháp là

  1. KHÔNG có Bộ xử lý hoặc Bộ hẹn giờ.
  2. Trình quản lý báo thức KHÔNG.
  3. KHÔNG quản lý Vòng đời ứng dụng.
  4. KHÔNG ACTION_SCREEN_ON/ Bộ ACTION_SCREEN_OFFthu phát sóng.

Giải pháp đáng tin cậy dễ dàng nhất

Chúng tôi sẽ không quan sát sự không hoạt động của người dùng theo bộ hẹn giờ thay vì chúng tôi sẽ kiểm tra thời gian hoạt động cuối cùng về hoạt động của người dùng. Vì vậy, khi người dùng tương tác với ứng dụng lần sau, tôi sẽ kiểm tra thời gian tương tác cuối cùng.

Đây là BaseActivity.classcái mà bạn sẽ mở rộng từ mọi lớp hoạt động của mình thay vì LoginActivity. Bạn sẽ xác định thời gian đăng xuất của mình trong trường TIMEOUT_IN_MILLItrong lớp này.

import android.content.Intent;
import android.content.SharedPreferences;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

public class BaseActivity extends AppCompatActivity {
    public static final long TIMEOUT_IN_MILLI = 1000 * 20;
    public static final String PREF_FILE = "App_Pref";
    public static final String KEY_SP_LAST_INTERACTION_TIME = "KEY_SP_LAST_INTERACTION_TIME";

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        if (isValidLogin())
            getSharedPreference().edit().putLong(KEY_SP_LAST_INTERACTION_TIME, System.currentTimeMillis()).apply();
        else logout();
    }

    public SharedPreferences getSharedPreference() {
        return getSharedPreferences(PREF_FILE, MODE_PRIVATE);
    }

    public boolean isValidLogin() {
        long last_edit_time = getSharedPreference().getLong(KEY_SP_LAST_INTERACTION_TIME, 0);
        return last_edit_time == 0 || System.currentTimeMillis() - last_edit_time < TIMEOUT_IN_MILLI;
    }

    public void logout() {
        Intent intent = new Intent(this, LoginActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
        finish();
        Toast.makeText(this, "User logout due to inactivity", Toast.LENGTH_SHORT).show();
        getSharedPreference().edit().remove(KEY_SP_LAST_INTERACTION_TIME).apply(); // make shared preference null.
    }
}

Cách truy cập các tùy chọn được chia sẻ trên chuỗi chính trên mọi tương tác của người dùng tốt hơn so với việc gọi nhiều chuỗi.
Nishita

@Nishita tại thời điểm đăng câu trả lời này, tôi không biết về sự thất vọng này. Cảm ơn bạn đã bình luận về 1 câu trả lời tồi tệ của tôi. Bạn nói đúng, đây không phải là cách làm đúng. Tôi sẽ giấu câu trả lời này.
Khemraj

2

Trong lớp cơ sở hoạt động của mình, tôi đã tạo lớp được bảo vệ:

protected class IdleTimer
{
    private Boolean isTimerRunning;
    private IIdleCallback idleCallback;
    private int maxIdleTime;
    private Timer timer;

    public IdleTimer(int maxInactivityTime, IIdleCallback callback)
    {
        maxIdleTime = maxInactivityTime;
        idleCallback = callback;
    }

    /*
     * creates new timer with idleTimer params and schedules a task
     */
    public void startIdleTimer()
    {
        timer = new Timer();            
        timer.schedule(new TimerTask() {

            @Override
            public void run() {             
                idleCallback.inactivityDetected();
            }
        }, maxIdleTime);
        isTimerRunning = true;
    }

    /*
     * schedules new idle timer, call this to reset timer
     */
    public void restartIdleTimer()
    {
        stopIdleTimer();
        startIdleTimer();
    }

    /*
     * stops idle timer, canceling all scheduled tasks in it
     */
    public void stopIdleTimer()
    {
        timer.cancel();
        isTimerRunning = false;
    }

    /*
     * check current state of timer
     * @return boolean isTimerRunning
     */
    public boolean checkIsTimerRunning()
    {
        return isTimerRunning;
    }
}

protected interface IIdleCallback
{
    public void inactivityDetected();
}

Vì vậy, trong phương thức onResume - bạn có thể chỉ định hành động trong lệnh gọi lại của mình, bạn muốn làm gì với nó ...

idleTimer = new IdleTimer(60000, new IIdleCallback() {
            @Override
            public void inactivityDetected() {
                ...your move...
            }
        });
        idleTimer.startIdleTimer();

Làm thế nào để kiểm tra người dùng không hoạt động ?? bất kỳ đầu vào từ hệ thống?
MohsinSyd

2

Trong quá trình Tìm kiếm của mình, tôi đã tìm thấy rất nhiều câu trả lời nhưng đây là câu trả lời tốt nhất mà tôi nhận được. Nhưng hạn chế của mã này là nó chỉ hoạt động cho hoạt động không cho toàn bộ ứng dụng. Hãy xem đây là một tài liệu tham khảo.

myHandler = new Handler();
myRunnable = new Runnable() {
    @Override
    public void run() {
        //task to do if user is inactive

    }
};
@Override
public void onUserInteraction() {
    super.onUserInteraction();
    myHandler.removeCallbacks(myRunnable);
    myHandler.postDelayed(myRunnable, /*time in milliseconds for user inactivity*/);
}

Ví dụ: bạn đã sử dụng 8000, tác vụ sẽ được thực hiện sau 8 giây người dùng không hoạt động.


2

Người dùng không hoạt động có thể phát hiện bằng cách sử dụng onUserInteraction()phương pháp ghi đè trong android

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

    }

Đây là mã mẫu, đăng nhập (HomeActivity -> LoginActivity) sau 3 phút khi người dùng không hoạt động

public class HomeActivity extends AppCompatActivity {

    private static String TAG = "HomeActivity";
    private Handler handler;
    private Runnable r;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);


        handler = new Handler();
        r = new Runnable() {

            @Override
            public void run() {

                Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
                startActivity(intent);
                Log.d(TAG, "Logged out after 3 minutes on inactivity.");
                finish();

                Toast.makeText(HomeActivity.this, "Logged out after 3 minutes on inactivity.", Toast.LENGTH_SHORT).show();
            }
        };

        startHandler();

    }

    public void stopHandler() {
        handler.removeCallbacks(r);
        Log.d("HandlerRun", "stopHandlerMain");
    }

    public void startHandler() {
        handler.postDelayed(r, 3 * 60 * 1000);
        Log.d("HandlerRun", "startHandlerMain");
    }

    @Override
    public void onUserInteraction() {
        super.onUserInteraction();
        stopHandler();
        startHandler();
    }

    @Override
    protected void onPause() {

        stopHandler();
        Log.d("onPause", "onPauseActivity change");
        super.onPause();

    }

    @Override
    protected void onResume() {
        super.onResume();
        startHandler();

        Log.d("onResume", "onResume_restartActivity");

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        stopHandler();
        Log.d("onDestroy", "onDestroyActivity change");

    }

}

2

Xử lý người dùng trong thời gian chờ tương tác trong KOTLIN:

     //Declare handler
      private var timeoutHandler: Handler? = null
      private var interactionTimeoutRunnable: Runnable? = null

 override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_aspect_ratio)

       //Initialise handler
      timeoutHandler =  Handler();
      interactionTimeoutRunnable =  Runnable {
         // Handle Timeout stuffs here
          }

      //start countdown
      startHandler()
}

// reset handler on user interaction
override fun onUserInteraction() {
      super.onUserInteraction()
      resetHandler()
}

 //restart countdown
fun resetHandler() {
      timeoutHandler?.removeCallbacks(interactionTimeoutRunnable);
      timeoutHandler?.postDelayed(interactionTimeoutRunnable, 10*1000); //for 10 second

}

 // start countdown
fun startHandler() {
    timeoutHandler?.postDelayed(interactionTimeoutRunnable, 10*1000); //for 10 second
}

1

Đây là một giải pháp hoàn chỉnh Xử lý người dùng không hoạt động sau vài phút (ví dụ: 3 phút). Điều này giải quyết các vấn đề phổ biến như Hoạt động nhảy vào nền trước khi Ứng dụng ở chế độ nền sau khi hết thời gian.

Đầu tiên, chúng tôi tạo một BaseActivity mà tất cả các Hoạt động khác có thể mở rộng.

Đây là mã BaseActivity.

package com.example.timeout;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.Window;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;


import javax.annotation.Nullable;

public class BaseActivity extends AppCompatActivity implements LogoutListener {

    private Boolean isUserTimedOut = false;
    private static Dialog mDialog;



    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        ((TimeOutApp) getApplication()).registerSessionListener(this);
        ((TimeOutApp) getApplication()).startUserSession();

    }

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


    }

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

        if (isUserTimedOut) {
            //show TimerOut dialog
            showTimedOutWindow("Time Out!", this);

        } else {

            ((TimeOutApp) getApplication()).onUserInteracted();

        }

    }

    @Override
    public void onSessionLogout() {


        isUserTimedOut = true;

    }


    public void showTimedOutWindow(String message, Context context) {


        if (mDialog != null) {
            mDialog.dismiss();
        }
        mDialog = new Dialog(context);


        mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        mDialog.setContentView(R.layout.dialog_window);

        mDialog.setCancelable(false);
        mDialog.setCanceledOnTouchOutside(false);

        TextView mOkButton = (TextView) mDialog.findViewById(R.id.text_ok);
        TextView text_msg = (TextView) mDialog.findViewById(R.id.text_msg);

        if (message != null && (!TextUtils.isEmpty(message)) && (!message.equalsIgnoreCase("null"))) {
            text_msg.setText(message);

        }


        mOkButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                if (mDialog != null){

                    mDialog.dismiss();

                    Intent intent = new Intent(BaseActivity.this, LoginActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    startActivity(intent);

                    finish();
                }


            }
        });

        if(!((Activity) context).isFinishing())
        {
            //show dialog
            mDialog.show();
        }

    }

}

Tiếp theo, chúng tôi tạo giao diện cho "Trình nghe đăng xuất"

package com.example.timeout;

public interface LogoutListener {

    void onSessionLogout();

}

Cuối cùng, chúng tôi tạo một lớp Java mở rộng "Ứng dụng"

package com.example.timeout;

import android.app.Application;

import java.util.Timer;
import java.util.TimerTask;

public class TimeOutApp extends Application {

    private LogoutListener listener;
    private Timer timer;
    private static final long INACTIVE_TIMEOUT = 180000; // 3 min


    public void startUserSession () {
        cancelTimer ();

        timer = new Timer ();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                listener.onSessionLogout ();

            }
        }, INACTIVE_TIMEOUT);

    }

    private void cancelTimer () {
        if (timer !=null) timer.cancel();
    }

    public void registerSessionListener(LogoutListener listener){
        this.listener = listener;
    }

    public void onUserInteracted () {
        startUserSession();
    }


}

Lưu ý: Đừng quên thêm lớp "TimeOutApp" vào thẻ ứng dụng bên trong tệp kê khai của bạn

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

0

Tôi nghĩ cần phải kết hợp bộ đếm thời gian với thời gian hoạt động cuối cùng.

Vì vậy, như thế này:

  1. Trong onCreate (Bundle đã lưuInstanceState) bắt đầu hẹn giờ, giả sử 5 phút

  2. Trong onUserInteraction () chỉ lưu trữ thời gian hiện tại

Khá đơn giản cho đến nay.

Bây giờ khi cửa sổ hẹn giờ bật lên như thế này:

  1. Lấy thời gian hiện tại và trừ đi thời gian tương tác đã lưu trữ để lấy thời gian
  2. Nếu timeDelta> = 5 phút, bạn đã hoàn thành
  3. Nếu timeDelta <5 phút, hãy bắt đầu lại bộ đếm thời gian, nhưng lần này sử dụng 5 phút - thời gian đã lưu trữ. Nói cách khác, 5 phút tạo thành tương tác cuối cùng

0

Tôi đã gặp tình huống tương tự với câu hỏi SO, trong đó tôi cần theo dõi người dùng không hoạt động trong 1 phút sau đó chuyển hướng người dùng bắt đầu Hoạt động, tôi cũng cần xóa ngăn xếp hoạt động.

Dựa trên câu trả lời @gfrigon, tôi đưa ra giải pháp này.

ActionBar.java

public abstract class ActionBar extends AppCompatActivity {

    public static final long DISCONNECT_TIMEOUT = 60000; // 1 min

    private final MyHandler mDisconnectHandler = new MyHandler(this);

    private Context mContext;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mContext = this;
    }



    /*
    |--------------------------------------------------------------------------
    | Detect user inactivity in Android
    |--------------------------------------------------------------------------
    */

    // Static inner class doesn't hold an implicit reference to the outer class

    private static class MyHandler extends Handler {

        // Using a weak reference means you won't prevent garbage collection

        private final WeakReference<ActionBar> myClassWeakReference;

        public MyHandler(ActionBar actionBarInstance) {

            myClassWeakReference = new WeakReference<ActionBar>(actionBarInstance);
        }

        @Override
        public void handleMessage(Message msg) {

            ActionBar actionBar = myClassWeakReference.get();

            if (actionBar != null) {
                // ...do work here...
            }
        }
    }


    private Runnable disconnectCallback = new Runnable() {

        @Override
        public void run() {

            // Perform any required operation on disconnect

            Intent startActivity = new Intent(mContext, StartActivity.class);

            // Clear activity stack

            startActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

            startActivity(startActivity);
        }
    };

    public void resetDisconnectTimer() {

        mDisconnectHandler.removeCallbacks(disconnectCallback);
        mDisconnectHandler.postDelayed(disconnectCallback, DISCONNECT_TIMEOUT);
    }

    public void stopDisconnectTimer() {

        mDisconnectHandler.removeCallbacks(disconnectCallback);
    }

    @Override
    public void onUserInteraction(){

        resetDisconnectTimer();
    }

    @Override
    public void onResume() {

        super.onResume();
        resetDisconnectTimer();
    }

    @Override
    public void onStop() {

        super.onStop();
        stopDisconnectTimer();
    }
}

Tài nguyên bổ sung

Android: Xóa ngăn xếp hoạt động

Lớp Xử lý này phải là lớp tĩnh hoặc có thể xảy ra rò rỉ


0

Điều tốt nhất là xử lý vấn đề này trên toàn bộ ứng dụng của bạn (giả sử bạn có nhiều hoạt động) bằng cách đăng ký AppLifecycleCallbackstrong Ứng dụng calss. Bạn có thể sử dụng registerActivityLifecycleCallbacks()trong lớp Ứng dụng với các lệnh gọi lại sau (Tôi khuyên bạn nên tạo một lớp AppLifecycleCallbacks để mở rộng ActivityLifecycleCallbacks):

public interface ActivityLifecycleCallbacks {
    void onActivityCreated(Activity activity, Bundle savedInstanceState);
    void onActivityStarted(Activity activity);
    void onActivityResumed(Activity activity);
    void onActivityPaused(Activity activity);
    void onActivityStopped(Activity activity);
    void onActivitySaveInstanceState(Activity activity, Bundle outState);
    void onActivityDestroyed(Activity activity);
}

0
open class SubActivity : AppCompatActivity() {
    var myRunnable:Runnable
    private var myHandler = Handler()

    init {
        myRunnable = Runnable{
            toast("time out")
            var intent = Intent(this, MainActivity::class.java)
            startActivity(intent)

        }
    }

    fun toast(text: String) {
        runOnUiThread {
            val toast = Toast.makeText(applicationContext, text, Toast.LENGTH_SHORT)
            toast.show()
        }
    }

   override fun onUserInteraction() {
        super.onUserInteraction();
        myHandler.removeCallbacks(myRunnable)
        myHandler.postDelayed(myRunnable, 3000)
    }

    override fun onPause() {
        super.onPause()
        myHandler.removeCallbacks(myRunnable)
    }

    override fun onResume() {
            super.onResume()
            myHandler.postDelayed(myRunnable, 3000)
    }
}

Mở rộng hoạt động của bạn với

YourActivity:SubActivity(){}

để truy cập MainActivity khi Người dùng không hoạt động sau 3000 mili giây trên YourActivity

Tôi đã sử dụng một câu trả lời trước đó và chuyển đổi nó thành kotlin.

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.