Dynamically Add and Save buttons in Android studio - java

Currently i managed to create the buttons dynamically on a view
Here is the my code to create the buttons;
public void Add_on(View v) {
AlertDialog.Builder mbuilder = new AlertDialog.Builder(Mb.this);
View mview = getLayoutInflater().inflate(R.layout.activity_mb1, null);
EditText number = (EditText) mview.findViewById(R.id.etnum);
Button Create = (Button) mview.findViewById(R.id.etcreate);
Button Cancel = (Button) mview.findViewById(R.id.etcancel);
Create.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view){
if (!number.getText().toString().isEmpty())
{
Toast.makeText(Mb.this, "Number can be NULL",Toast.LENGTH_SHORT).show();
LinearLayout yenilayout = new LinearLayout(Mb.this);
int n =1;
for(int i=0; i<n; i++)
{
Button yeniButton = new Button(Mb.this);
yenilayout.addView(yeniButton);
yeniButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(Mb.this, "Button is working",Toast.LENGTH_SHORT).show();
}
});
}
altlayout.addView(yenilayout);
} else {
Toast.makeText(Mb.this, "Number cannot be NULL",Toast.LENGTH_SHORT).show();
}
}
});
But whenever i recall the activity, the buttons are no longer exist. So May i know can i place the button there permanently?
Thank you for suggestions

You can use Bundle to save an activity's state and recreate it in the onCreate() method. This works for a particular instance of Activity, so can be used to save data concerning selection, or user input etc., but not data that you need to be persistent across application launches.
To use the Bundle, override the onSaveInstanceState(Bundle) and onRestoreInstanceState(Bundle) methods in the Activity class. You can use methods from Bundle to save whatever data you like in a map, and get it back in onRestoreInstanceState(Bundle), which is called in onStart().
The default implementations already handle most UI stuff though, and I would have thought this would keep track of your buttons for you, so it may be that your question is actually about associating some persistent data with your application. (this also means that if you do override the above methods, you should make sure to call the super methods in the first line of your implementation).
If you need persistent data across application launches, then the quickest and easiest way would be to use SharedPreferences, see this answer for an example.

Related

Android: SetText in handler doesn't change text in TextView

I have an app that connects to bluetooth and displays information received.
when pressing back, the activity isn't killed and I can go back to the activity and everything is the same. The activity collects the data in the background and everything is okay
I have a button, that when pressed, kills all activities (including the activity that displays the data).
When I try to create that activity again, the data keeps coming, and I can still handle it and write it to a file, but it won't show it in the UI. It seems the setText function in the handler doesn't work after the activity is created the second time (setText does work outside of the handler).
The boolean value synced is true if the activity is created a second time.
This is OnCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
loading_panel = findViewById(R.id.loadingPanel);
loading_panel.setVisibility(View.GONE);
connectionButton = (Button) findViewById(R.id.connection_button);
gsrTextView = (TextView) findViewById(R.id.gsr_textview);
emgTextView = (TextView) findViewById(R.id.emg_textview);
adxlTextView = (TextView) findViewById(R.id.adxl_textview);
fsrTextView = (TextView) findViewById(R.id.fsr_textview);
textviews_set=true;
if(synced)
{
setConnected(currMac);
manageConnection();
Button sync_button = (Button) findViewById(R.id.sync_button);
sync_button.setText(R.string.synced_text);
}
// more code
}
Implementation of OnBackPressed:
#Override
public void onBackPressed() {
Intent i = new Intent(AdminActivity.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);
}
This is (part of) the handler:
#SuppressLint("HandlerLeak")
public final Handler handler = new Handler() {
#Override
public void handleMessage(#NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//a lot of code for other cases
case READ_SUCCESS:
String s = (String) msg.obj;
showData(s);
break;
}
}
}
This is (part of) showData:
private void showData(String s) {
// todo: 1.parse the json; 2.show data (json components) on the textViews
try {
//Log.d(LOG_TAG, "the new string is " + s);
JSONObject json = new JSONObject(s);
// Collect the sensors measurements
String gsrMeasure = json.getString("gsr");
String emgMeasure = json.getString("emg");
String adxlMeasure = json.getString("adxl");
String fsrMeasure = json.getString("fsr");
String time_str = json.getString("time");
// Show the data
if(textviews_set) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(LOG_TAG, "ABOUT TO SET TEXT");
gsrTextView.setText(gsrMeasure);
emgTextView.setText(emgMeasure);
adxlTextView.setText(adxlMeasure);
fsrTextView.setText(fsrMeasure);
}
});
}
//more code
}
}
I even made sure that I'm running the setText on UI thread even though it works on the first run of the activity without the runOnUiThread
I also thought that maybe the handler is called before the findViewByIDs are called but I used a boolean variable textviews_set to make sure it doesn't happen
It is worth mentioning that when I create the activity for the first time, the bluetooth device isn't connected and thus the handler isn't running, so there's a really good chance that the problem lies there. I just don't know exactly where, or how to solve it.
I found out what the problem was, if anyone gets stuck with the same issue.
I declared all the textviews as non-static, thus when creating the activity the second time, for some reason the handler still referred to the textviews of the first instance of the activity.
All I had to do was declare the textviews in the class as static, so when I create the activity for the second time, the textviews are already declared and refer to the actual textviews in the xml.
Based on the information provide the follow is the best suggestion.
So try the following in onCreate() before textviews_set=true;
gsrTextView.setText(" ");
emgTextView.setText(" ");
adxlTextView.setText(" ");
fsrTextView.setText(" ");
Hope this solves issue.
Reference:
How do I declare a TextView variable so that I can use it anywhere?

