How to add the TextView to the layout programmatically? - java

I'm trying to make messages like in messenger. They must appear one after another. So I use the LinearLayout and add the TextView to it. But the appear all at once. I use the loop, but it looks like it doesn't work!
Here is the code
final LinearLayout lm = (LinearLayout) findViewById(R.id.line_layout);
final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(10, 10, 500, 50);
int i = 0;
for (final Task task : tasks) {
i = i + 1;
for (int j = 0; j < 1; j++) {
final TextView message = new TextView(TaskActivity.this);
message.setText(task.getName());
message.setId(task.getId());
message.setLayoutParams(params);
message.setTextSize(30);
message.setBackground(getApplicationContext().getDrawable(R.drawable.task_text));
Toast.makeText(TaskActivity.this, "Text loaded",
Toast.LENGTH_SHORT).show();
lm.addView(message);
SystemClock.sleep(1000);
}
}
The TextViews appear at once no matter the timer. The app waits while the Timer for every circle of the loop and returns the hole messengers at once!
See the screenshot of the app:
So how would you do this task and resolve the problem? Thank you!

If you want the behaviour as in Messenger , you should use RecyclerView in android.
https://developer.android.com/guide/topics/ui/layout/recyclerview
With the time interval to add a new message, you can use recyclerview notify methods to show the new messages.

define a layout in which you need to add your textView and then do the following
LayoutParams lparams = new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
TextView tv=new TextView(this);
tv.setLayoutParams(lparams);
tv.setText("test");
this.parentLayout.addView(tv);

Your code is running on the uiThread so the UI doesn't update until the loop is complete. Have a look at using an AsyncTask to pause the app in the background and do the update after finishing. Try something like this:
public class TestActivity extends Activity
{
Queue<String> messages = new LinkedList<String>();
class PushNextMessage extends AsyncTask<Void, Void, Void>
{
#Override
protected Void doInBackground(Void... params)
{
try
{
Thread.sleep(1000);
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void _void)
{
String message = messages.remove();
//this is where you add the view to the base layout
if (messages.size() > 0)
{
new PushNextMessage().execute();
}
}
}
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
messages.add("message 1");
messages.add("message 2");
messages.add("message 3");
new PushNextMessage().execute();
}
}

Related

How to remove dynamically created imageview from another button onclick?

I have created an ImageView dynamically like below image.It works fine. Now I want to remove view when top cross ImageView is clicked. When I click, it crashes .Please help how to achieve it.
here is what i have done
private void postImage(List<Uri> urilist) {
for(int i=0; i< urilist.size(); i++) {
imgView = new ImageView(getActivity());
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(150, 150);
lp.setMargins(20,10,20,10);
imgView.setLayoutParams(lp);
imgView.setId(i);
Log.d("uri list in loop",""+urilist.get(0));
Glide.with(getActivity())
.load(urilist.get(i))
.into(imgView);
layout.addView(imgView);
imgView1 = new ImageView(getActivity());
LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(50, 50);
lp1.setMargins(0,5,1,80);
imgView1.setLayoutParams(lp1);
imgView1.setId(i);
Log.d("uri list in loop",""+urilist.get(0));
Glide.with(getActivity())
.load(R.drawable.ic_action_cross)
.into(imgView1);
layout.addView(imgView1);
}
imgView1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
layout.removeViewAt(v.getId());
}
});
}
If it is because of the index (which definitely will crash in deletion of the 2nd item) then you can try below
imgView1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ViewGroup parentView = (ViewGroup) v.getParent();
parentView.removeView(v);
}
});
Note: You should not set id of two views as same. Rather use some mathematical formula.
I mean #shakac, you can try like that;
for(int i = 0; i<layout.getChildCount(); i++)
{
if (layout.getChildAt(i).getId() == v.getId()){
layout.removeView(layout.getChildAt(i));
break;
}
}
But as I said on the comment, you will remove the cross button like that.

Check if various checkboxes that have being created programmatically are checked when you click a button in android

