Android PreferenceList, sublist after a choice - java

I'm looking for a way to show a second list in a preference, after a user has selected a choice in a listpreference
For example : the user selects the option "Send sms to" from a list, then a second list appears, and the user can choose a contact.
At the moment, i'm trying to put a onSharedPreferenceChanged method from my preference activity, and show an alert Dialog containing the contacts after a selection, but i think there is another way... But i havent found it yet on the Internet...
Does anyone know how it is possible ?
Thank's

In your PreferenceActivity put a method like below that listens for when that specific key is clicked.
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
//Make sure the item changed was the list_preference
if(key.equals("list_preference")) {
String value = sharedPreferences.getString(key, "Nothing");
if(value.equals("Send_sms")) {
//launch AlertDialog with list or launch new preference
}
}
}

Related

Return message if no checkbox is selected

How to implement more into this code so that it returns a message telling the user to 'select at least one checkbox' if he/ she does not select any?
public void verificaCheckBox() {
Listcheck.clear();
if (cbPapel.isChecked())
Listcheck.add(cbPapel.getText().toString());
if (cbPlastico.isChecked())
Listcheck.add(cbPlastico.getText().toString());
if (cbMetal.isChecked())
Listcheck.add(cbMetal.getText().toString());
if (cbVidro.isChecked())
Listcheck.add(cbVidro.getText().toString());
cbSelecionado = (Listcheck.toString());
}
public String verificaCheckBox(){
Listcheck.clear();
if (cbPapel.isChecked())
Listcheck.add(cbPapel.getText().toString());
if (cbPlastico.isChecked())
Listcheck.add(cbPlastico.getText().toString());
if (cbMetal.isChecked())
Listcheck.add(cbMetal.getText().toString());
if (cbVidro.isChecked())
Listcheck.add(cbVidro.getText().toString());
cbSelecionado = (Listcheck.toString());
return Listcheck.isEmpty() ? "Message goes here" : "";
}
Then wherever calls it can check to see if the return is an empty string or the message. If you just want to show the user a message you could do this:
public void verificaCheckBox(){
Listcheck.clear();
if (cbPapel.isChecked())
Listcheck.add(cbPapel.getText().toString());
if (cbPlastico.isChecked())
Listcheck.add(cbPlastico.getText().toString());
if (cbMetal.isChecked())
Listcheck.add(cbMetal.getText().toString());
if (cbVidro.isChecked())
Listcheck.add(cbVidro.getText().toString());
cbSelecionado = (Listcheck.toString());
if(Listcheck.isEmpty()) {
Toast.makeText(applicationContext, "Your message", Toast.LENGTH_SHORT).show();
}
}
Try using an Alert Dialog to accomplish that.
I believe that the following link gives more relevant details on how to do so:
How to add message box with ok button
To put it for you in simpler steps:
Add an else-statement at the end of your code.
Use the Alert Dialog to notify the user of the changes needed to be done.
I am not sure that I have understood your question, but if you want to send message to the user you can use a Toast
For example:
if (Listcheck.size() == 0)
Toast.makeText(this, "select at least one checkbox", Toast.LENGTH_SHORT).show();

Handling positions in FirebaseRecyclerAdapter

