5

Tôi gặp sự cố và sau một số tìm kiếm, tôi không tìm thấy bất kỳ giải pháp tích cực nào. Sau khi nghiên cứu, tôi có ý tưởng rằng không có triển khai cho vấn đề của tôi nhưng câu hỏi này có thể là cơ hội cuối cùng của tôi.Android, nhận tín hiệu mạnh (PhoneStateListener) trong khi thiết bị ở chế độ ngủ

Tôi cần phải làm gì?

Có ứng dụng nhận thông tin về tín hiệu cường độ mạng di động. Tôi làm điều đó bởi PhoneStateListener. Tất nhiên nó hoạt động tốt nhưng khi điện thoại của tôi đi vào giấc ngủ chế độ, người nghe không hoạt động:

https://code.google.com/p/android/issues/detail?id=10931 https://code.google.com/p/android/issues/detail?id=7592

WakeLock giải quyết vấn đề chỉ trong trường hợp, nếu thiết bị tắt bởi thời gian chờ. Trong trường hợp khi tôi nhấn nút nguồn cứng, thiết bị của tôi cũng có chế độ ngủ. Chúng tôi không thể ghi đè tác vụ nút nguồn.

Mục tiêu của tôi luôn nhận được tín hiệu mạnh khi thiết bị của tôi được bật. Nó không quan trọng là chế độ nào. Tất cả thời gian cần thu thập dữ liệu.

Câu hỏi:

Có bất kỳ ý tưởng? Làm thế nào để đạt được điều đó? Có cách nào để làm điều này hoặc có thể có một số hack? Tất cả các giải quyết đều được chào đón. Nếu bạn có một số kinh nghiệm hữu ích, hãy chia sẻ điều này.

Nhờ tất cả để được trợ giúp !!! Tôi hy vọng, chủ đề này sẽ nhận được thông tin đầy đủ về vấn đề này.

+1

"Trong trường hợp tôi nhấn nút nguồn cứng, thiết bị của tôi cũng có chế độ ngủ. Chúng tôi không thể ghi đè tác vụ nút nguồn". - một 'WakeLock' không bị ảnh hưởng bởi nút nguồn. – CommonsWare

+0

Tại sao không sử dụng dịch vụ? –

+0

nó cũng không hoạt động ở chế độ ngủ. –

Trả lời

9

quản lý báo thức là con đường để đi - phần khó khăn là để giữ cho điện thoại tỉnh táo sau khi trở về tiếp nhận quản lý báo động. Vì vậy,

  • thiết lập một báo động (chú ý bạn cũng nên đăng ký một máy thu "On Boot hoàn" để thiết lập báo động sau khi khởi động lại - báo động của bạn không tồn tại khi khởi động lại):

    Intent monitoringIntent = new Intent(context, YourReceiver.class); 
    monitoringIntent.setAction("your action"); 
    PendingIntent pi = PendingIntent.getBroadcast(context, NOT_USED, 
             monitoringIntent, PendingIntent.FLAG_UPDATE_CURRENT); 
    AlarmManager am = (AlarmManager) 
            context.getSystemService(Context.ALARM_SERVICE); 
    // here is the alarm set up 
    am.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, 
           SystemClock.elapsedRealtime() + INITIAL_DELAY, 
           INTERVAL_BETWEEN_ALARMS, pi); 
    
  • nhận được nó - người nhận giữ một WakeLock trong nó onReceive() mà không bao giờ thất bại:

    public abstract class YourReceiver extends BroadcastReceiver { 
    
        @Override 
        final public void onReceive(Context context, Intent intent) { 
         final String action = intent.getAction(); 
         if ("your action".equals(action)) { 
          // monitoring - got broadcast from ALARM 
          try { 
            d("SS : " + new Signal().getSignalStrength(context)); 
          } catch (InterruptedException e) { 
            e.printStackTrace(); 
          } 
          // Actu8ally the lines above will ANR 
          // I did it with WakefulIntentService : 
          // WakefulIntentService.sendWakefulWork(
          // context, YourWakefulService.class); 
          // Will be posting it asap 
         } else { 
          w("Received bogus intent : " + intent); 
          return; 
         } 
        } 
    } 
    

    Nếu bạn là người may mắn (yourRetrieveSignal() là đủ nhanh) này sẽ làm việc, oth bạn sẽ cần một mẫu IntentService (Wakeful) trong bộ thu của bạn.
    WakefulIntentService sẽ xử lý khóa thức (nếu bạn muốn tránh sự phụ thuộc có giao diện here) - CHỈNH SỬA: hãy nhớ rằng bạn không thể xác định người nghe trong một dịch vụ có mục đích - xem here.

Nếu người nhận ANR trên bạn, bạn phải thử mẫu WakefulIntentService.Trong cả hai trường hợp, bạn có thể sử dụng this:

này chứng tỏ phần khó khăn nhất thực sự:

class Signal { 

    static volatile CountDownLatch latch; //volatile is an overkill quite probably 
    static int asu; 
    private final static String TAG = Signal.class.getName(); 

    int getSignalStrength(Context ctx) throws InterruptedException { 
     Intent i = new Intent(TAG + ".SIGNAL_ACTION", Uri.EMPTY, ctx, 
       SignalListenerService.class); 
     latch = new CountDownLatch(1); 
     asu = -1; 
     ctx.startService(i); 
     Log.d(TAG, "I wait"); 
     latch.await(); 
     ctx.stopService(i); 
     return asu; 
    } 
} 

nơi:

public class SignalListenerService extends Service { 

