Hi in my lib module I'm having a interface like this,
public interface ServiceData {
void deviceName();
}
I implement this in Main app module in Activity as follows,
MainActivity extends AppCompatActivity implements ServiceData
#Override
public void deviceName() {
}
}
I have to invoke this in a class file which is also in lib module. I searched and found solution like
ServiceData service = (ServiceData) context;
But it throws ClassCastException. How can I invoke this in a class file? Any help will be appreciated and thanks in advance.
Use localbroadcastmanager.
In lib
Intent intent = new Intent("YOUR_INFO");
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context);
manager.sendBroadcast(intent);
In app.
IntentFilter intentFilter = new IntentFilter("YOUR_INFO");
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
manager.registerReceiver(broadcastReceiver, intentFilter);
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d("MainActivity","your info" +" "+action);
if(action.equals("YOUR_INFO")) {
}
}
};
Related
I am trying to get list of available wifi network and display it in a list view. In PCL project, i created an interface 'IWifiService'.
public interface IWifiService
{
void GetWifiList();
}
In android project a class WifiService to get all networks list.
[assembly:Dependency(typeof(WifiService))]
namespace WifiConnectivity.Droid.WifiService
{
public class WifiService : IWifiService
{
private static WifiManager wifi;
private WifiReceiver wifiReceiver;
public static List<string> WiFiNetworks;
public void GetWifiList()
{
WiFiNetworks = new List<string>();
var context = Android.App.Application.Context;
wifi = (WifiManager)context.GetSystemService(Context.WifiService);
wifiReceiver = new WifiReceiver();
context.RegisterReceiver(wifiReceiver, new IntentFilter(WifiManager.ScanResultsAvailableAction));
wifi.StartScan();
}
public class WifiReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
IList<ScanResult> scanWifiNetworks = wifi.ScanResults;
foreach(ScanResult wifinetwork in scanWifiNetworks)
{
WiFiNetworks.Add(wifinetwork.Ssid);
}
}
}
}
}
And from ViewModel i am calling a Dependency Service like this:
var service = DependencyService.Get<IWifiService>();
service.GetWifiList();
Now the class WifiReceiver cannot return anything, so i am not being able to get those list of networks in my ViewModel. How can i get this list into my ViewModel?
I would suggest that you return a List in your GetWifiList method so the interface looks something like this:
public interface IWifiService
{
void GetWifiList(Action<List<string>> action);
}
And then your GetWifiList method will look like this:
public static Action<List<string>> CallBackAction;
public void GetWifiList(Action<List<string>> callBackMethod)
{
WiFiNetworks = new List<string>();
var context = Android.App.Application.Context;
wifi = (WifiManager)context.GetSystemService(Context.WifiService);
wifiReceiver = new WifiReceiver();
context.RegisterReceiver(wifiReceiver, new IntentFilter(WifiManager.ScanResultsAvailableAction));
wifi.StartScan();
CallBackAction= callBackMethod;
}
And then in your OnRecieve method, you execute the callback method:
public override void OnReceive(Context context, Intent intent)
{
IList<ScanResult> scanWifiNetworks = wifi.ScanResults;
foreach(ScanResult wifinetwork in scanWifiNetworks)
{
WiFiNetworks.Add(wifinetwork.Ssid);
}
CallBackAction(WiFiNetworks);
}
And now the most important part of the callback method and what to pass as your argument:
A System.Action is basically a method reference where you pass the name of your call back method something like below:
var service = DependencyService.Get<IWifiService>();
service.GetWifiList(MyCallBackAction);
Where MyCallBackAction is as below:
public void MyCallBackAction(List<string> wifiNetworks)
{
// this method will be called every time you get a callback at OnRecieve
}
I have a class structure as below
public class Admin extends DeviceAdminReceiver
{
public static class PubSub extends Activity
{
protected void onCreate(Bundle savedInstanceState) {
messageIntentReceiver = new MQTTMessageReceiver();
IntentFilter intentCFilter = new IntentFilter(MQTTService.MQTT_MSG_RECEIVED_INTENT);
registerReceiver(messageIntentReceiver, intentCFilter);
}
#Override
protected void onDestroy()
{
unregisterReceiver(messageIntentReceiver);
super.onDestroy();
}
public class MQTTMessageReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle notificationData = intent.getExtras();
String newTopic = notificationData.getString(MQTTService.MQTT_MSG_RECEIVED_TOPIC);
String newData = notificationData.getString(MQTTService.MQTT_MSG_RECEIVED_MSG);
Log.e("Received Message on",newTopic+"- "+newData);
}
}
}
}
The receivers are dynamically registered and unregistered. The broadcast receiver works while PubSub activity stays on the screen. How to make it work from outside of activity?
I tried to do it in static way by registering in manifest.xml, but that dint work as MQTTMessageReceiver is a non static inner class. Cant able to instantiate the receiver runtime error I get.
I cant change the MQTTMessageReceiver class static as i need to access outer class members.
I want to dynamically control location tracking (registering / unregistering location broadcast receiver). This is how I am planning to do it. I have two questions :
What are the mistakes in the implementation below because all this concept is still very theoretical to me as I am very new to android/java dev. Still building concepts!
How do I pass some EXTRA_INFO from my location library class to the location receiver.
IMPLEMENTATION:
I have a library class LocationLibrary.java which consists of two methods. They do as the name suggest. The location tracking should start when I call startTracking(). Plz note the extraInfo that needs to be passed to myLocationReceiver. The tracking should stop when stopTracking() is called.
Code snippet:
public class LocationLibraray
{
private static BroadcastReceiver myLocationReceiver;
public LocationLibraray(Context context)
{
this.ctx = context;
myLocationReceiver = new MyLocationReceiver();
}
public void startTracking(Context context, String extraInfo)
{
IntentFilter filter = new IntentFilter();
filter.addAction("com.app.android.tracker.LOCATION_READY");
context.registerReceiver(myLocationReceiver, filter);
// NEED TO PASS extraInfo to myLocationReceiver for some processing, but HOW?
}
public void stopTracking(Context context)
{
context.unregisterReceiver(locationReceiver);
}
}
MyLocationReceiver.java
public class MyLocationReceiver extends BroadcastReceiver {
public void onReceive(final Context context, Intent intent) {
if ((intent.getAction() != null) &&
(intent.getAction().equals("com.app.android.tracker.LOCATION_READY")))
{
//GET THAT EXTRA INFO FROM LocationLibrary class and process it here
}
}
}
Please help me out. Thnx!
Why not add a constructor to MyLocationReceiver?
public class MyLocationReceiver extends BroadcastReceiver {
String info = "";
public MyLocationReceiver(String extraInfo)
{
this.info = extraInfo;
}
........
public void onReceive(final Context context, Intent intent) {
if ((intent.getAction() != null) &&
(intent.getAction().equals("com.app.android.tracker.LOCATION_READY")))
{
if (info.contains("Hi"))
//do some stuff
}
}
}
And you would instantiate it like this:
myLocationReceiver = new MyLocationReceiver(new String("Hello!"));
i need to use my application class inside my thread which is started with InterService.
in my IntentService i have the following code:
protected void onHandleIntent(Intent intent) {
final ResultReceiver receiver = intent.getParcelableExtra("receiver");
context = getBaseContext();
app = (AppLoader)getApplicationContext();
ConnectionThread thread = new ConnectionThread(receiver, context, app.getNewApp());
this is my Thread:
public ConnectionThread (ResultReceiver receiver, Context context, AppLoader app)
{
this.receiver = receiver;
this.context = context;
this.activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
this.app = app;
}
#Override
public void run() {
Log.d("ConnectionThread","Starting Server Connection");
try {
while(isThereActivityRunning()) {
if(app.isInternetOn())
{
Log.d("ConnectionThread", app.getText());
results = sendGetMessage();
b.putString("results", results);
receiver.send(2, b);
}
this is my application:
public class AppLoader extends Application{
private AppLoader newApp;
public void onCreate()
{
super.onCreate();
}
public AppLoader getNewApp()
{
if(newApp == null)
newApp = new AppLoader();
return newApp;
}
i get a java.lang.NullPointerException and i can't figure out why..
You can't create your own Application instance, i.e.
newApp = new AppLoader();
is not meant to be called. Android creates the app for you, or at least it does if you declared your application class in the manifest, i.e.
<application ... android:label="#string/app_name" android:name="AppLoader" android:debuggable="true">
It will compile but you won't have access to anything that an Android-instantiated application normally would.
Assuming you have the manifest as above, you already have access to the application instance by calling:
app = (AppLoader)getApplicationContext();
so use that and delete the getNewApp() method.
Here's a BroadcastReceiver from my project, which I'm looking to unit test. When the user makes a phone call, it grabs the phone number, and sets up an intent to start a new activity, passing in the phone number.
public class OutgoingCallReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context xiContext, Intent xiIntent)
{
if (xiIntent.getAction().equalsIgnoreCase(Intent.ACTION_NEW_OUTGOING_CALL))
{
String phoneNum = xiIntent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Intent intent = new Intent(xiContext, MyActivity.class);
intent.putExtra("phoneNum", phoneNum);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
xiContext.startActivity(intent);
setResultData(null);
}
}
}
So far, my unit test looks like this:
public class OutgoingCallReceiverTest extends AndroidTestCase
{
private OutgoingCallReceiver mReceiver;
#Override
protected void setUp() throws Exception
{
super.setUp();
mReceiver = new OutgoingCallReceiver();
}
public void testStartActivity()
{
Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
intent.putExtra(Intent.EXTRA_PHONE_NUMBER, "01234567890");
mReceiver.onReceive(getContext(), intent);
}
}
This runs through the code, but I want my test to be able to check that the intent was sent out, and to check the phone number on it. How do I do this?
Can I also test that the phone call gets cancelled (because of the setResultData(null) line)?
corlettk pointed me at the MockContext object in Android, which does the trick. I've made a subclass of it, TestContext, which looks like this:
public class TestContext extends MockContext
{
private List<Intent> mReceivedIntents = new ArrayList<Intent>();
#Override
public String getPackageName()
{
return "com.mypackage.test";
}
#Override
public void startActivity(Intent xiIntent)
{
mReceivedIntents.add(xiIntent);
}
public List<Intent> getReceivedIntents()
{
return mReceivedIntents;
}
}
And my test case now looks like this:
public class OutgoingCallReceiverTest extends AndroidTestCase
{
private OutgoingCallReceiver mReceiver;
private TestContext mContext;
#Override
protected void setUp() throws Exception
{
super.setUp();
mReceiver = new OutgoingCallReceiver();
mContext = new TestContext();
}
public void testStartActivity()
{
Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
intent.putExtra(Intent.EXTRA_PHONE_NUMBER, "01234567890");
mReceiver.onReceive(mContext, intent);
assertEquals(1, mContext.getReceivedIntents().size());
assertNull(mReceiver.getResultData());
Intent receivedIntent = mContext.getReceivedIntents().get(0);
assertNull(receivedIntent.getAction());
assertEquals("01234567890", receivedIntent.getStringExtra("phoneNum"));
assertTrue((receivedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0);
}
}
Matt,
Sounds like you need to mock-up a Context ... and then swap your methods over to accepting interfaces instead of concrete classes: public void onReceive(IContext c, IIntent i), just for the purposes of testing. But then the Context and Intent classes aren't yours are they... they're Android's... so you can't "just" make them implement your interfaces, so you'd have to "wrap" them in order to expose a your interface, which is RATHER a lot of code for not much gain. Very Yucky!!!
So I started to wonder if someone's been through all this before, and done the hard-yards for us... and tada: http://developer.android.com/reference/android/test/mock/package-summary.html
Cheers. Keith.
Since this question was asked mocking Frameworks have evolved pretty much. With mockito you can now mock not only interfaces but as well classes. So I would suggest to solve this problem by mocking a context and using ArgumentCapture:
import static org.mockito.Mockito.*;
public class OutgoingCallReceiverTest extends AndroidTestCase {
private OutgoingCallReceiver mReceiver;
private Context mContext;
#Override
protected void setUp() throws Exception {
super.setUp();
//To make mockito work
System.setProperty("dexmaker.dexcache",
mContext.getCacheDir().toString());
mReceiver = new OutgoingCallReceiver();
mContext = mock(Context.class);
}
public void testStartActivity() {
Intent intent = new Intent(Intent.ACTION_NEW_OUTGOING_CALL);
intent.putExtra(Intent.EXTRA_PHONE_NUMBER, "01234567890");
mReceiver.onReceive(mContext, intent);
assertNull(mReceiver.getResultData());
ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).startActivity(argument.capture());
Intent receivedIntent = argument.getValue();
assertNull(receivedIntent.getAction());
assertEquals("01234567890", receivedIntent.getStringExtra("phoneNum"));
assertTrue((receivedIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0);
}
}