I have fiddled with the FirebaseRecyclerAdapter for quite some time now. It's really a great tool to populate a custom list/recycler view very fast with all of its features. However, one thing that I would like to ask is how to handle positions of items inside the adapter itself.
So for example, I want to mimic this small feature that WhatsApp has in their chats.
So, in a group chat setting, if a person sends more than one consecutive message in a row, the display name of that particular person will be invisible.
The logic behind it according to my understanding: if the person who sends the message is the same for (position - 1), then I will just make the EditText invisible for (position). This is, of course, to prevent a very long stream of text with minimum amounts of repetitive information.
Let's say the JSON tree from Firebase database is as follows.
{
"messages" : {
"pushed_id_1" : {
"message_sender" : "AppleJuice",
"message_text" : "Are you free?"
},
"pushed_id_2" : {
"message_sender" : "AppleJuice",
"message_text" : "On Saturday I mean..."
}
}
}
The FirebaseRecyclerAdapter would look like this.
FirebaseRecyclerAdapter<Message, MessageViewHolder> adapter = new FirebaseRecyclerAdapter<Message, MessageViewHolder>(Message.class, R.layout.message_item, MessageViewHolder.class, myRef) {
#Override
protected void populateViewHolder(MyBookingsViewHolder viewHolder, Booking model, int position) {
viewHolder.messageSender.setText(model.getMessage_sender());
viewHolder.messageText.setText(model.getMessage_text());
//put some code here to implement the feature that we need
}
};
messages_recycler_menu.setAdapter(adapter);
The furthest I have gone is to use getItemCount() method in the FirebaseRecyclerAdapter, but I am still unable to achieve the feature that mimics that of Whatsapp's that I was talking about previously.
Is there a method that can achieve this? Or am I missing something very important in this example?
String lastSender=null; //or some random string
FirebaseRecyclerAdapter<Message, MessageViewHolder> adapter =
new FirebaseRecyclerAdapter<Message, MessageViewHolder>
(Message.class, R.layout.message_item, MessageViewHolder.class, myRef) {
#Override
protected void populateViewHolder(MyBookingsViewHolder viewHolder, Booking model, int position) {
if (model.getMessage_sender().equals(lastSender){ //check if the current sender is same as the last sender
viewHolder.messageText.setText(model.getMessage_text()); //setting only message text
viewHolder.messageSender.setVisibility(View.GONE); //if required
}else{
lastSender=model.getMessage_sender();//updating the lastSender value
viewHolder.messageSender.setVisibility(View.VISIBLE); //if required
viewHolder.messageSender.setText(model.getMessage_sender());
viewHolder.messageText.setText(model.getMessage_text());
}
//put some code here to implement the feature that we need
}
};
messages_recycler_menu.setAdapter(adapter);
As discussed in comments:
Let's suppose I received message and stored sender's name in constant String that should be static constant in some class i.e. AppConstants so that It can be accessed everywhere therefore after that:
in populateViewHolder or in your message receiver do something like this:
if (TextUtils.isEqual(storedSender,model.getMessage_sender())){
viewHolder.messageSender.setVisiblity(View.GONE)
}
else{
// do your normal flow
viewHolder.messageSender.setVisiblity(View.VISIBLE);
storedSender = model.getMessage_sender();
}
In this way automatically the last message's sender's name will be updated , this is exactly what you were trying to achieve by adapter position!

Display text in Android

I know that System.out.println() does not work on Android.
So I need another way to print out some text.
Please help me.
I'm using the Root Tools library
class superuser {
public static Command c ;{
if (RootTools.isRootAvailable()) {
System.out.print("Root found!!");
}
else{ System.out.print(("NO ROOT!"));
}
}
}
Outputing text in android
There are many ways, but usually for testing and debugging processes we use log. The log is not visible to user but you can see it in DDMS.
From what i understand you want to create a dialog or display a textview to users so they know if root is available or not.
1.Logging(for testing and debugging processes)
we defined TAG in below code because it would be easy to make changes later and our code is more organised
private static final String TAG = MyActivity.class.getName();
Log.v(TAG , "here is the line i want to output in logcat");
here v in log.v stands for verbose.You may use i for info, e for error etc.
2.Displaying text to user via a TextView
First lets import the textview. Let the id of the textview you imported may be "resultTextView"
TextView resultText = (TextView) findViewById(R.id.resultTextView);
now applying your logic and setting its text...
if (RootTools.isRootAvailable()) {
resultText.setText("Root found!!");
}
else{ resultText.setText(("NO ROOT!"));
}
3.Creating a dialog
Dialogs are the pop out messages we get.
I would recommend creating a function that takes String message and a String Title as a parameter and creates a dialog using dialog.builder something like this rather than a dialog fragment(which is available in the below link) - http://developer.android.com/reference/android/app/AlertDialog.Builder.html
public void alertDialog(String message,String title){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
this);
// set title
alertDialogBuilder.setTitle(title);
// set dialog message
alertDialogBuilder
.setMessage(message)
.setPositiveButton("OK", null) //we write null cause we don't want
//to perform any action after ok is clicked, we just want the message to disappear
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
// show it
alertDialog.show();
}
Now you can call the method with title and text you want :)
if(condition){
Log.d("message","The root found");
}
else{
Log.d("message","The root not found");
}
Have you tried using logcat ? http://developer.android.com/reference/android/util/Log.html
use it like so: Log.v("myAwesomeApp", "my developer comment");
then use the log panel in your IDE to read it
Using logcat is the usual way in Android, and the simplest.
Log.d("message_id","message content");
If you want another way to display log, you can try
https://github.com/orhanobut/logger

