while making an Android app, I have ran in the following problem:
My MainActivity looks like this:
...
private String token;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
tokenSetter();
}
private void tokenSetter() {
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(task -> {
if (!task.isSuccessful()) {
Log.w("TRAZENITOKEN", "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = Objects.requireNonNull(task.getResult()).getToken();
setToken(token);
Log.d("TRAZENITOKEN", "onGetToken: " + token);
// Log and toast
// Log.d("TRAZENITOKEN", "onComplete: " + token);
});
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
I know that the token value is being set as in an another method inside this MainActivity class, when I call getToken(), I get the value.
However, when I try to call getToken from an another Activity, something like this:
...
button.setOnClickListener(view -> {
FirebaseActions firebaseActions = new FirebaseActions();
MainActivity mainActivity = new MainActivity();
//firebaseActions.setUserNameOnToken(editText.getText().toString());
if(mainActivity.getToken() != null) editText.setText(mainActivity.getToken());
else editText.setText("Skafiskafnjak");
});
(I opted for the editText.setText method for debugging purposes, I am going to use it in the commented way)
The code snippet above always goes to the else part as the getToken is null.
Why does it return null in this class, if it returns a value in it's own class?
Could it be perhaps because I did
MainActivity mainActivity = new MainActivity();
An answer would be appreciated.
Thanks in advance!
MainActivity mainActivity = new MainActivity();
This activity instance is not the same one that the Android system created where you see the token being set. Besides, we never create an activity with new. The Android system creates activities according to the activity lifecycle and your code must work within this structure. To pass data between activities, you need to send it in the Intent when you call startActivity(). See the documentation for an example of how to do this.
Creating new activity causes new instance of that activity, therefor a new token which would be null
Send the token through the intent as String data from your MainActivity, and then from the second Activity, grab that String data(token), and do with it whatever you want.
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
intent.putExtra("token", yourTokenValue);
startActivity(intent);
and in onCreate method of your SecondActivity,you can use getIntent().getStringExtra("token"); to retrieve the token value which was passed from the first Activity
String token= getIntent().getStringExtra("token");
Related
I need write a service which will update the list in MainActivity every 30sec. I use MVVM with ViewModel and LiveData and so my Service class looks like this:
public class ArticleJobService extends JobService {
public static String TAG = "ArticleJobService";
private Context context = this;
#Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d(TAG, "onStartJob");
MainActivity.PAGE_NUMBER++;
LiveData<List<Article>> liveArticles = ArticleRepository.getInstance(getApplication()).getArticles(MainActivity.PAGE_NUMBER);
liveArticles.observeForever(new Observer<List<Article>>() {
#Override
public void onChanged(#Nullable List<Article> articles) {
Log.d(TAG, "onStartJob - onChanged!!!!!!");
liveArticles.removeObserver(this);
NotificationUtils.showNotification(context, articles.get(0).getSectionName(), articles.get(0).getWebTitle());
jobFinished(jobParameters, true);
}
});
return true;
}
}
Class for my notification:
public static void showNotification(Context context, String section, String title) {
PendingIntent contentPendingIntent = PendingIntent.getActivity
(context, REQUEST_CODE, new Intent(context, MainActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager manager =
(NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
manager.createNotificationChannel(createNotificationChannel(context));
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
.setContentTitle(section)
.setContentText(title)
.setContentIntent(contentPendingIntent)
.setSmallIcon(R.drawable.app_icon)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setAutoCancel(true);
manager.notify(0, builder.build());
}
When Onchanged in JobService works I get the list and show a notification. Notification opens MainActivity which makes new call to api as it always did. What changes do I have to make in order the MainActivity to show the list that I got from the service??? I really can't tie this up together.
I heard of IPC but wouldn't do that, I want some simpler practice which I sure exists which I just don't know about.
Also, there are two cases: Notification came and MainActivity is open, app is open but MainActivity is not in the foreground and app is on the background or closed. How should I handle each of these cases?
See also piece of code from MainActivity onCreate:
mArticleViewModel = ViewModelProviders.of(this).get(ArticleViewModel.class);
mArticleViewModel.getArticleList(PAGE_NUMBER).observe(this, articles -> {
Log.d(TAG, "List<Result> onChanged!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
mProgressBar.setVisibility(View.GONE);
mProgressBarMain.setVisibility(View.GONE);
mIsLoading = false;
mArticles = articles;
Please provide the best practices for this task, I know it's very common I just do it first time and using LiveData makes it way more complicated.
Here is Also Repository code:
public static ArticleRepository getInstance(Application application){
if(INSTANCE == null){
return new ArticleRepository(application);
}
return INSTANCE;
}
private ArticleRepository(Application application) {
Log.d(TAG, "ArticleRepository constructor");
mContext = application;
mArticles = new MutableLiveData<>();
ArticleRoomDatabase db = ArticleRoomDatabase.getInstance(application);
mArticleDao = db.articleDao();
}
public LiveData<List<Article>> getArticles(int page) {
Log.d(TAG, "getArticles");
if (NetworkUtils.isOnline(mContext)) {
Log.d(TAG, "isOnline");
mArticles = loadFromNetwork(page);
} else {
Log.d(TAG, "is NOT Online");
mArticles = loadFromDB(page);
}
}
You have this problem specifically because your Repository implementation is incorrect.
public LiveData<List<Article>> getArticles(int page) {
Log.d(TAG, "getArticles");
if (NetworkUtils.isOnline(mContext)) {
Log.d(TAG, "isOnline");
mArticles = loadFromNetwork(page);
} else {
Log.d(TAG, "is NOT Online");
mArticles = loadFromDB(page);
}
}
If you check the code for NetworkBoundResource, the trick is that you have a single LiveData that binds together the ability to both load from network, and to load from database.
In your case, you are replacing the database's auto-updating query results whenever you have network access - which is why you can't update the MainActivity.
The easiest way (without using a MediatorLiveData) is to have two separate functions on Repository: one for fetchFromNetwork, and one for fetchFromDatabase. The MainActivity should always fetch from database, while the Service always triggers load from network (and inserts it directly into database via a Dao).
This way, the observe function in MainActivity will receive the latest data when Service inserts the data into DB on background thread.
So Azure spit the following code for me to insert into an activity (Android Studio is what I'm using)
Add the following line to the top of the .java file containing your launcher activity:
import com.microsoft.windowsazure.mobileservices.*;
Inside your activity, add a private variable
private MobileServiceClient mClient;
Add the following code the onCreate method of the activity:
mClient = new MobileServiceClient("https://pbbingo.azurewebsites.net", this);
Add a sample item class to your project::
public class ToDoItem{ public String id; public String Text;}
In the same activity where you defined mClient, add the following code:
ToDoItem item = new ToDoItem();
item.Text = "Don't text and drive";
mClient.getTable(ToDoItem.class).insert(item, new TableOperationCallback<item>(){
public void onCompleted(ToDoItem entity, Exception exception, ServiceFilter response)
{
if(exception == null){
//Insert Succeeded
} else {
//Insert Failed
}
}});
My goal is to create a login page. I understand that the above was probably offered up more with a ToList in mind. I just want to get the syntax correct today. The problem I think, is my basic class structure. I have created an OnClick Listener within my on create that gets the ID from a button in my layout. I don't need it checking for anything in the database until the button has been actually clicked to either login or register.
public class LoginClass extends AppCompatActivity{
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.MyLoginLayout);
MobileServiceClient mClient = null;
try {
mClient = new MobileServiceClient ("myAzureWebsite", "AzureKey", this);
} catch (MalformedURLException e) {
e.printStackTrace();
}
Button Attempt = (Button) findViewById (R.id.mySubmitButton);
final MobileServiceClient finalMClient = mClient; // finalized so I can use it later.
Attempt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick (View v) {
final View thisView = v;
final MyToDoItemClass item = new MyToDoItemClass();
In MyToDoItemClass I have two variables (Both String) Just left over from
the example of a ToDoList (they are String ID and String Text)
item.Text = "Filler";
item.ID = "Fill";
finalMClient.getTable(MyToDoItemClass.class).insert(new Table OperationCallback<item>() { //<--- I'm getting an error that the variable, item
is from an unknown class...
public void onCompleted (Item entity, Exception exception, ServiceFilterResponse response){
if(exception == null) {
Intent i = new Intent (LoginClass.this, MainActivity.class);
startActivity(i);
}else{
Toast.makeText(thisView.getContext(), "Failed", Toast.LENGTH_LONG).show();
}}
});
}
});
}}
The problem is with that the TableOperationCallback is saying that the item from MyToDoItemClass class is from an unknown class.
There are many issues in your code, as below.
According to the javadoc for class MobileServiceClient, there is not a method insert(TableOperationCallback<E> callback), so the code finalMClient.getTable(MyToDoItemClass.class).insert(new Table OperationCallback<item>() {...} is invalid.
The generics E in Table OperationCallback<E> means that you need to write a POJO class name instead of E, not an object variable name like item, so the correct code should be new Table OperationCallback<MyToDoItemClass>, please see the Oracle tutorial for Generics to know more details.
The figure below shows all methods insert of class MobileServiceClient. The bold word Deprecated under the method name means that you should not use it for developing on new project, it‘s only compatible for old project on the new version of Java SDK.
Please follow the offical tutorial to develop your app. Any concern, please feel free to let me know.
I have a activity where you select a number in a spinner(dropdown-list in AndroidStudio) and sends it to a new activity/another class, before it is sent to a server. The array-adapter works fine, but using the getExtra Intent in the receiving activity is a lot of trouble for me.
The app crashes and logcat give this message:
NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.getStringExtra(java.lang.String)' on a null object reference.
MainActivity.(MainActivity.java:76)
Line 76 in MainActivity String avd_nr= getIntent().getStringExtra("getData");
This is my code for passing the array value, and the line Log.i("data",avd); posts the spinner value(avd) in the logcat.
btnAvdeling.setOnClickListener(new View.OnClickListener()
{
final String avd = dropdown.getSelectedItem().toString();
#Override
public void onClick(View v)
{
Intent i = new Intent(getApplicationContext(), MainActivity.class);
i.putExtra("getData",avd.toString());
startActivity(i);
Log.i("data",avd);
}
}
This is my code where I receive data
String avd_nr= getIntent().getStringExtra("getData");
private SurveyResponse fillInResponsData(Integer answer) {
surveyResponse.setAvdeling(avd_nr);
return surveyResponse;
}
Please give some help on what i need to add or change
in onCreate() Method put the following :
String avd_nr =getIntent.getExtras("getData");
String avd_nr =getIntent.getExtras("getData");
Its should be on onCreate() method
I'm developing an android app using beacon library, part of this app is about to search for a specific beacon via its minor ID (which is inserted by user via dialog).
if I write everything in the same activity things works fine but I'd like to keep dialogs separate in an external pure java class, so in the activity implementing BeaconConsumer I added a "method" creating and binding the beacon manager.
public class Activity03 extends AppCompatActivity
implements BeaconConsumer, RangeNotifier {
...
public void scanForBeacon(Context context, String selectedMinorId){
beaconManager = BeaconManager.getInstanceForApplication(context);
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
Identifier minorIdFilter = Identifier.parse(selectedMinorId);
myRegion = new Region(
"my_region",
null,
null,
minorIdFilter);
beaconManager.bind((BeaconConsumer) context);
}
...
}
The point is that when calling startRangingBeaconsInRegion, i got:
Attempt to invoke virtual method 'void org.altbeacon.beacon.BeaconManager.startRangingBeaconsInRegion(org.altbeacon.beacon.Region)' on a null object reference
The sequence is:
1. the user is asked (via GoogleApiClient) to switch on BLE and localization
2. inside onActivityResult the dialog for inserting minor ID is picked from the java class DialogUtilities
DialogUtilities.showSelectionDialog(Activity03.this);
3. pressing the button dialog is dismissed, an instance of the BeaconConsumer activity is created and the method called:
Activity03 a03 = new Activity03();
a03.scanForBeacon(context, minorId);
4. when the onBeaconServiceConnect() is called I got null object reference on the line of startRangingBeaconsInRegion
#Override
public void onBeaconServiceConnect() {
try {
beaconManager.startRangingBeaconsInRegion(myRegion);
} catch (RemoteException e) {
e.printStackTrace();
}
}
I'm new of java and android but it doesn't seems to me that problem is about the Region because I've the same response even if I set to null all the Identifiers so I cannot understand why null reference.
Is it possible that I create two different BeaconMangers because of the activity's istance I return by Dialog ? If so how I can solve it?
If not, how to avoid this null object reference?
Thanks in advance
EDIT
BeaconManager declaration
public class Activity03 extends AppCompatActivity implements BeaconConsumer, RangeNotifier {
static final int REQUEST_CHECK_SETTINGS = 1000;
private BeaconManager beaconManager;
private Region myRegion;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_03);
}
#Override
protected void onResume() {
#Override
super.onResume();
PermissionsUtilities.switchLocationAndBluetooth(Activity03.this);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
final LocationSettingsStates states = LocationSettingsStates.fromIntent(data);
switch (requestCode) {
case REQUEST_CHECK_SETTINGS:
switch (resultCode) {
case Activity.RESULT_OK:
DialogUtilities.showSensorSelectionDialog(Activity03.this);
break;
case Activity.RESULT_CANCELED:
...
break;
default:
break;
}
break;
}
}
You can try the code below to avoid null pointer exception:
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection beacons, Region region) {
if (beacons.size() > 0) {
Log.i(TAG, "The first beacon I see is about "+beacons.iterator().next().getDistance()+" meters away.");
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(new Region("myRangingUniqueId", null, null, null));
} catch (RemoteException e) {
e.printStackTrace();
}
The question does not show the declaration of beaconManager and how it is scoped, so it is hard to say the exact cause.
Two tips:
The BeaconManager is a singleton, meaning there is one instance per Java process. So you can always get this instance from within an Activity like this: BeaconManager.getInstanceForApplication(this).startRangingBeaconsInRegion(myRegion);
Manually constructing a new Activity instance as shown below generally will not work in Android programming. You must create new Activity instance using an Intent. In your case I suspect you may not want to create a new Activity instance at all but to get a reference to the existing one. This may be unrelated to what you are asking, but it will certainly need to be changed: Activity03 a03 = new Activity03();
a03.scanForBeacon(context, minorId);
I am fairly new to java / android programming and have mostly been following tutorials / reading. I have 2 classes called MainActivity and Homeactivity, the MainActivity is where the user logs in and HomePageactivity is opened via intent if the login is correct.
The username is passed through an edit text to which i have used the following code in the main class
String CurrentUser = editTextusername.getText().toString();
public String GetCurrentUser ()
{
return CurrentUser;
}
And this in the homepage class
MainActivity testing = new MainActivity();
String x = testing.GetCurrentUser();
CurrentUserName.setText(x);
This seems like it should work to me, how ever when launching my application it just crashes, and without the lines of code in the main activity it works fine
Any ideas as to what im doing wrong here guys
The String may be null during setting to TextView check before setting to textView
String CurrentUser = editTextusername.getText().toString();
public String GetCurrentUser ()
{
if(currentUser.length>0&¤tUser!="")
return CurrentUser;
else return "empty";
}
String x = testing.GetCurrentUser();
CurrentUserName.setText(""+x);
You can use intent to carry info from one Activity to another.
Read this: Intents
It is quite easy to transfer strings and primitive data types via intent, using putExtra() .
Some example code to make it more clear:
//this runs, for example, after a button click
Intent intent = new Intent(this,SecondActivity.class);
intent.putExtra("username", userName);
startActivity(intent);
At the other end you can take them as like this:
String username = getIntent().getStringExtra("username");