2016-08-15 4 views
1

私はAndroidとJavaの初心者です(私は80年代のZ80マシン言語でかなり進歩しました)。バックグラウンドで5分ごとにBluetoothデバイスをスキャンするアプリを作成したいと思います。目的は、私の家庭のさまざまなデバイスの使用状況を監視することです。私は3つのクラスを持っています:MainActivityはUI用のコード、MbtScannerはBluetoothデバイス用のスキャン用のコード、BluetoothTSchedulerにはアラームが発生するとスキャンを呼び出すコードがあります。アラームは、テスト目的で60秒ごとに繰り返すように設定されていますが、コードが機能したら5分ごとに設定します。結果はファイルに書き込まれます。Bluetoothデバイスのスキャンをトリガーするアラームマネージャーを取得できません

MainActivityから呼び出すとうまく動作しますが、alarmManagerの結果としてBluetoothTSchedulerから呼び出されたときはうまく動作しません。

私はstackoverflowとインターネットで答えを探していて運が無かった。問題は文脈に間違ったタイプのMbtScannerアクティビティに渡している文脈にあると思うが、私は本当に問題を理解していないし、解決する方法も知らない。

これは私のMainActivityのコード

public class MainActivity extends AppCompatActivity { 

AlarmManager alarmManager; 
Intent intent; 
public PendingIntent pendingIntent; 

MbtScanner mbtscanner; 
BluetoothTScheduler bluetoothTScheduler; 

public static ArrayAdapter<String> mArrayAdapter; 
ListView listView; 



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

    listView = (ListView) findViewById(R.id.listView); 
    mArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, 0); 
    listView.setAdapter(mArrayAdapter); 

    mbtscanner = new MbtScanner(this); 

    setScheduler(); 
    mbtscanner.mbtScannerInit(); 
    mbtscanner.scanResult(); 
    setBtReceiver(); 
} 


// SCAN FOR BLUETOOTH DEVICES - CALLED BY UI SCAN BUTTON 
public void btScan(View v) { 
    if (!mbtscanner.stillScanning) { 
     mArrayAdapter.clear(); 
    } 
    mbtscanner.mbtScan(); 
} 


// ASK USER TO SWITCH ON BLUETOOTH (CALLED IF BLUETOOTH OFF) 
private void turnOnBT() { 
    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
    startActivityForResult(enableBtIntent, 1); 
} 



// SET BLUETOOTH RECEIVER AND IF FOUND CAPTURE DATA TO FILE AND TO LISTVIEW 
private void setBtReceiver() { 

    //CHECK FOR BLUETOOTH CAPABILITY AND IF IT IS SWITHCED ON 
    if (mbtscanner.mBluetoothAdapter == null) { 
     Toast.makeText(getApplicationContext(), "Bluetooth not supported", Toast.LENGTH_SHORT).show(); 
     finish(); 
    } else { 
     if (!mbtscanner.mBluetoothAdapter.isEnabled()) { 
      turnOnBT(); 
     } 

     if (mbtscanner.mBluetoothAdapter.isDiscovering()) mbtscanner.mBluetoothAdapter.cancelDiscovery(); 
    } 


} 

public static void updateListView(String s){ 
    mArrayAdapter.add(s); 
} 



@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    // IF USER REFUSES TO SWITCH ON BLUETOOTH THEN TERMINATE APPLICATION 
    if (resultCode == RESULT_CANCELED) { 
     Toast.makeText(getApplicationContext(), "Bluetooth must be enabled to Continue", Toast.LENGTH_SHORT).show(); 
     finish(); 
    } 
} 


@Override 
protected void onPause() { 

    Toast.makeText(this, "On Pause", Toast.LENGTH_SHORT).show(); 

    super.onPause(); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 
    // init(); 
    // setBtReceiver(); 
} 


