I want to create a singleton object using RoboGuice but I get null exception. I don't know what is wrong with my codes.
#Singleton
public class SessionService {
private static Session session;
public Session getSession() {
if (session == null){
session = new Session();
}
return session;
}
}
--
public class ChannelManager {
#Inject SessionService sessionService;
public String getName(){
return sessionService.getSession().getName();
}
}
public class MainActivity extends RoboActivity{
#InjectView(R.id.button1) Button btn;
#Inject SessionService a;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
a.getSession().setName("dsadas");
Log.i("A","NEW: "+ a.getSession().getName());
Log.i("A","NEW NAME: "+ new ChannelManager().getName());
}
I get null exception on "new ChannelManager().getName()" line. What's wrong with that?
Thanks in advance.
When you do new ChannelManager(), you are not using Guice injection, so your injected fields are null.
To inject your ChannelManager, either use the #Inject annotation or use the following code to create your instance:
ChannelManager myChannelManager = RoboGuice.getInjector(this).getInstance(ChannelManager.class);
Also consider if there is necessity to use 'new' operator to create e Object. This always implicate some problems especially in (unit)tests.
Related
When launching the activity I get a error:
java.lang.InstantiationException: java.lang.Class<com.example.ui.activities.NoteActivity> has no zero argument constructor
Could someone please help me fix this? Please see the class code below.
Quick summary of the code: it's trying to do an insert into an SQlite database by calling noteDao.insert(note); Note is instantiated and the values are set in the constructor as seen in the code below. But I think I havent initialised the noteDao properly as the IDE shows it as being greyed out and underlined stating its declared but not initialised. but I don't know how to fix this.
private EditText automaticThoughtET;
#Inject
ViewModelProviderFactory providerFactory;
#NonNull
private final NoteDao noteDao;
#Inject
public NoteActivity(#NonNull NoteDao noteDao) {
this.noteDao = noteDao; }
private SharedPreferences loginPref, workoutPref;
private int userId, therapistId, distortions = 0;
private FloatingActionButton nextButton;
private static final String TAG = "sqCbtId";
private int sqCbtId;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_note);
// Initialising editText form the xml file
automaticThoughtET = findViewById(R.id.noteThoughtInput);
// Initialising the nextButton form the xml file
nextButton = findViewById(R.id.noteActivityButton);
nextButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Note note = new Note(userId, therapistId, "Test", 0, "", "", postedWorkout);
try {
noteDao.insert(note);
} catch (Exception e) {
e.printStackTrace();
}
This part:
#Inject
public NoteActivity(#NonNull NoteDao noteDao) {
this.noteDao = noteDao;
}
is a No-No. You do not mess with activity constructors. You do not override activity cosntructors. You do not write new activity constructors.
Injecting stuff to activity is being done other ways, generally done in onCreate() method. For example, assuming that you are using Dagger, something like this: https://www.vogella.com/tutorials/Dagger/article.html#exercise_androiddagger_di
I am new in Android unit testing and I want to add some unit tests in an existing project. I am using the MVP design architecture. Inside my presenter, I have a call to PreferenceManager in order to get the default SharedPrefences but it always returns null. I have followed some tutorials and advices across stackoverflow on how to mock PreferenceManager and SharedPreferences but I can't make it work. This is my presenter class
#RunWith(MockitoJUnitRunner.class)
public class SettingsPresenterTest {
#Mock
private SettingsView mView;
#Mock
private LocalConfiguration conf;
private SettingsPresenter mPresenter;
public SettingsPresenterTest() {
super();
}
#Before
public void startUp() throws Exception {
MockitoAnnotations.initMocks(LocalConfiguration.class);
MockitoAnnotations.initMocks(PreferenceManager.class);
mPresenter = new SettingsPresenter(mView);
final SharedPreferences sharedPrefs =
Mockito.mock(SharedPreferences.class);
final Context context = Mockito.mock(Context.class);
Mockito.when(PreferenceManager.getDefaultSharedPreferences(context)).
thenReturn(sharedPrefs);
}
#Test
public void notificationsEnabledClicked() throws Exception {
boolean notifsEnabled = false;
mPresenter.notificationsEnabledClicked(notifsEnabled);
Mockito.verify(mView).setNotificationsView(notifsEnabled);
}
}
and here is the method where the SharedPreferences are returned null
public class LocalConfiguration {
public TerritoryDto getLastSavedTerritory() {
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(H.getContext());
String terrritoryString = preferences.getString(SAVED_TERRITORY,
null);
return
SerializerHelper.getInstance().deserialize(terrritoryString,
TerritoryDto.class);
}
}
Could you give me some guidelines on how to resolve this error?
Instead of directly referring to Android SDK, abstract that out from your presenter logics. What this means is, that instead of performing PreferenceManager.getDefaultSharedPreferences(), create an abstraction and ask for territoryString from your abstraction.
What will this give to you, is that your presenter won't know about the precense of neither PreferenceManager nor SharedPreferences, which are from Android SDK, thus you would have enough seams to perform pure unit testing.
Having said this, let's implement the abstractions. Having declared following interface:
public interface Storage {
#Nullable
String getSavedTerritory();
}
To which the concrete implementation would be:
public SharedPrefsStorage implements Storage {
private final SharedPreferences prefs;
public SharedPrefsStorage(Context context) {
prefs = PreferenceManager.getDefaultSharedPreferences();
}
#Nullable
#Override
public String getSavedTerritory() {
return prefs.getString(SAVED_TERRITORY, null);
}
}
Then your presenter would become something like this:
public class LocalConfiguration {
final Storage storage;
public LocalConfiguration(Storage storage) {
this.storage = storage;
}
public TerritoryDto getLastSavedTerritory() {
final String territory = storage.getSavedTerritory();
return SerializerHelper.getInstance().deserialize(territory, TerritoryDto.class);
}
}
This would give you a seam to perform pure unit testing:
#Test
void someTest() {
when(storage.getSavedTerritory()).thenReturn("New York");
...
}
No need to worry about mocking PreferenceManager anymore.
I try make a plugin in android studio to use in Unity.
So I make this method in android studio.
public class MainActivity extends UnityPlayerActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public static String SendMessage(){
return "Message";
}
}
and in Unity,
public class PluginWrapper : MonoBehaviour {
// Use this for initialization
void Start () {
TextMesh textMesh = GetComponent<TextMesh> ();
var plugin = new AndroidJavaClass ("com.thewell_dev.beaconf.MainActivity");
textMesh.text = plugin.CallStatic<string> ("ReturnMessage");
}
}
to use SendMessage() method in unity, using AndroidJavaClass and CallStatic.
It is success.
I can check message in device by unity.
But, one error occurs.
If I change method like this,
public class MainActivity extends UnityPlayerActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public String SendMessage(){
return "Message";
}
}
change SendMessage method type.(static String to String)
and in Unity,
public class PluginWrapper : MonoBehaviour {
// Use this for initialization
void Start () {
TextMesh textMesh = GetComponent<TextMesh> ();
var plugin = new AndroidJavaClass ("com.thewell_dev.beaconf.MainActivity");
textMesh.text = plugin.Call<string> ("ReturnMessage");
}
}
change plugin.CallStaic to plugin.Call
In case, I just delete Static, but it returns no result.
https://docs.unity3d.com/kr/current/ScriptReference/AndroidJavaClass.html
I just change the type. But no returns.
I think I mistake to Call method by AndroidJavaClass,
but I can't find it.
If you know about it, Please help me.
You can use "types" to invoke static methods, as static things are bound to their defining types. You can't, however, use instance methods (non-static methods, that is) without an instance of the type. That's why your second attempt fails. To invoke instance methods, you must get an instance of the type, either by making one yourself by invoking the java constructor like this:
var object = new AndroidJavaObject ("com.some.class", constructor_param1, constructor_param2, constructor_param3, ...);
result = object.Call<string> ("SomeMethod");
Or, to get as instance of something like an activity which is constructed outside the scope of your C# script, you use static methods to retrieve the instance you're looking for:
var type = new AndroidJavaClass ("com.some.class");
var object = type.CallStatic<AndroidJavaObject>( "SomeStaticGetterMethod" );
result = object.Call<string> ("SomeMethod");
I have a custom ListView say CustomListView:
In a fragment there is:
<com.custom.CustomListView
android:id="#+id/custom_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
and in that fragment's source, I have
private CustomListView mCustomListView;
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mContext = getActivity();
mCustomListView = mContext.findViewById(R.id.custom_listview);
}
Then there is some method later:
public void doSomethingOnReceivingData(Data data) {
mCustomListView.someCustomMethod(data);
}
I want to write test for doSomethingOnReceivingData(Data) method.
I can not figure out how to mock the listview so that I can continue with the test (ArgumentCaptors and stuff)?
I would give to list field package local access and mock it in test directly. For our app it is already package accessible since we use Butterknife
#RunWith(MockitoJUnitRunner.class)
public class MainActivityFragmentTest {
#Mock
private CustomListView mCustomListView;
#InjectMocks
private MainActivityFragment fragment;
#Test
public void doSomethingOnReceivingData_callsCustomListView() {
final String data = "data";
fragment.doSomethingOnReceivingData(data);
verify(mCustomListView).someCustomMethod(eq(data));
}
}
I have followed this link and successfully made singleton class in Android.
http://www.devahead.com/blog/2011/06/extending-the-android-application-class-and-dealing-with-singleton/
Problem is that i want a single object. like i have Activity A and Activity B. In Activity A I access the object from Singleton class. I use the object and made some changes to it.
When I move to Activity B and access the object from Singleton Class it gave me the initialized object and does not keep the changes which i have made in Activity A.
Is there any other way to save the changing?
Please help me Experts.
This is MainActivity
public class MainActivity extends Activity {
protected MyApplication app;
private OnClickListener btn2=new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent=new Intent(MainActivity.this,NextActivity.class);
startActivity(intent);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Get the application instance
app = (MyApplication)getApplication();
// Call a custom application method
app.customAppMethod();
// Call a custom method in MySingleton
Singleton.getInstance().customSingletonMethod();
Singleton.getInstance();
// Read the value of a variable in MySingleton
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
Button btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(btn2);
}
}
This is NextActivity
public class NextActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_next);
String singletonVar = Singleton.customVar;
Log.d("Test",singletonVar);
}
}
Singleton Class
public class Singleton
{
private static Singleton instance;
public static String customVar="Hello";
public static void initInstance()
{
if (instance == null)
{
// Create the instance
instance = new Singleton();
}
}
public static Singleton getInstance()
{
// Return the instance
return instance;
}
private Singleton()
{
// Constructor hidden because this is a singleton
}
public void customSingletonMethod()
{
// Custom method
}
}
and MyApplication
public class MyApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
// Initialize the singletons so their instances
// are bound to the application process.
initSingletons();
}
protected void initSingletons()
{
// Initialize the instance of MySingleton
Singleton.initInstance();
}
public void customAppMethod()
{
// Custom application method
}
}
When i run this code, i get Hello which i have initialized in Singleton then World which i gave it in MainActivity and again shows Hello in NextActivity in logcat.
I want it to show world again in NextActivity.
Please help me to correct this.
Tip: To create singleton class In Android Studio, right click in your project and open menu:
New -> Java Class -> Choose Singleton from dropdown menu
EDIT :
The implementation of a Singleton in Android is not "safe" (see here) and you should use a library dedicated to this kind of pattern like Dagger or other DI library to manage the lifecycle and the injection.
Could you post an example from your code ?
Take a look at this gist : https://gist.github.com/Akayh/5566992
it works but it was done very quickly :
MyActivity : set the singleton for the first time + initialize mString attribute ("Hello") in private constructor and show the value ("Hello")
Set new value to mString : "Singleton"
Launch activityB and show the mString value. "Singleton" appears...
It is simple, as a java, Android also supporting singleton. -
Singleton is a part of Gang of Four design pattern and it is categorized under creational design patterns.
-> Static member : This contains the instance of the singleton class.
-> Private constructor : This will prevent anybody else to instantiate the Singleton class.
-> Static public method : This provides the global point of access to the Singleton object and returns the instance to the client calling class.
create private instance
create private constructor
use getInstance() of Singleton class
public class Logger{
private static Logger objLogger;
private Logger(){
//ToDo here
}
public static Logger getInstance()
{
if (objLogger == null)
{
objLogger = new Logger();
}
return objLogger;
}
}
while use singleton -
Logger.getInstance();
answer suggested by rakesh is great but still with some discription
Singleton in Android is the same as Singleton in Java:
The Singleton design pattern addresses all of these concerns. With the Singleton design pattern you can:
1) Ensure that only one instance of a class is created
2) Provide a global point of access to the object
3) Allow multiple instances in the future without affecting a
singleton class's clients
A basic Singleton class example:
public class MySingleton
{
private static MySingleton _instance;
private MySingleton()
{
}
public static MySingleton getInstance()
{
if (_instance == null)
{
_instance = new MySingleton();
}
return _instance;
}
}
As #Lazy stated in this answer, you can create a singleton from a template in Android Studio. It is worth noting that there is no need to check if the instance is null because the static ourInstance variable is initialized first. As a result, the singleton class implementation created by Android Studio is as simple as following code:
public class MySingleton {
private static MySingleton ourInstance = new MySingleton();
public static MySingleton getInstance() {
return ourInstance;
}
private MySingleton() {
}
}
You are copying singleton's customVar into a singletonVar variable and changing that variable does not affect the original value in singleton.
// This does not update singleton variable
// It just assigns value of your local variable
Log.d("Test",singletonVar);
singletonVar="World";
Log.d("Test",singletonVar);
// This actually assigns value of variable in singleton
Singleton.customVar = singletonVar;
I put my version of Singleton below:
public class SingletonDemo {
private static SingletonDemo instance = null;
private static Context context;
/**
* To initialize the class. It must be called before call the method getInstance()
* #param ctx The Context used
*/
public static void initialize(Context ctx) {
context = ctx;
}
/**
* Check if the class has been initialized
* #return true if the class has been initialized
* false Otherwise
*/
public static boolean hasBeenInitialized() {
return context != null;
}
/**
* The private constructor. Here you can use the context to initialize your variables.
*/
private SingletonDemo() {
// Use context to initialize the variables.
}
/**
* The main method used to get the instance
*/
public static synchronized SingletonDemo getInstance() {
if (context == null) {
throw new IllegalArgumentException("Impossible to get the instance. This class must be initialized before");
}
if (instance == null) {
instance = new SingletonDemo();
}
return instance;
}
#Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Clone is not allowed.");
}
}
Note that the method initialize could be called in the main class(Splash) and the method getInstance could be called from other classes. This will fix the problem when the caller class requires the singleton but it does not have the context.
Finally the method hasBeenInitialized is uses to check if the class has been initialized. This will avoid that different instances have different contexts.
The most clean and modern way to use singletons in Android is just to use the Dependency Injection framework called Dagger 2. Here you have an explanation of possible scopes you can use. Singleton is one of these scopes. Dependency Injection is not that easy but you shall invest a bit of your time to understand it. It also makes testing easier.