onSave- / onRestoreInstanceState not working

The situation is that I want to create an app, which should be able to create a new TextView in a LinearLayout everytime a button is clicked. A text from and EditText ist assigned to said TextView. I managed to pull this off. However I've been struggling on how to save all of the created TextViews, once the app is closed and started up again. I tried using OnSaveInstanceState and OnRestoreInstance state to save an Array, to which I save every text that is displayed on a TextView. After restored I would check the size of the arraylist and create for a TextView for every value in the arraylist, so that all is restored. However, it doesn't work. I know, that the names are saved to the arraylist, however, nothing is restored, when I restart the app. Here's my Code:
public class MainActivity extends AppCompatActivity{
private ArrayList<String> SubjectArray = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button savebtn = findViewById(R.id.MAINsave);
EditText newname = findViewById(R.id.newname);
CheckBox promo = findViewById(R.id.MAINpromo);
LinearLayout linearlayout = findViewById(R.id.MAINln);
savebtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
newsub();
}
});
}
private void newsub(){
EditText newname = findViewById(R.id.newname);
CheckBox promo = findViewById(R.id.MAINpromo);
LinearLayout MAINln = findViewById(R.id.MAINln);
SubjectArray.add(newname.getText().toString());
Toast.makeText(MainActivity.this, "Added To Array", Toast.LENGTH_SHORT).show();
RelativeLayout.LayoutParams Params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 200);
Params.setMargins(0, 10, 0, 10);
TextView newsubject = new TextView(MainActivity.this);
newsubject.setText(newname.getText().toString());
newsubject.setGravity(View.TEXT_ALIGNMENT_CENTER);
newsubject.setBackgroundColor(GRAY);
newsubject.setLayoutParams(Params);
MAINln.addView(newsubject);
}
#Override
protected void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
SubjectArray = savedInstanceState.getStringArrayList("KEY_SUBJECTARRAY");
LinearLayout MAINln = findViewById(R.id.MAINln);
int subjectcount = SubjectArray.size();
for (int i = 0; i <= subjectcount; i++) {
RelativeLayout.LayoutParams Params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 200);
Params.setMargins(0, 10, 0, 10);
TextView restoredsubject = new TextView(MainActivity.this);
restoredsubject.setText(SubjectArray.get(i));
restoredsubject.setGravity(View.TEXT_ALIGNMENT_CENTER);
restoredsubject.setBackgroundColor(GRAY);
restoredsubject.setLayoutParams(Params);
MAINln.addView(restoredsubject);
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putStringArrayList("KEY_SUBJECTARRAY", SubjectArray);
}
}
you can manage a local database table and every time you are adding the new TextView just insert the Text of that TextView in the table . When you start your application first check the data of that table, if available then get the data in a list .
After getting list
Apply a loop on list size
Add a new textview inside body of loop
Set the current indexed text in Added TextView inside the loop.
you can clear table also when you need.
When you say "restart the app" you mean, a fresh start?
The savedInstanceState is not made for this. You save the state for moments when the instance of your Activity gets recreated.
As an example, when the user is turning the phone to landscape formatting. Then a onConfigurationChanged event happens (depends on how you set up your activity in the manifest) and onCreate gets called with the Bundle you saved in onSaveInstanceState.
To persist your state over app sessions, best approach is either saving it in the SharedPreferences (and loading them in onCreate of your MainActivity oder Application class) or to persist them in a database table.
The onRestoreInstanceState not made this purpose. It has a different purpose like, if your activity was previously destroyed and you going to recreate the activity again, at this you could be able to retrieve the saved data. For more details click here.
In this case, recommend using preferences or lightWeight persistence libraries like Room. So you could retrieve the details any point the app until clear the data of the app.