@Override 
protected void onDestroy() { 
    Toast.makeText(this, "On Destroy", Toast.LENGTH_SHORT).show(); 
    if (mbtscanner.mBluetoothAdapter.isDiscovering()) { 
     mbtscanner.mBluetoothAdapter.cancelDiscovery(); 
    } 
    unregisterReceiver(mbtscanner.mReceiver); 

    super.onDestroy(); 
} 


// THIS IS CALLED FROM A UI BUTTON "CANCEL ALARM" 
public void cancelAlarm(View view) { 
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 
    intent = new Intent(this, BluetoothTScheduler.class); 
    pendingIntent = PendingIntent.getBroadcast(
      this.getApplicationContext(), 234324243, intent, 0); 
    alarmManager.cancel(pendingIntent); 
    Toast.makeText(this, "Alarm cancelled", Toast.LENGTH_LONG).show(); 
} 



public void setScheduler() { 

    bluetoothTScheduler = new BluetoothTScheduler(); 

    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); 
    intent = new Intent(this, BluetoothTScheduler.class); 
    pendingIntent = PendingIntent.getBroadcast(
      this.getApplicationContext(), 234324243, intent, 0); 

    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 
      + (30 * 1000), 60 * 1000, pendingIntent); 
    Toast.makeText(this, "Alarm set in 10 seconds for every 60 seconds", Toast.LENGTH_LONG).show(); 

} 
} 

これは私のMbtScannerクラスのコードです:

public class MbtScanner { 


public String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/btTracker"; 
FileWriter fileWriter; 
File file; 

ProgressDialog progress; 

Context mContext; 

BluetoothAdapter mBluetoothAdapter; 
IntentFilter filter; 
BroadcastReceiver mReceiver; 
boolean stillScanning = false; 

String s; 
int count =0; 

public MbtScanner(Context mContext) { 
    this.mContext = mContext; 
} 


public void mbtScan(){ 
    mBluetoothAdapter.startDiscovery(); 
    stillScanning = true; 

    // DIALOG BOX SAYING PLEASE WAIT 
    progress = new ProgressDialog(mContext); 
    progress.setTitle("Scanning"); 
    progress.setMessage("Please wait..."); 
    // progress.setCancelable(false); 
    progress.show(); 

} 

public void mbtScannerInit(){ 
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
    filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); 


    File dir = new File(path); 
    dir.mkdirs(); 
    file = new File(path + "/savedfile.csv"); 
} 


public void scanResult() { 
    mReceiver = new BroadcastReceiver() { 
     @Override 
     public void onReceive(Context context, Intent intent) { 
      String action = intent.getAction(); 
      // When discovery finds a device 


      // IF DEVICE FOUND 
      if (BluetoothDevice.ACTION_FOUND.equals(action)) { 
       // Get the BluetoothDevice object from the Intent 


       // CAPTURE DEVICE DATA TO LISTVIEW 
       BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 

       count++; 

       int rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE); 
       String sName, sAddress, sUuids, sDate, sFile; 
       int iBondState, iMajorClass; 

       sName = device.getName(); 
       sAddress = device.getAddress(); 
       iBondState = device.getBondState(); 
       iMajorClass = device.getBluetoothClass().getMajorDeviceClass(); 
       sUuids = "" + device.getUuids(); 
       sDate = DateFormat.getDateTimeInstance().format(new Date()); 

       s = "Count= " + count + "\n"; 
       s += "Name= " + sName + "\n"; 
       s += "Address= " + sAddress + "\n"; 
       s += "Bond state= " + iBondState + "; "; 
       s += "Major class= " + iMajorClass + "\n"; 
       s += "Uuids= " + sUuids + "; "; 
       s += "RSSI= " + rssi + "dBm" + "\n"; 
       s += "Date= " + sDate + "\n"; 

       MainActivity.updateListView(s); 

       // CREATE STRING OF DEVICE DATA TO SAVE TO FILE 
       sFile = count + "," + sName + "," + sAddress + "," + iBondState + "," + iMajorClass + "," + sUuids + "," + rssi + "," + sDate; 


       // SAVE DEVICE DATA TO FILE 
       try { 
        commitToFile(sFile); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 

      } else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) { 
       Toast.makeText(mContext, "Discovery started", Toast.LENGTH_SHORT).show(); 

       // SCANNING FINISHED SO INFORM USER 
      } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { 
       progress.dismiss(); 
       Toast.makeText(mContext, "Discovery finished. Last device found: " + s, Toast.LENGTH_SHORT).show(); 
       stillScanning = false; 


       // IF SOMEHOW BLUETOOTH HAS BEEN SWITCHED OFF THEN TRY TO SWITCH IT BACK ON 
      } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { 
       if (mBluetoothAdapter.getState() == mBluetoothAdapter.STATE_OFF) { 
        // Toast.makeText(mActivity, "Bluetooth state changed", Toast.LENGTH_SHORT).show(); 

        // turnOnBT(); ALTERNATIVE CODE TO NOTIFY USER THAT APP CAN NO LONGER WORK BCAUSE BLUTOOTH IS OFF, AND CANCEL ALARM 
       } 
      } 
     } 
    }; 


    mContext.registerReceiver(mReceiver, filter); 
    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_STARTED); 
    mContext.registerReceiver(mReceiver, filter); 
    filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); 
    mContext.registerReceiver(mReceiver, filter); 
    filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 
    mContext.registerReceiver(mReceiver, filter); 

} 