Android: Logout system and the android lifecycle

on the weekend I started to build my first android app. As I need to ask the user of my app for user credentials [which are used for further webservice usage] I want to simulate a "login system". On the start of my app the user should be told to enter his credentials. When the user is inactive for too long I want to dismiss the entered credentials and to "log out" the user.
While coding and afterwards while testing I realized that the way I thought I could go doesn't work. After reading the docu and several SO-questions again and again I question myself more and more if I have understand the app / activity life cycle and its possibilites fully. So I wanted to ask for help in understand the life cycle and its linked influences on my app. So yes this might be several questions in one :/
For the moment my app consists of the following activities:
a search activity (which is opened once the app is started)
a settings acitivy (which can be accessed from the search dialog and has a link back to the search dialog)
After the user has entered an ID in the search dialog I want to open an activity regarding to the search result (NYI).
When starting to implement the user auth, my idea was the following:
Everytime onResume() of an activity is called I need to check a) if user credentials are already stored and b) if the last action of the user is less then X minutes ago. If one these fails I want to show a "log in panel" where the user can enter his credentials, which are then stored in the SharedPreferences. For that I did the following:
I first build an parent activity which has the check and a reference for the SharedPreferences in it
public class AppFragmentActivity extends FragmentActivity {
protected SharedPreferences sharedPref;
protected SharedPreferences.Editor editor;
protected String WebServiceUsername;
protected String WebServicePassword;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_appfragmentactivity);
}
#Override
protected void onResume () {
super.onResume();
// Check if user is "logged in".
// Meaning: Are there given user credentials and are they valid of was the user inactive for too long?
// We only do this "onResume" because this callback is the only one, which is called everytime an user
// starts/restarts/resumes an application
checkForUserCredentials();
// Set new "last action" now "now"
setLastAction(new Date().getTime());
}
#Override
protected void onStart () {
// Fill content
super.onStart();
// Set global sharedPreferences
sharedPref = this.getSharedPreferences(getString(R.string.FILE_settings_file), Context.MODE_PRIVATE);
}
/*
* Checks if user credentials are valid meaning if they are set and not too old
*/
private void checkForUserCredentials() {
long TimeLastAction = sharedPref.getLong(getString(R.string.SETTINGS_USER_LAST_ACTION), 0);
long TimeNow = new Date().getTime();
// Ask for User credentials when last action is too long ago
if(TimeLastAction < (TimeNow - 1800)) {
// Inactive for too long
// Set back credentials
setUsernameAndPassword("", "");
}
else
{
WebServiceUsername = sharedPref.getString(getString(R.string.SETTINGS_USER_USERNAME), "");
WebServicePassword = sharedPref.getString(getString(R.string.SETTINGS_USER_PASSWORD), "");
}
}
/*
* Saves the given last action in the sharedPreferences
* #param long LastAction - Time of the last action
*/
private void setLastAction(long LastAction) {
editor = sharedPref.edit();
editor.putLong(getString(R.string.SETTINGS_USER_LAST_ACTION), LastAction);
editor.commit();
}
/*
* Saves the given username and userpassword sharedPreferences
* #param String username
* #param String password
*/
private void setUsernameAndPassword(String username, String password) {
editor = sharedPref.edit();
editor.putString(getString(R.string.SETTINGS_USER_USERNAME), username);
editor.putString(getString(R.string.SETTINGS_USER_PASSWORD), password);
editor.commit();
WebServiceUsername = username;
WebServicePassword = password;
}
/*
* Method called when pressing the OK-Button
*/
public void ClickBtnOK(View view) {
// Save User-Creentials
EditText dfsUsername = (EditText) findViewById(R.id.dfsUsername);
String lvsUsername = dfsUsername.getText().toString();
EditText dfsPassword = (EditText) findViewById(R.id.dfsPassword);
String lvsPassword = dfsPassword.getText().toString();
if(lvsUsername.equals("") || lvsPassword.equals("")) {
TextView txtError = (TextView) findViewById(R.id.txtError);
txtError.setText(getString(R.string.ERR_Name_or_Password_empty));
}
else
{
// Save credentials
setUsernameAndPassword(lvsUsername, lvsPassword);
setLastAction(new Date().getTime());
// open Searchactivity
Intent intent = new Intent(this, SearchActivity.class);
startActivity(intent);
}
}
The "log in mask" is setContentView(R.layout.activity_appfragmentactivity);.
The two other activites I created are then extending this parent class. This is one of it:
public class SearchActivity extends AppFragmentActivity {
SearchFragment searchfragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
}
#Override
protected void onResume() {
super.onResume();
if(WebServiceUsername.equals("") && WebServicePassword.equals("")) {
// Username not set. Re"login".
Intent intent = new Intent(this, AppFragmentActivity.class);
startActivity(intent);
}
}
#Override
protected void onStart() {
super.onStart();
}
// ...
}
As far as I understand the lifecycle now this should work as the following: When my app starts (the SearchActivity is set for LAUNCH) the app should step into the onResume() of my parent class. There it sees that the credentials are not yet stored and opens the layout of the AppFragmentActivity which is the login. When entered, the user is redirected to the SearchActivity which now sees "ok credentials are there, lets move forward". But this doesnt't happen as the login is not shown up. So I think my onResume() might be wrong. Perhaps my full idea is bad? Up to here I thought I also understand the life cycle, but obviosly I don't?
I then had a look around on SO for similar problems. One thing I saw here was a comment to an user which wanted to build a similar "logout" mechanism as mine, that he has to implement this in every activity. I thought about that and ask myself "Why do I have to override the onResume() in every of my activites, when they are all from the same parent? When theres no onResume() in the child, the one of the parent should be called". The user in the SO-question was advised to use services as background threads to count down a timer in there for the logout. I then read the services article in the docu and then fully got disoriented:
There are two types of services: Started and bounded ones. A started service is once started by an activity and then runs in the background until hell freezes when it doesn't get stoped. So it's fully independed of any app, but the programmer has to / should stop it when it's not longer needed. A bounded services is bounded to one or many app components and stops when all bounded components end. I thought this might be a good alternative for me, but when I thought further I ask myself how: If one of my starts it (let's say the login dialog) and then is closed the service is stoped and the other activites always start there own ones which can't be the sense of it. So this service must be bounded not to any component but to my app. But whats the life cycle of an android app? How can I keep information "global" inside my app. I know I can switch data between actitivites using 'Intents'.
This more and more "foggy cloud" lead to ask myself: "Shall I use only one activity and try to switch in/out everything using fragments?"
So my questions are (I think that's all of them, but I'm not sure anymore):
Does my idea of writing an parent class which does the checks for all extended childs ok or bad AND does it work as I understood it?
Do I have to override every onResume() in the childs just to call the parent one for the checks?
Can you give me a tip why my "login systems" doesn't work?
What's the life cycle of an android app and how can I interact with it?
Shall I only use one activity and switch in/out everything using fragments or is it a good way to have several activities and some of them use fragments (to reuse often used parts)?
Thanks in advise
What I've done in the end is the following:
I removed the "login" thing from the parent class into a stand alone activity. This activity is called when the credentials are not valid together with an finish() of the calling one. So I don't build a loop and drop unused activites.