My question is:
How I can check if the checkboxes are checked and how can I get its id or text in a onclick event?
I have done it whit RadioGroup, but RadioGroup only let me check 1 RadioButton, and in this case I need to check more than one, but if Im wrong and there is a way to do it with RadioGroup it should work for me.
Thanks for the help
Here is the code where I create the checkboxes programmatically:
protected void onCreate(Bundle savedInstanceState) {
LinearLayout lg = (LinearLayout) findViewById(R.id.lg);
Button botonenv = (Button) findViewById(R.id.botonenv);
try{
myJson = new JSONObject(data);
JSONArray Solutions = myJson.getJSONArray("solutions");
for (int i = 0; i < Solutions.length(); i++) {
JSONObject JSonSol = Solutions.getJSONObject(i);
final String idSt = JSonSol.getString("id");
final String name = JSonSol.getString("name");
String resp = name.toUpperCase();
CheckBox cb1 = new CheckBox(this);
cb1.setText(resp);
LinearLayout.LayoutParams llg = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
llg.setMargins(0, 30, 0, 0);
cb1.setTextSize(15);
cb1.setTextColor(Color.parseColor("#FF000000"));
lg.addView(cb1);
int id =Integer.parseInt(idSt);
cb1.setId(id);
}
}catch(JSONException e){
e.printStackTrace();
}
botonenv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//HERE I MUST NOW WHAT CHECKBOXES ARE CHECKED AND THEIR IDS
..............
}
});
}
Add their references to list , then you can reuse those reference again in any where outside after creation .
like
List<CheckBox> checkBoxes = new ArrayList<>();
add checkbox to your list wherever your create a new one checkBoxes.add(cb1);
inside your onClick you can check all of them .

AsyncTask onPostExecute UI Changes

It is always the little things that stump me for hours.
I have an onPostExecute method from an AsyncTask class that looks like so:
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
showColumnCounts();
dataDownloadCompleteToast();
}
The toast works just fine. However, my showColumnCounts() method refuses to work. It works just fine on the main thread. I use it during onCreate() just not here. I thought the onPostExecute ran on the UI thread?
Here is my showColumnCounts() method if it is relevant.
public void showColumnCounts() {
TextView totalView = (TextView) findViewById(R.id.totalColumn2);
TextView ignoredView = (TextView) findViewById(R.id.ignoredColumn2);
TextView rView = (TextView) findViewById(R.id.rColumn2);
Cursor c = myDB.getEmptyRColumn("");
int count = c.getCount();
if (count == 0) {
c.close();
return;
}
String unread = String.valueOf(count);
String total = getTotalCount();
int tTotal = Integer.parseInt(total);
int r = tTotal - count;
String read = String.valueOf(r);
totalView.setText(total);
ignoredView.setText(unread);
rView.setText(read);
c.close();
}
I've been fiddling with it for a while now assuming the answer should be obvious but I'm calling uncle. Can't figure it.
Edit***** 6/30
I THINK I've found my problem. In my background thread I am using a parse.com method "query.findInBackground" which I assume is starting a third thread? I'm trying to update this to "query.find" and I'm hoping that will fix.
First of all you should move all your TextView declarations inside your onCreate method
if you want to change or perform some UI operation, if you want to perform some non UI based operations while the thread is running then do that in doInBackground() method
You should move …setText(...) lines into
runOnUiThread(new Runnable(){
void run(){
// UI stuff
});
You need to tell where is your async class located and the showColumnCounts() function located.
If they both where in different class then you should create a context to call the function from the async class.
Take this as example and try.
Example:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.main);
new AsyncClass(this);
super.onCreate(savedInstanceState);
}
public void showColumnCounts() {
TextView totalView = (TextView) findViewById(R.id.totalColumn2);
TextView ignoredView = (TextView) findViewById(R.id.ignoredColumn2);
TextView rView = (TextView) findViewById(R.id.rColumn2);
Cursor c = myDB.getEmptyRColumn("");
int count = c.getCount();
if (count == 0) {
c.close();
return;
}
String unread = String.valueOf(count);
String total = getTotalCount();
int tTotal = Integer.parseInt(total);
int r = tTotal - count;
String read = String.valueOf(r);
totalView.setText(total);
ignoredView.setText(unread);
rView.setText(read);
c.close();
}
public class AsyncClass extends AsyncTask<String, Void, Boolean> {
private Activity activity;
public AsyncClass(Activity main_activity) {
this.activity = main_activity;
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
activity.showColumnCounts();
dataDownloadCompleteToast();
}
}
}
If you want to do some UI change process in background running operation(ASYNC TASK),you write that codes in UI thread. Example:
YourActivity.this.runOnUiThread(
new Runnable()
void run()
{
//UI changes
showColumnCounts();
});