// SAVE DATA TO FILE 
private void commitToFile(String str) throws IOException { 
    fileWriter = new FileWriter(file, true); 
    BufferedWriter bufferWriter = new BufferedWriter(fileWriter); 
    PrintWriter printWriter = new PrintWriter(bufferWriter); 

    printWriter.print(str + "\n"); 
    printWriter.close(); 

    Toast.makeText(mContext, "written to file: ", Toast.LENGTH_SHORT).show(); 
} 

} 

これはAlarmmanagerによって呼び出されBluetoothTSchedulerクラスのための私のコードです:

public class BluetoothTScheduler extends BroadcastReceiver { 

public static final String MyPREFERENCES = "MyPrefs" ; 
SharedPreferences sharedpreferences; 
int brCounter; 
MbtScanner sbtscanner; 



@Override 
public void onReceive(Context context, Intent intent) { 
    sharedpreferences = context.getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE); 
    SharedPreferences.Editor editor = sharedpreferences.edit(); 
    brCounter = sharedpreferences.getInt("counter", 0); 

    Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 
    vibrator.vibrate(1000); 
    Toast.makeText(context, "Alarm...." + brCounter, Toast.LENGTH_LONG).show(); 

    brCounter = brCounter +1; 
    editor.putInt("counter", brCounter); 
    editor.commit(); 



    sbtscanner = new MbtScanner(context); 
    sbtscanner.mbtScannerInit(); 
    if (sbtscanner.mBluetoothAdapter.isDiscovering()) sbtscanner.mBluetoothAdapter.cancelDiscovery(); 
    sbtscanner.scanResult(); 

} 

} 

これは私のマニフェストファイルです:

012ここで
<uses-permission android:name="android.permission.BLUETOOTH" /> 
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.WAKE_LOCK" /> 
<uses-permission android:name="android.permission.VIBRATE" /> 

<application 
    android:allowBackup="true" 
    android:icon="@mipmap/ic_launcher" 
    android:label="@string/app_name" 
    android:supportsRtl="true" 
    android:theme="@style/AppTheme" > 
    <activity 
     android:name=".MainActivity" > 
     <intent-filter> 
      <action android:name="android.intent.action.MAIN" /> 
      <category android:name="android.intent.category.LAUNCHER" /> 
     </intent-filter> 
    </activity> 
    <receiver android:name="BluetoothTScheduler" > 
    </receiver> 