How can I let another class know that a button was clicked (Android Studio)

Below is the code which I'm using to return a number which should be 1 when the button is clicked. However when I try to get that number from another class, it always stays 0.
As you might recognize, I tried to change the number in the onClickListener and returned it below.
I also tried to use the onPause command so that it will return the number onPause but it still doesn't work.
public class MainActivity extends Activity {
public int number;
Button btnAngled;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
btnAngled = (Button) findViewById(R.id.btnAngled);
final Intent intent = new Intent(this, angledForeheadActivity.class);
btnAngled.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
number = 1;
startActivity(intent);
}
});
}
#Override
protected void onPause() {
super.onPause();
}
public int getNumber() {
return number;
}
}
I try to get the code in another class with:
MainActivity a = new MainActivity();
int number = a.getNumber();
Sorry for the noob question..
declare the variable as static variable. Then you can simply obtain the result you want since there is only one copy of that variable. If you want to pass the value using intent, you can call putExtra() of intent to carry information to another activity.
Intent reference page
What you actually want is getting the number from another Class. Don't mix the job with button click together. You should setup the concept of model to store data and seperate UI and data, UI just change/get the data.
I suggest you either of the two ways
Store the number in some global model, then you can get the number from another Class.
User Android Broadcast to transfer the data
Use static variable in Activity is not a good idea, it may cause memroy leak, though it can solve your problem.

How can I create multiple screen views in eclipse?

I'm using Eclipse for windows 7 and I am making an informative application(just text and offline content).
In my app I have about 180 buttons. Each button will lead to another screen. I need to know how to make each button lead to a specific screen?
And also, is there a way to like duplicate the code and not spend hours copying and pasting the code 180 times?
Check my code below for the first two screens:
That's for the MainActivity.java:
public void addListenerOnButton() {
final Context context = this;
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(context, MainActivity2.class);
startActivity(intent);
}
});
}
I mean that code is only for one single button. Am I supposed to repeat this for every single button?
and also a question, how many classes should I do? 180 main activities, 180 fragment_main.xml and 180 activity_main.xml?
That's my idea, since your application is just a "informative application" you can create two activities:
Main activity with buttons
"Information page"
To do it i need info about how you get this informations:
In a SQLite Database.
In a string-array
Personally, i prefer a SQLite DB it allows you to improve it without problems in the future.
About the Information activity:
Example: in your layout you have a TextView where will be added the text which this activity should be passed.
To make it dynamic in your case we pass the string to show using Intents, in our onCreate we add something like this:
Intent intent = getIntents();
String stringToDisplay = null;
if (intent != null)
{
stringToDisplay = intent.getStringExtra (EXTRA_STRING_CONTENT);
}
getIntents will get the Intent object which is created and passed to it by our main activity. getStringExtra is a simple method which says to Android: i want to get the string which is saved with the key EXTRA_STRING_CONTENT (it's something like a Map)
EXTRA_STRING_CONTENT is a field which we used to make sure we don't make any error in passing data, since we need to use the same name when we pass it (in MainActivity) and when we read it (InformationActivity)
public static final String EXTRA_STRING_CONTENT = "EXTRA_STRING_CONTENT";
Ok, we are done.
We now only need to set the string to our TextView:
TextView infoTextView = (TextView) findViewById(R.id.infotextview);
infoTextView.setText (stringToDisplay);
Stop it.
Now we should go to our MainActivity code and modify our addListenerOnButton
final Context context = this;
button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(context, MainActivity2.class);
startActivity(intent);
}
});
Well, i will focus on this two lines
Intent intent = new Intent(context, MainActivity2.class);
startActivity(intent);
We need to pass the string to display here, how?
Before we used getStringExtra now it's similar (note: it's the same Intent class) but now we need the putExtra method, the compiler will select the correct overload for us so we just need to do
String stringToDisplay = "Hello world";
intent.putExtra(InformativeActivity.EXTRA_STRING_CONTENT, stringToDisplay);
(Note: InformativeActivity.EXTRA_STRING_CONTENT)
With the current code we will always sent Hello world to the second activity but we need something of dynamic based on the button... well now this depends on how you get the data.
If it's a string-array, you can save the string-array in an array and then based on the button (if it's the first sent string index 0, etc.).
An example:
int buttonId = 1; // it will be a general variable, if it's button 1 it will be 0, if 2-1 etc.
String[] informations = getResources().getStringArray(R.array.infos); // in a real code you should move it outside the `onClick` code and put it in a static final field.
intent.putExtra(InformativeActivity.EXTRA_STRING_CONTENT, informations[buttonId]); // it's the same of above
If you understand the concept you will know how to adapt the code based on your needs.
There are some cases where you need more info or what you want to sent is something which is better if managed by the second activity (example: in a sqlite database you could sent only the id of the line and read lines in the second activity based on this id)
Some things which you could change:
Avoid to call it MainActivity2, it's not so helpful as name
You don't need really to save Context, you could just use MainActivity.this
Try to make your addListenerOnButton more general, example take as argument a Button and set the listener to it.. don't read it from XML you will end up with 180 methods for every button.