Attempt to call a method but I get a NullPointerException

I want to create a connection through socket but I'm having trouble with the graphic of my App:
This is my activity:
public class Messaggi2 extends ActionBarActivity{
LinearLayout mLayout;
ScrollView scroll;
EditText scriviMessaggi;
Button invia;
Socket connessione;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaggi2);
mLayout = (LinearLayout) findViewById(R.id.LinearScrollLayout);
scroll = (ScrollView) findViewById(R.id.scrollView2);
scriviMessaggi = (EditText) findViewById(R.id.Scrivi);
invia = (Button) findViewById(R.id.Invia);
LavoraDietro asd = new LavoraDietro(connessione);
asd.execute();
}
private TextView createNewTextView(String text) {
final LinearLayout.LayoutParams lparams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); final TextView textView = new TextView(this);
textView.setLayoutParams(lparams);
textView.setText(text);
textView.setBackgroundResource(R.drawable.balloon_broadcast_incoming_pressed);
return textView;
}
private TextView createNewTextViewSent(String text) {
final LinearLayout.LayoutParams llparams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
llparams.gravity = Gravity.RIGHT;
final TextView textViewSent = new TextView(this);
textViewSent.setLayoutParams(llparams);
textViewSent.setText(text);
textViewSent.setBackgroundResource(R.drawable.balloon_outgoing_normal);
return textViewSent;
}
public void AggiungiTextALlayout(String messaggio){
mLayout.addView(createNewTextView(messaggio));
aggiornaScroll();
}
public void AggiungiTextInviatoALlayout(String messaggio){
mLayout.addView(createNewTextViewSent(messaggio));
aggiornaScroll();
}
public void aggiornaScroll(){
scroll.post(new Runnable() {
#Override
public void run() {
scroll.fullScroll(View.FOCUS_DOWN);
}
});
}
}
This is my AsynTask class:
public class LavoraDietro extends AsyncTask<Void, Void, Socket> {
Socket connessione;
boolean vediSeDeviPartire;
Messaggi2 mess = new Messaggi2();
public LavoraDietro(Socket connessione){
this.connessione = connessione;
}
#Override
protected Socket doInBackground(Void... params){
try {
InetAddress local = InetAddress.getByName("192.168.1.71");
connessione = new Socket(local , 7000);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return null;
}catch(Exception e){
e.printStackTrace();
}
return connessione;
}
#Override
protected void onPostExecute(Socket result) {
super.onPostExecute(result);
if(result != null){
vediSeDeviPartire = true;
mess.AggiungiTextALlayout("Sono connesso al server");
mess.AggiungiTextALlayout("I canali sono aperi..");
}
else{
mess.AggiungiTextALlayout("ERRORE CONNESSIONE AL SERVER ");
}
}
}
Using this code when I start my app the connection is established and then it crashes. What I see on my Logcat is this Exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
So I tried to delete the content of my onPostExecute and everything works perfect. So the mistake is to try to call the method AggiungiTextAlLayout on my AsyncTask class.
Can someone help me with this? Can someone suggest me something? I'm new in this field so I know that this is a stupid thing but I need help.
Thanks guys in advance
EDITED WITH THE SOLUTION
Thanks to Ataulm I got the problem and I solved it I changed the costructor of my LavoraDietro class (unfortunatly I can't change the name of variables and classes in English. But next time I ll use english Name of course )
LavoraDietro Class
public class LavoraDietro extends AsyncTask<Void, Void, Socket> {
Socket connessione;
boolean vediSeDeviPartire;
Messaggi2 action;
public LavoraDietro(Socket connessione, Messaggi2 action){
this.connessione = connessione;
this.action = action;
}
#Override
protected Socket doInBackground(Void... params){
try {
InetAddress local = InetAddress.getByName("192.168.1.71");
connessione = new Socket(local , 7000);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
return null;
}catch(Exception e){
e.printStackTrace();
}
return connessione;
}
#Override
protected void onPostExecute(Socket result) {
super.onPostExecute(result);
if(result != null){
vediSeDeviPartire = true;
action.AggiungiTextALlayout("Sono connesso al server");
action.AggiungiTextALlayout("I canali sono aperi..");
}
else{
action.AggiungiTextALlayout("ERRORE CONNESSIONE AL SERVER ");
}
}
}
And in the Messaggi2 class I changed the call of the constructor in this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.messaggi2);
mLayout = (LinearLayout) findViewById(R.id.LinearScrollLayout);
scroll = (ScrollView) findViewById(R.id.scrollView2);
scriviMessaggi = (EditText) findViewById(R.id.Scrivi);
invia = (Button) findViewById(R.id.Invia);
LavoraDietro asd = new LavoraDietro(connessione, this);
asd.execute();
Your AsyncTask has a reference to mess which is an object of type Messaggi2.
Messaggi2 is a subclass of Activity. You attempt, inside your AsyncTask, to create a new instance of that class.
The Android system has no awareness of this object; it has called none of the life cycle methods, such as onCreate() where the activity's layout would typically be inflated. This means that none of your views are inflated nor even initialised.
When you call mess.AggiungiTextALlayout("Sono connesso al server");, mLayout is null.
The NPE you see may likely not even be this one.
TL;DR: don't instantiate your Activity objects like Java objects; use them as specified within the Android framework.
I suspect you have this Activity starting correctly somewhere. The mistake is that you've not associated that activity with your Asynctask. When you create LavoraDietro, you pass a reference to the Socket in the constructor; you can also pass a reference to your activity, and assign that to the mess field, instead of calling new Messaggi2(). I'm not advocating this structure. But that is the issue at hand.
A few general tips to help you avoid this in future / or spot it faster:
be consistent with your naming; it's difficult to read your code when you're switching between English and Italian.
it's equally difficult for others to read your code if you don't maintain follow Java conventions with class/method names.
When you're extending Activity, it's typical to append the word "Activity" after your class; in this example new Messaggi2Activity() would have been easier to spot.
Where you're able, pass a Class's dependencies as parameters in the constructor; don't rely on constructing these dependencies yourself inside that class. Once you do this, you can begin to draw lines around what your class is responsible for; the less it's responsible for, the harder it is for your class to mess up.
That problem is for put a variable with no "data", verify your variables

How to repeat textview?

In my Activity I have to add 10 times the same TextView.
Is it possible to load the definition of textview from layout.xml and repeat it programmatically?
for(int i=0;i<10;i++){
Textview text = new TextView(this);
mainlayout.add(text);
}
public class YourClassName extends Activity
{
#Override
public void onCreate(Bundle bundle)
{
super.onCreate(bundle);
// set activity layout
setContentView(R.layout.some_activity_layout);
LinearLayout mainActivityLayout = (LinearLayout)findViewById(R.id.main_layout);
LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// then see previous answer
// loop n times {
TextView yourTextView = _li.inflate(R.layout.text_view_layout, null);
mainActivityLayout.addView(yourTextView);
// } end loop
}
}
You may want to read this article on reusing UI components: http://developer.android.com/resources/articles/layout-tricks-reuse.html

Categories

Resources