</application> 

logcatです:

D/InputMethodManager: windowDismissed mLockisused = false 
D/AndroidRuntime: Shutting down VM 
E/AndroidRuntime: FATAL EXCEPTION: main 
E/AndroidRuntime: Process: com.orinocosolutions.bluetracker2, PID: 29905 
E/AndroidRuntime: java.lang.RuntimeException: Unable to start receiver com.orinocosolutions.bluetracker2.BluetoothTScheduler: android.content.ReceiverCallNotAllowedException: BroadcastReceiver components are not allowed to register to receive intents 
E/AndroidRuntime:  at android.app.ActivityThread.handleReceiver(ActivityThread.java:3508) 
E/AndroidRuntime:  at android.app.ActivityThread.access$1900(ActivityThread.java:218) 
E/AndroidRuntime:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795) 
E/AndroidRuntime:  at android.os.Handler.dispatchMessage(Handler.java:102) 
E/AndroidRuntime:  at android.os.Looper.loop(Looper.java:145) 
E/AndroidRuntime:  at android.app.ActivityThread.main(ActivityThread.java:6917) 
E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Native Method) 
E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Method.java:372) 
E/AndroidRuntime:  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404) 
E/AndroidRuntime:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199) 
E/AndroidRuntime: Caused by: android.content.ReceiverCallNotAllowedException: BroadcastReceiver components are not allowed to register to receive intents 
E/AndroidRuntime:  at android.app.ReceiverRestrictedContext.registerReceiver(ContextImpl.java:275) 
E/AndroidRuntime:  at android.app.ReceiverRestrictedContext.registerReceiver(ContextImpl.java:264) 
E/AndroidRuntime:  at com.orinocosolutions.bluetracker2.MbtScanner.scanResult(MbtScanner.java:166) 
E/AndroidRuntime:  at com.orinocosolutions.bluetracker2.BluetoothTScheduler.onReceive(BluetoothTScheduler.java:42) 
E/AndroidRuntime:  at android.app.ActivityThread.handleReceiver(ActivityThread.java:3501) 
E/AndroidRuntime:  at android.app.ActivityThread.access$1900(ActivityThread.java:218)  
E/AndroidRuntime:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1795)  
E/AndroidRuntime:  at android.os.Handler.dispatchMessage(Handler.java:102)  
E/AndroidRuntime:  at android.os.Looper.loop(Looper.java:145)  
E/AndroidRuntime:  at android.app.ActivityThread.main(ActivityThread.java:6917)  
E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Native Method)  
E/AndroidRuntime:  at java.lang.reflect.Method.invoke(Method.java:372) 

すべてのヘルプは非常に高く評価されます。

答えて

0

それはあなたがエラーを修正するために必要なすべては、この変更で次のようになります。これに

sbtscanner = new MbtScanner(context); 

sbtscanner = new MbtScanner(context.getApplicationContext()); 

をMbtScannerでscanResult()メソッドの内部で、使用しているためですこのコンテキストは実行時にBroadcastReceiverを登録し、onReceive()メソッドに渡されたコンテキストはBluetoothTSchedulerであり、別のBroadcastReceiverの登録には使用できません。 the documentationから

この例外はregisterReceiver(BroadcastReceiver、 IntentFilter)と これらの方法はBroadcastReceiverコンポーネントから使用されてbindService(テント、ServiceConnection、INT)からスローされます。 このケースでは、インテントを受け取った から戻ったときにコンポーネントがアクティブにならないため、非同期APIを使用することはできません。

MbtScannerクラスは、AlarmからトリガーされたBroadcastReceiverから呼び出されたときにアプリケーションコンテキストを使用します。

+0

素晴らしい!それは問題を解決したようだ。この問題を修正すると、私のコードでいくつかのマイナーなバグが発見されましたが、私はそれらを解決できると確信しています。もう一度! – OrinocoBoyo

関連する問題