Won't load values from SharedPreferences - when using them in a calculation, they appear to be blank

when testing an activity in my app I see that it's not using the values I've set using the PreferenceActivity.
I can confirm that the values are corretly set in the PrefsActivity (at least "locally"), because every time I open it, the settings are exactly like they were when I closed it the last time...
Do I have to specify in my PreferenceActivity which preference file to store the settings into, or is it a problem with the methods I'm using to import those values for use in my activity?
It feels like I've searched all over the web without ever finding a clear answer to that question...
This is where my activity is supposed to load the preferences, does it look right?
I know that's the only thing missing, because the calculation works just fine when I run it in debug mode and manually input the values to use...
public void OnStart() {
// Loads the values for the calculator to use
SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
bodymass = settings.getInt(getString(R.string.pref_key_user_mass).toString(), 0);
gender = settings.getString(getString(R.string.pref_key_user_gender).toString(), "");
Also, does this following code look right to you?
(I would also be grateful if someone told me how to make an 'if' statement comparing several variables at once - e.g. if (one out of three fields are empty) {do something})
//Checks defined user gender and sets value to be used by calc accordingly
if (gender == "male") {
genderValue = 0.7;
}
else if (gender == "female") {
genderValue = 0.6;
}
else if (gender == "") {
settingsAlert();
}
It never seems to trigger the settingsAlert()-function, even when all app data is wiped (it should then spawn an alert message, prompting the user to go set the preferences before using, but nothing happens)
Here's the code that's supposed to spawn the alert:
public void settingsAlert() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("#string/dialog_setPrefs_text")
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
Intent gotoSettings = new Intent(ActivityCalc.this, ActivitySettings.class);
startActivity(gotoSettings);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
})
.create();
}
--UPDATE--
I have now managed to get the alert dialog spawn like it should, I figured I'd post the code lines that made it happen, so others with the same problem can watch and learn... :)
The problem appeared to be that the alert was indeed created correctly, but never actually called to display - therefore everything worked perfectly once I added that little .show() after the .create() in the last line.
Alternatively, you can define it as an AlertDialog object, and just call it whenever you feel like it:
AlertDialog alert = builder.create();
alert.show();
I'm posting the contents of my PreferenceActivity class here for you to see
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// This line will import the preferences to display in the settings activity
addPreferencesFromResource(R.xml.settings);
}
To see how to build the preference resource file, look at this article
I've no longer included the string for specifying the name of the shared prefs to use, as I changed the get-method to use DefaultSharedPreferences instead:
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
I have now only defined and initialized the variables required to be persistent for the rest of the activity:
private double genderValue = 0;
private String gender = "";
private int bodymass = 0;
The app now works exactly like it should - not crashing, and correctly loading the preferences as set in the PreferenceActivity.
You need to use equals for the IF-ELSE sentences
if (gender.equals("male")) { //equals
genderValue = 0.7;
}
else if (gender.equalsIgnoreCase("female")) { //Here the equalsIgnorecase one
genderValue = 0.6;
}
else if (gender == "") {
settingsAlert();
} else {
settingsAlert(); //Probably it always comes here.
}
Another thing.. did you saved the preferences correctly with 'commit' ?
settings.edit().putString(getString(R.string.pref_key_user_gender).toString(), gender).commit();
--After 3rd comment---
Never tried. One for each works fine. But if you check 'duanhong169' comment, there're 2 following putString and the last commited, so.. make a try :)
Anyway you can just do:
SharedPreferences.Editor editor = settings.edit();
editor.putString("gender", genderValue);
editor.putInt("bodymass", bodymassValue);
editor.commit();
And answering your other question.. you need the 'edit' to save a prefference, is how it works. you can use it at onpause, onrestart, or just after you've the data you need (inside a method).
Ie if you need a login data, once after you checked the login is correct, and if you've a different login-pass value stored (different user), you can edit.putString to save the new value inside onResult confirmation.
The better thing you can do is try different methods of saving to prefferences with different tags and then creare a Log and do getString() from each tag, so you'll know which one works, and then you can choose the better/easier for your case.
-- UPDATE 2 --
As far as I know.. (i've never tried that, and like you, i'm really new in android) your preferences.xml should be placed at res/xml and then:
public class PreferencesFromXml extends PreferenceActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
}
and to get the data:
PreferenceManager.setDefaultValues(this, R.xml.prefer, false);
SharedPreferences p = PreferenceManager.getDefaultSharedPreferences(this);
p.getString("key", "value_default")

Categories

Resources