    private TelephonyManager Tel; 
    private SignalListener listener; 
    private final static String TAG = SignalListenerService.class.getName(); 

    private static class SignalListener extends PhoneStateListener { 

     private volatile CountDownLatch latch; 

     private SignalListener(CountDownLatch la) { 
      Log.w(this.getClass().getName(), "CSTOR"); 
      this.latch = la; 
     } 

     @Override 
     public void onSignalStrengthChanged(int asu) { 
      Signal.asu = asu; 
      latch.countDown(); 
     } 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.w(TAG, "Received : " + intent.getAction()); 
     Tel = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 
     listener = new SignalListener(Signal.latch); 
     @SuppressWarnings("deprecation") 
     final int listenSs = PhoneStateListener.LISTEN_SIGNAL_STRENGTH; 
     Tel.listen(listener, listenSs); 
     return START_STICKY; 
    } 

    @Override 
    public void onDestroy() { 
     Log.w(TAG, "onDestroy"); 
     Tel.listen(listener, PhoneStateListener.LISTEN_NONE); 
     super.onDestroy(); 
    } 

    @Override 
    public IBinder onBind(Intent intent) { 
     return null; 
    } 
} 

Đây là mã làm việc (nhưng không phải là đỉnh cao của sự sang trọng thừa nhận - bình luận/chỉnh sửa chào mừng). Đừng quên đăng ký dịch vụ của bạn trong tệp kê khai và nhận quyền.
EDIT 2013.07.23: Tôi không sử dụng onReceive - nếu bạn sử dụng nó, nó sẽ ANR - đây là mã làm việc nếu bạn sử dụng WakefulIntentService trong onReceive và trong đó bạn gọi SignalListenerService.

+1

Nếu bạn chỉ hỗ trợ Android 2.1 trở lên, bạn sẽ cần sử dụng 'PhoneStateListener.LISTEN_SIGNAL_STRENGTHS' thay vì' PhoneStateListener.LISTEN_SIGNAL_STRENGTH'. – ChuongPham

1

Từ hiểu biết của tôi về PhoneStateListener, bạn không thể thực hiện việc này trong khi CPU ứng dụng đang ở chế độ ngủ. Bạn có thể giữ thiết bị luôn tỉnh táo, điều này sẽ làm hỏng tuổi thọ pin. Hoặc bạn có thể sử dụng báo thức (xem AlarmManager) để đánh thức thiết bị theo các khoảng thời gian, do đó bạn có thể thu thập dữ liệu (ảnh hưởng đến tuổi thọ pin).

Some samples of using AlarmManager can be found here

+0

Làm cách nào để giữ thiết bị luôn tỉnh táo? Sau khi nhấn nút nguồn phần cứng, thiết bị của tôi sẽ vẫn ở chế độ ngủ. Hoặc có thể tôi có thể đạt được điều đó bằng cách nào đó? Vấn đề chính là trường hợp với nút nguồn. –

+0

Sau đó, có vẻ như bạn muốn sử dụng AlarmManager. :) AlarmManger sẽ cho phép bạn đánh thức CPU và thực hiện một đoạn mã mỗi X phút/giây. – AndersNS

+0

Bạn vẫn sẽ ảnh hưởng đến nước pin nếu bạn sử dụng AlarmManager. Tôi đoán nếu bạn đã thực hiện điều này trong ứng dụng của bạn, bạn sẽ cần phải giải thích cho người dùng rằng pin của họ có thể tiêu hao một chút. – ChuongPham

1

Commons Ví dụ về thăm dò vị trí của Ware thực sự tốt về việc đánh thức điện thoại và đưa nó vào giấc ngủ một lần nữa. Tôi nghĩ rằng nó có thể giúp bạn có một cái nhìn: https://github.com/commonsguy/cwac-locpoll

0

Một trong những cách giải quyết có thể có của vấn đề Android 10931 là gửi ý định android.intent.action.SCREEN_ON đến quá trình 'điện thoại' sau khi màn hình tắt.

  1. Tạo và đăng ký BroadcastReceiver để lắng nghe thông báo khi màn hình tắt

    start(Context context) { 
        IntentFilter filter = new IntentFilter(); 
        filter.addAction(Intent.ACTION_SCREEN_OFF); 
        context.registerReceiver(mScreenReceiver, filter); 
    } 
    
    final BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { 
        @Override 
        public void onReceive(final Context context, final Intent intent) { 
         if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) { 
          Log.v(LOGTAG, "Screen is off. Running workaround"); 
          new Thread(mReportScreenIsOnRunnable).start(); 
         } 
        } 
    }; 
    
  2. Gửi SCREEN_ON mục đích duy nhất quá trình điện thoại.

    public final Runnable mReportScreenIsOnRunnable = new Runnable() { 
        @Override 
        public void run() { 
         try { 
          Thread.sleep(100); 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 
         try { 
          Runtime.getRuntime().exec(new String[] { "su", "-c", 
            "am broadcast -a android.intent.action.SCREEN_ON com.android.phone" }); 
         } catch (IOException e) { 
          e.printStackTrace(); 
         } 
        } 
    }; 
    

Sau khi nhận được ý định này quá trình điện thoại sẽ tiếp tục gửi vị trí tế bào cập nhật.

Đặc quyền gốc là bắt buộc.

Giải pháp này hơi khó hiểu, nguy hiểm và không hoạt động trên tất cả các điện thoại. Nó có thể dẫn đến tiêu thụ điện năng cao hơn, nhưng không nhiều hơn nếu bạn giữ màn hình bật.

Các vấn đề liên quan