I have 3 classes in my activity, the first is a BLEmanager which handle the bluetooth connection and return some values through a interface.
The second one is an activity which i call splash, it is the LAUNCHER activity.
Splash extends AppCompactActivities and implements the the BLEmanager interface, so that i can call the third activity when the connection has been established.
All the interface method are inside this class now, but i want them to trigger something in the third class too.
The third class is an activity which is called Main and contain the core of the app and all the functionalities. This class extends the Splash one. Thanks to this fact i thought that i could have override the interface method which are already inside Splash.
I don't know why but when i call an interface method from the BLEmanager only the method inside the Splash class are triggered and not the Main method.
The code is quite confusing so i didn't post it, ask me if you need.
thank you a lot.
EDIT:
Here's the code, comments and variable name are in italian
BLEmanager
public class MDPtechBLE {
private int MY_PERMISSION_LOCATION=1;
private Context context;
private Activity activity; //contesto e activity della applicazione
private CallBacksBLE CB_BLE; //Interfaccia di Callback
private BluetoothGatt GATT;
//Variabili Strettamente legate al Bluetooth
private static BluetoothAdapter myBlueAdapt; //Adapter del BLE, rappresenta il modulo HW del BLE
private Intent enableBtIntent;
private ScanCallback myScanCallBack; //NUOVA CALLBACK
private BluetoothAdapter.LeScanCallback myLeScanCallBack; //VECCHIA CALLBACK
public BluetoothDevice DISPOSITIVOCONNESSO;
//variabi utili
private int TempoScansione=1000;
private boolean MitragliatriceState=false;
//Liste
private List<ScanResult> ListaDeiRisultatiTrovatiDallaScansione; //Nuova Lista di device trovati dalla scansione
private List<BluetoothGattService> ListaServizi;
private List<BluetoothGattCharacteristic> ListaTutteLeCaratteristiche;
private List<BluetoothGattCharacteristic> ListaCaratteristicheSCRITTURA;
private List<BluetoothGattCharacteristic> ListaCaratteristicheLETTURA;
List<PacchettoScrittura> Coda;
//Devo tenere in memoria tutte le Caratteristiche che mi serviranno, PARLARNE CON GIACOMO A PROPOSITO, devono essere pubbliche per essere raggiunte anche dai frammenti
public MDPtechBLE(Context context)
{
ListaServizi = new ArrayList<>();
this.context=context;
activity = (Activity)context;
this.CB_BLE = (CallBacksBLE)context;
initVariabiliScansione();
Log.i("BLE","inizializzato");
Start();
}
Inside this class there are all the method's which handle my BLE connection.
**Callback interface **
public interface CallBacksBLE {
//BLUETOOTH
void BluetoothStato(Boolean stato);
void BleError(int ErrorCode);
//GATT
void StatoConnessioneCambiato(int stato);
void ViaLibera(List<BluetoothGattCharacteristic> ListaCaratteristicheSCRITTURA, List<BluetoothGattCharacteristic> ListaCaratteristicheLETTURA);
void RisultatoLettura(byte[] data, BluetoothGattCharacteristic CharLetta);
void Notifica(byte[] data, BluetoothGattCharacteristic CharNotificata);
}
When, for example, the connection state change i call CB_BLE.StatoConnessioneCambiato('current connection state');
SPLASH
public class Splash extends AppCompatActivity implements CallBacksBLE{
private Intent mainIntent;
public static MDPtechBLE MyBLE;
//Variabili Resume Pause
public static boolean CambioActivityEffettuato;
#Override
public void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
setContentView(R.layout.splashscreen_xlink);
startLockTask();
if(MyBLE==null){
Log.i("Splash","Creazione");
MyBLE = new MDPtechBLE(this);
}
mainIntent = new Intent(Splash.this,MasterActivity.class);
}
#Override
public void onResume() {
super.onResume();
Log.e("DEBUG", "onResume of Splash");
}
#Override
public void onPause() {
super.onPause();
Log.e("DEBUG", "OnPause of Splash");
}
Boolean InRicerca=false;
#Override
public void BluetoothStato(Boolean Stato) {
if(Stato && !InRicerca) {
InRicerca=true;
MyBLE.Cerca_e_Connetti();
}
}
#Override
public void BleError(int ErrorCode) {
}
#Override
public void StatoConnessioneCambiato(int stato) {
int i=0;
i++; //BREAKPOINT
}
#Override
public void ViaLibera(List<BluetoothGattCharacteristic> ListaCaratteristicheSCRITTURA, List<BluetoothGattCharacteristic> ListaCaratteristicheLETTURA) {
CambioActivityEffettuato=true;
Splash.this.startActivity(mainIntent);
Splash.this.finish();
MyBLE.SetMitragliatriceState(true);
}
#Override
public void RisultatoLettura(byte[] data, BluetoothGattCharacteristic CharLetta) {
}
#Override
public void Notifica(byte[] data, BluetoothGattCharacteristic CharNotificata) {
}
#Override
public void onBackPressed() {
// nothing to do here
// … really
}
}
Here in splash, the callbacks are triggered once the interface method are called from the BLEmanager
MainMaster
Here in the main class i handle all the fragments and all the rest of the application, to do everything in the right way i need to know the BLE state, to know the BLE state i need to implement in this class the same callbacks which are in the SPLASH. So i thought about Extending SPLASH.
#Override
public void StatoConnessioneCambiato(int stato) {
int k=0;
k++; //BREAKPOINT
}
This is the callback which tell me the BLE connection state.
If i call it from the BLEmanager only the StatoConnessioneCambiato(bool) inside Splash is triggered and not the one inside MasterActivity.
The reason Main is not receiving callbacks is that it has never been setup. `Override' annotation has nothing to do with it.
You are calling this line to receive callbacks from BLE for SPLASH:
MyBLE = new MDPtechBLE(this);
You need to move this call to Main class and pass it's instance as the argument.
Related
I am trying to implement an architecture similar to the one presented at the Android Developer Summit 2015: https://github.com/yigit/dev-summit-architecture-demo. My application has a simple class that handles the network requests. The class uses Retrofit 2 for the requests. I am also using Dagger 2 for dependency injection.
I am trying to achieve something very simple. My activity tells a controller to fetch data. The controller then makes a call to my REST client to perform a network request. When the request completes successfully I want to broadcast an event to my Activity so that it can update the UI. However, the event is not being broadcast.
I am using the LocalBroadcastManager to broadcast events. My activity registers/unregisters for broadcasts in the onResume/onPause methods. My REST client has an instance of the application context which is provided through dependency injection. The REST client uses the application context to send the broadcast.
My first suspicion was that the broadcasts were not being sent because the network requests are executed on a worker thread whereas the activity is expecting broadcasts on the main thread. However, this type of scenario shouldn't be a problem if the Android documentation is correct.
This is my activity.
public class BaseActivity extends AppCompatActivity {
private ApplicationComponent mApplicationComponent;
private EventBroadcastReceiver mEventBroadcastReceiver = new EventBroadcastReceiver();
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mApplicationComponent = getMovieManagerApplication().getApplicationComponent();
}
#Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("now_playing");
LocalBroadcastManager.getInstance(this).registerReceiver(mEventBroadcastReceiver, intentFilter);
}
#Override
protected void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(this).unregisterReceiver(mEventBroadcastReceiver);
}
protected MovieManagerApplication getMovieManagerApplication() {
return (MovieManagerApplication) getApplication();
}
protected ApplicationComponent getApplicationComponent() {
return mApplicationComponent;
}
protected void update(Intent intent) {
}
private class EventBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
update(intent);
}
}
}
And this is my REST client.
public class MovieRestClient extends BaseRestClient implements Callback<MovieResponse> {
#Inject
public MovieApiService mMovieApiService;
#Inject
public Context mApplicationContext;
public MovieRestClient(ApplicationComponent applicationComponent) {
super(applicationComponent);
getApplicationComponent().inject(this);
}
#Override
public void onResponse(Response<MovieResponse> response) {
if (response.isSuccess()) {
Parcelable parcelable = Parcels.wrap(response.body());
MovieResponse movieResponse = Parcels.unwrap(parcelable);
Intent intent = new Intent("now_playing");
intent.putExtra(MovieResponse.class.getName(), parcelable);
LocalBroadcastManager.getInstance(mApplicationContext).sendBroadcast(intent);
}
}
#Override
public void onFailure(Throwable t) {
}
public void getNowPlaying() {
mMovieApiService.getNowPlaying(API_KEY).enqueue(this);
}
public void getPopular() {
mMovieApiService.getPopular(API_KEY).enqueue(this);
}
public void getTopRated() {
mMovieApiService.getTopRated(API_KEY).enqueue(this);
}
public void getUpcoming() {
mMovieApiService.getUpcoming(API_KEY).enqueue(this);
}
}
Any help would be greatly appreciated.
I am new to Android. I am using Sockets in an asynchronous task and I wish to pass data back to the activity that called it. But I do not want the asynchronous task to handle the UI. I just wish to pass data.
The class that e![enter image description here][1]xtends async task is not a part of the class that extends activity
My activity has 2 buttons. When the button is clicked, async task is called and corresponding changes should be made to rest of the activity.
From How do I send data back from OnPostExecute in an AsyncTask:
class YourActivity extends Activity {
private static final int DIALOG_LOADING = 1;
public void onCreate(Bundle savedState) {
setContentView(R.layout.yourlayout);
new LongRunningTask1().execute(1,2,3);
}
private void onBackgroundTaskDataObtained(List<String> results) {
//do stuff with the results here..
}
private class LongRunningTask extends AsyncTask<Long, Integer, List<String>> {
#Override
protected void onPreExecute() {
//do pre execute stuff
}
#Override
protected List<String> doInBackground(Long... params) {
List<String> myData = new ArrayList<String>();
for (int i = 0; i < params.length; i++) {
try {
Thread.sleep(params[i] * 1000);
myData.add("Some Data" + i);
} catch(InterruptedException ex) { }
}
return myData;
}
#Override
protected void onPostExecute(List<String> result) {
YourActivity.this.onBackgroundTaskDataObtained(result);
}
}
}
Yes you can use handler to communicate between AsyncTask and Activity, see following example, it will help,
#Override
protected void onPostExecute(Object result) {
super.onPostExecute(result);
Message message = new Message();
Bundle bundle = new Bundle();
bundle.putString("file", pdfPath);
message.setData(bundle);
handler.sendMessage(message); // pass handler object from activity
}
put following code into Activity class
Handler handler = new android.os.Handler() {
#Override
public void handleMessage(Message msg) {
String filePath = msg.getData().getString("file"); // You can change this according to your requirement.
}
};
If you dont't aware of Handler class then first read following link, it will help you
https://developer.android.com/training/multiple-threads/communicate-ui.html
There are different way to pass data back to activity. As explained below
Suppose u have one class
public class Socket {
private Activity activity;
//create interface
public interface OnAyscronusCallCompleteListener{
public void onComplete(/*your data as parameter*/);
}
private void setAsyncListener(Activity activity){
this.activity = activity;
}
//rest of your code
// send back data to activity
activity.onComplete(/* your data */)
}
//Now your activity
class YourActivity extends Activity implements Socket.OnAyscronusCallCompleteListener {
// rest of your activity life cycle methods
onCreate(Bundle onSaved)
{Socket socket = new Socket();
socket.setAsyncListener(this);
}
public void onComplete(/*your data*/){
// perform action on data
}
}
In your Activity Class
new YourAsyncTask().execute("String1","String2","12");
Your AsyncTask
AsyncTask<Params, Progress, Result>
private class YourAsyncTask extends AsyncTask<String, Void, Void > {
protected Long doInBackground(String... s) {
String s1 = s[0]; //="String1";
String s2 = s[1]; //="String2";
int s1 = Integer.parseInt(s[2]); //=3;
}
protected void onProgressUpdate(Void... values) {
}
protected void onPostExecute() {
}
}
A great explanation is here
Example to implement callback method using interface.
Define the interface, NewInterface.java.
package javaapplication1;
public interface NewInterface {
void callback();
}
Create a new class, NewClass.java. It will call the callback method in main class.
package javaapplication1;
public class NewClass {
private NewInterface mainClass;
public NewClass(NewInterface mClass){
mainClass = mClass;
}
public void calledFromMain(){
//Do somthing...
//call back main
mainClass.callback();
}
}
The main class, JavaApplication1.java, to implement the interface NewInterface - callback() method. It will create and call NewClass object. Then, the NewClass object will callback it's callback() method in turn.
package javaapplication1;
public class JavaApplication1 implements NewInterface{
NewClass newClass;
public static void main(String[] args) {
System.out.println("test...");
JavaApplication1 myApplication = new JavaApplication1();
myApplication.doSomething();
}
private void doSomething(){
newClass = new NewClass(this);
newClass.calledFromMain();
}
#Override
public void callback() {
System.out.println("callback");
}
}
Then regarding your answer, in actually you have a 2 possibilities... The first one is the answer from #Rodolfoo Perottoni and the other possibility are correctly, read this post please!
I prefer the second way because I can update when I need it.
I would create a inner class in the MainActivity that extends the AsyncTask and voila all data is there already by getters.
In the reference application, RegionBootstrap is initialised in a custom application class on it's onCreate method and of course, the application class is called before any activity is called.
Is there a way to initialise RegionBootstrap inside an activity? I already tried making a static variable of RegionBootstrap so i can call it in a different activity, but unfortunately, it doesn't work.
BeaconApplication.regionBootstrap = new RegionBootstrap((BootstrapNotifier) this.getApplication(), downloadedBeacons);
The Regions I needed to be initialised will come from a server, so initialisation of RegionBootstrap must not come from the application class.
* EDIT *
public class LoginActivity extends ActionBarActivity {
…
/*** short version ***/
#Override
protected void onCreate(Bundle savedInstanceState) {
/*** after successful login ***/
BeaconApplication.beacons = downloadBeaconsFromServer();
}
}
public class BeaconActivity extends ActionBarActivity {
…
#Override
protected void onCreate(Bundle savedInstanceState) {
…
startService(new Intent(this, BeaconService.class));
}
}
This is where I implemented BeaconConsumer
public class BeaconService extends Service implements BeaconConsumer {
private BeaconManager beaconManager;
private BeaconNotifier beaconNotifier;
private RegionBootstrap regionBootstrap;
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setBackgroundBetweenScanPeriod(1001);
beaconManager.setBackgroundScanPeriod(101);
beaconManager.setForegroundScanPeriod(101);
beaconManager.setForegroundBetweenScanPeriod(1001);
beaconNotifier = new BeaconNotifier(this);
beaconManager.bind(this);
}
#Override
public void onBeaconServiceConnect() {
beaconManager.setMonitorNotifier(beaconNotifier);
monitorBeacons();
regionBootstrap = new RegionBootstrap(beaconNotifier, BeaconApplication.beacons);
}
private void monitorBeacons() {
for (Region beacon : BeaconApplication.beacons) {
try {
Log.i(TAG, "Monitoring beacon " + beacon.getUniqueId());
beaconManager.startMonitoringBeaconsInRegion(beacon);
} catch (RemoteException e) {
Log.e(TAG, "Monitoring beacon failed");
e.printStackTrace();
}
}
}
}
Implementation of BeaconNotifier
public class BeaconNotifier implements BootstrapNotifier {
private Context context;
public BeaconNotifier(Context context) {
this.context = context;
}
#Override
didEnter.. etc
#Override
public Context getApplicationContext() {
return context;
}
}
You can use:
BeaconManager.setMonitorNotifier(MonitorNotifier);
BeaconManager.startMonitoringBeaconsInRegion(Region);
But do not forget, in order to use BeaconManager methods, you have to wait until BeaconService is connected. Be aware, with this methods, you need to create your own service if you want to monitor beacons even if app is killed.
Btw, I remember, once I have also faced a problem with RegionBootstrap. I used a trick to handle that problem. Can you test following code?
...
BeaconManager.bind(yourConsumer);
...
//wait until BeaconConsumer.onBeaconServiceConnect() is called
//write following code inside of onBeaconServiceConnect
RegionBootstrap dummy = new RegionBootstrap(mBootstrapNotifier, new Region("dummy", null, null, null));
dummy.disable();
//after this point you can create your own RegionBootstrap
There is a key point in here, you need to create your own BootstrapNotifier. If you are doing this in an activity, you can do this:
public class YourActivity extends Activity implements BootstrapNotifier {
...
BootstrapNotifier mBootstrapNotifier = this;
...
Or in an Application class:
public class YourApp extends Application implements BootstrapNotifier {
...
BootstrapNotifier mBootstrapNotifier = this;
...
In my case, I have created an adapter and that adapter requires Contextin its constructor and I have used that adapter as BootstrapNotifier:
public class AltBeaconAdapter implements BootstrapNotifier {
private Context mContext;
...
public AltBeaconAdapter(Context context) {
mContext = context;
...
}
#Override
public Context getApplicationContext() {
return mContext;
}
...
}
Also, you have to implement MonitorNotifier methods since BootstrapNotifier is a sub class of MonitorNotifier.
Yes, this trick is weird and it shows there is an error in the library with initializing RegionBootstrap but I have service so I switched to first method that I proposed to you. If this trick works for you too, let me know so that I can create an issue on the library's GitHub page.
i've seen this thread : How to implement a listener about implement listeners.
its actually pretty simple but i don't get how exactly its done and how to implement in my own code.
i have this static variable variable: AppLoader.isInternetOn.
i want to build a listener which will listen to this variable changes and update a TextView.
should i do this: ?
build an interface:
public interface InternetStateListener {
public void onStateChange();
}
run it in my activity:
public class MyActivity extends Activity {
private InternetStateListener mListener;
setTheListener(this);
public void setTheListener(InternetStateListener listen) {
mListener = listen;
}
private void onStateChange() {
if (mListener != null) {
if (AppLoader.isInternetOn)
text.setText("on")
else
text.setText("off")
}
}
}
Your Activity does nothing special, just register itself (since the interface is implemented directly in the class) with the Other class that provides the listener.
public class MyActivity extends Activity implements InternetManager.Listener {
private TextView mText;
private InternetManager mInetMgr;
/* called just like onCreate at some point in time */
public void onStateChange(boolean state) {
if (state) {
mText.setText("on");
} else {
mText.setText("off");
}
}
public void onCreate() {
mInetMgr = new InternetManager();
mInetMgr.registerListener(this);
mInetMgr.doYourWork();
}
}
The other class has to do pretty much all the work. Besides that it has to handle the registration of listeners it has to call the onStateChange method once something happend.
public class InternetManager {
// all the listener stuff below
public interface Listener {
public void onStateChange(boolean state);
}
private Listener mListener = null;
public void registerListener (Listener listener) {
mListener = listener;
}
// -----------------------------
// the part that this class does
private boolean isInternetOn = false;
public void doYourWork() {
// do things here
// at some point
isInternetOn = true;
// now notify if someone is interested.
if (mListener != null)
mListener.onStateChange(isInternetOn);
}
}
The part that you're missing it the class that actually notifies the listener. So you would need a class (most likely a service) that runs and pings the state of the network. Then when it detects a change it should call onStateChange() in any registered listeners. Then you would call setTheListener on that service, not on your activity.
Here's a link that thoroughly describes this design pattern: http://en.wikipedia.org/wiki/Observer_pattern
If I got class A and class B, class A act as a menu with 2 buttons one to connect one to login. When I press connect i run this method:
private void connect(){
Thread t1 = new Thread(){
public void run(){
connection_class = new ConnectionClass();
connection_class.run();
}
};t1.start();
}
which calls my ConnectionClass which does this in the constructor:
public ConnectionClass(){
socket = new Socket("address", port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
}
works great im connected to the server and press login which does (without the onClick stuff):
connection_class.MethodToWriteToServer("CommandThatLogsMeIn");
Intent i = new Intent().setClass(v.getContext(), Class.class);
startActivity(i);
This works fine but when im in Class B I want to use the same instance of it. I could just do a new thread and instance of the class but that would defeat the purpose of the start menu and require me to log in once more.
Is it somehow possible to pass the instance as a parameter to the activity when starting it or whats the android way of doing it?
As a sidenote I dont really NEED the menu but ive got some spare time before the assignment is due and thought I might aswell try it.
I have just finished a project like this yesterday.
For example you have this connection manager, called WebService:
// singleton class
public class WebService {
private static WebService instance;
private WebService() {}
public static WebService getInstance() {
if (instance == null)
instance = new WebService();
return instance;
}// getInstance()
public void login() {};
public void getFeeds() {};
public void logout() {};
}
Then you can put it in an base activity like this:
public class WebServiceActivity extends Activity {
private final WebService fWebService = WebService.getInstance();
protected WebService ws() { return fWebService; }
}
Then, you have two activities, LoginActivity and WorkingActivity:
public class LoginActivity extends WebServiceActivity {
buttonLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
ws().login();
// start WorkingActivity if logging in ok
} catch (...) { ... }
}
});
}
public class WorkingActivity extends WebServiceActivity {
buttonGetFeeds.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ws().getFeeds();
}
});
buttonLogout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ws().logout();
finish();
}
});
}
Anyway, there are many approaches. The one above is mine. Hope it helps you :-)
I am still don't sure if this is the correct way or not. But I prefer to use a static instance of the class like this:
// Create this class just once
public class MediaManager {
public static MediaManager instance;
public MediaManager() {
instance = this;
}
public void addNewImage(Bitmap bitmap) {
//....
}
}
//
public class AnotherClass {
public void doSomething() {
MediaManager.instance.addNewImage(..);
}
}
If somebody know a better way of using Manager Classes please make comment.