How to dynamically add rows from a table (sqlite) to layout? (Android)

I am trying to take all the rows from my db and add it to the current layout, also, making each row clickable in the layout to take the user to a new screen with the id...
Here is my current code, but stuck on that part... I understand that I can put an onClickListener, but then does it have to be a button?
For a visual representation refer to a notepad app on any device where each note title appears and clicking on it takes you to that note.
public class MainActivity extends Activity implements OnClickListener {
private Button add_new_dictionary;
// Database helper
private DatabaseHelper db;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// db setup
db = new DatabaseHelper(getApplicationContext());
// get all dictionaries
List<db_dictionary> allDictionaries = db.getAllDictioniaries();
for (db_dictionary dictionary_found : allDictionaries) {
// create new view for each dictionary name include id and make it
// dynamic and include onclick to take to dictionary_view screen
Button dictionary_button = new Button(this);
}
add_new_dictionary = (Button) findViewById(R.id.add_new_dictionary);
}
#Override
public void onClick(View v) {
if (v == add_new_dictionary) {
Intent add_new_dictionary_intent = new Intent(MainActivity.this,
add_new_dictionary.class);
startActivity(add_new_dictionary_intent);
}
}
}
To re-iterate the question: How do I go about dynamically taking rows from my db and adding it to my layout dynamically based on how many results are returned from the query? (However, the rows should be able to point to a new screen with the dictionary id)
All views in android can implement the OnClickListener interface. So no, it doesn't HAVE to be a button.
As you've decided to use the activity to handle this then you need to tell your code to pass the event to your implementation wihin your activity.
// create new view for each dictionary name include id and make it
// dynamic and include onclick to take to dictionary_view screen
Button dictionary_button = new Button(this);
dictionary_button.setOnClickListener(this);
A trick I use to store information is the setTag method which would allow you to retrieve the correct reference during your onClick:
dictionary_button.setTag(some_record_id);
Then retrieve it later:
#Override
public void onClick(View v) {
if (v == add_new_dictionary) {
Intent add_new_dictionary_intent = new Intent(MainActivity.this,
add_new_dictionary.class);
startActivity(add_new_dictionary_intent);
}
else (
Object tag = v.getTag();
//now launch the detail activity using the data from the tag
}
}
You should really look into ListAdapters and cursors to do this properly, but this method should get you going for now
If you need to pick data from a db and show it as a list (getting click events) you should probably look into CursorAdapter and ListView
http://developer.android.com/reference/android/widget/CursorAdapter.html
http://developer.android.com/reference/android/widget/ListView.html
You can fins many examples on the web on how to use a cursoradapter and the listview

Categories