After trawling for ages trying to find an understandable solution to my problems i gave up and came here to see if you can help.
My Objective : Update a TextView to count from 1 to 99999 every second without hanging the main thread.
package com.myapp.counter;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myBackgroundThread myThread = new myBackgroundThread();
myThread.execute();
}
private class myBackgroundThread extends AsyncTask<Void,Integer,Void>
{
int maxTimer = 99999;
int i = 0;
//Assign the textView in MainActivity to a variable myCounter.
TextView myCounter = (TextView)findViewById(R.id.idCounter);
#Override
protected void onPreExecute() {
}
#Override
protected Void doInBackground(Void... params) {
// Toast.makeText(getApplicationContext(),"InBackground",Toast.LENGTH_SHORT).show();
//Tried Toasting a message upon this starting but just threw an error
//Guess because i tried to add a UI component in a background task.
for(int i = 0; i < maxTimer; i++)
{
publishProgress(i);
}
return null;
}
//onProgressUpdate is never firing from publishProgress...
protected void onProgressUpdate(Integer i) {
Toast.makeText(getApplicationContext(),i,Toast.LENGTH_SHORT).show();
//Updatet he counter from 000 to 1,2,3,4 etc.
myCounter.setText(i);
}
protected void onPostExecute(Void result)
{
}
}
public void startTimer(View view)
{
TextView myText = (TextView)findViewById(R.id.textView);
// Toast.makeText(this,"Started...", Toast.LENGTH_SHORT).show();
}
public void stopTimer(View view) {
Toast.makeText(this, "Stopped...", Toast.LENGTH_SHORT).show();
}
}
I cannot seem to see why publishProgress does NOT fire from and I wanted to execute the ASyncTask from an button press.
I have 3 elements 2 buttons startTimer and stopTimer and 1 textview to update in the background.
Many thanks all.
Ty something like this :
protected class InitTask extends AsyncTask<Context, Integer, String> {
// -- run intensive processes here
// -- notice that the datatype of the first param in the class definition matches the param passed to this
// method
// -- and that the datatype of the last param in the class definition matches the return type of this method
#Override
protected String doInBackground(Context... params) {
// -- on every iteration
// -- runs a while loop that causes the thread to sleep for 50 milliseconds
// -- publishes the progress - calls the onProgressUpdate handler defined below
// -- and increments the counter variable i by one
int i = 0;
while (i <= 50) {
try {
Thread.sleep(50);
publishProgress(i);
i++;
}
catch (Exception e) {
Log.i("makemachine", e.getMessage());
}
}
return "COMPLETE!";
}
// -- gets called just before thread begins
#Override
protected void onPreExecute() {
Log.i("makemachine", "onPreExecute()");
super.onPreExecute();
}
// -- called from the publish progress
// -- notice that the datatype of the second param gets passed to this method
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.i("makemachine", "onProgressUpdate(): " + String.valueOf(values[0]));
_percentField.setText((values[0] * 2) + "%");
_percentField.setTextSize(values[0]);
}
// -- called if the cancel button is pressed
#Override
protected void onCancelled() {
super.onCancelled();
Log.i("makemachine", "onCancelled()");
_percentField.setText("Cancelled!");
_percentField.setTextColor(0xFFFF0000);
}
// -- called as soon as doInBackground method completes
// -- notice that the third param gets passed to this method
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
Log.i("makemachine", "onPostExecute(): " + result);
_percentField.setText(result);
_percentField.setTextColor(0xFF69adea);
_cancelButton.setVisibility(View.INVISIBLE);
}
}
}
Please help, I can find the distance of one beacon but I can't populate a listview with other beacons in the region. I've tested the listview by just using a string array, populates fine. Everything else works but I'm at a total loss for this last part, close to the edge here...
Here's my code for the main activity`import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.widget.*;
import org.altbeacon.beacon.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
public class MainActivity extends Activity implements BeaconConsumer{
private BeaconManager beaconManager;
int distance;
Identifier minorID;
double distanceLong;
private Handler mHandler;
private int i;
public TextView distanceText;
public TextView distanceName1;
public ImageView distanceImage;
public String name1;
public boolean exitRegion = false;
public String minorString;
List<String> beaconList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
name1 = intent.getStringExtra("beacon1");
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
beaconManager.bind(this);
distanceText = (TextView) findViewById(R.id.distanceText);
distanceText.setText("No beacons found yet, please wait");
distanceName1 = (TextView) findViewById(R.id.name1);
distanceName1.getText();
distanceName1.setText("How far away is "+name1+"?");
distanceText = (TextView) findViewById(R.id.distanceText);
distanceText.getText();
distanceText.setText("Distance: " + distance+ " metres");
distanceImage = (ImageView) findViewById(R.id.distanceImage);
//alertDialogue();
i = 0;
mHandler = new Handler() {
#Override
public void close() {
}
#Override
public void flush() {
}
#Override
public void publish(LogRecord record) {
}
};
beaconList = new ArrayList<String>();
ListAdapter beaconAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, beaconList);
ListView beaconListView = (ListView) findViewById(R.id.beaconListView);
beaconListView.setAdapter(beaconAdapter);
distanceText.post(mUpdate);
distanceImage.post(mUpdate);
}
private Runnable mUpdate = new Runnable() {
public void run() {
distanceText.setText("Distance: " + distance+ " ms");
imageDistance(distance);
alertDialogue(distance);
i++;
distanceText.postDelayed(this, 10000);
}
};
#Override
protected void onDestroy() {
super.onDestroy();
beaconManager.unbind(this);
}
#Override
public void onBeaconServiceConnect() {
final Region region = new Region("myBeacons", Identifier.parse("B9407F30-F5F8-466E-AFF9-25556B57FE6D"), null, null);
beaconManager.setMonitorNotifier(new MonitorNotifier() {
#Override
public void didEnterRegion(Region region) {
try {
Log.d(TAG, "didEnterRegion");
exitRegion=false;
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didExitRegion(Region region) {
try {
Log.d(TAG, "didExitRegion");
exitRegion = true;
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
});
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for(Beacon oneBeacon : beacons) {
distanceLong = oneBeacon.getDistance();
distance = (int) distanceLong;
minorID = oneBeacon.getId3();
minorString = minorID.toString();
String distanceString = String.valueOf("Distance of " + minorID +" beacon: "+ (int) distanceLong+ " metres");
beaconList.add(distanceString);
Beacon.setHardwareEqualityEnforced(true);
}
}
});
try {
beaconManager.startMonitoringBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
`
My layout code is here, as I said the UI mostly works already but maybe I've missed something with the listview...
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="${relativePackage}.${activityClass}">
<TextView
android:layout_width="wrap_content"
android:layout_height="60dp"
android:textColor="#color/material_blue_grey_800"
android:textSize="25sp"
android:id="#+id/name1"
android:layout_gravity="center_horizontal"
android:layout_margin="10dp"
/>
<TextView android:layout_width="wrap_content"
android:layout_height="60dp"
android:id="#+id/distanceText"
android:textColor="#color/material_blue_grey_800"
android:textSize="25sp"
android:layout_margin="10dp"
android:layout_gravity="center_horizontal"
android:layout_below="#+id/name1"
/>
<ImageView android:layout_width="150dp"
android:layout_height="150dp"
android:id="#+id/distanceImage"
android:layout_margin="10dp"
android:layout_below="#+id/distanceText"
android:layout_gravity="center_horizontal"
/>
<ListView android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/beaconListView"
android:textColor="#color/material_blue_grey_800"
android:textSize="25sp"
></ListView>
</LinearLayout></ScrollView>
A few tips:
You don't need the separate beaconList, only the beaconAdapter. But you do need to move the declaration of the beaconAdapter to be a class level variable like this:
...
public String minorString;
private ListAdapter beaconAdapter;
...
Then you can initialize it the same place you do now, just remove the declaration part. You can also remove the reference to beaconList, which is unneeded:
beaconAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
In the didRangeBeaconsInRegion callback, you then update the entries in the beaconAdapter. Like this:
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
beaconAdapter.clear();
for(Beacon oneBeacon : beacons) {
distanceLong = oneBeacon.getDistance();
distance = (int) distanceLong;
minorID = oneBeacon.getId3();
minorString = minorID.toString();
String distanceString = String.valueOf("Distance of " + minorID +" beacon: "+ (int) distanceLong+ " metres");
beaconAdapter.add(distanceString);
Beacon.setHardwareEqualityEnforced(true);
}
beaconAdapter.notifyDataSetChanged()
}
Note that in the code above, notifyDataSetChanged() is called as #niels-masdorp correctly says to do in his answer.
I'm new to Android and I'm trying to display a list of comments with a "load more" button. But somehow my button is not triggered. It seems the listener doesn't do anything...
Here is my code:
public class CommentActivity extends AppCompatActivity {
ListView listComments;
private String FullJson = "";
private static int current_page = 0;
private int offset = 0;
public int getOffset() {
return current_page * 10;
}
private ProgressDialog pDialog = null;
protected String qid = "", udida="";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_comment);
listComments = (ListView) findViewById(R.id.listComments);
//get list of comments on this question
Intent intent = getIntent();
qid = intent.getStringExtra(QuestionActivity.EXTRA_QID);
udida = intent.getStringExtra(QuestionActivity.EXTRA_MESSAGE);
FullJson = intent.getStringExtra(QuestionActivity.EXTRA_JSON);
new HttpAsyncTask().execute("http://heycrowd.com/requests/questionWithComments.json?questionId="+qid+"&offset="+getOffset());
// LoadMore button
Button btnLoadMore = (Button) findViewById(R.id.load_more);;
//Listening to Load More button click event
btnLoadMore.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
// Starting a new async task
new GetIdTask().execute();
}
});
}
public String getIdThread () {
try {
Context ctx = CommentActivity.this.getApplicationContext();
AdvertisingIdClient.Info adInfo = AdvertisingIdClient.getAdvertisingIdInfo(ctx);
final String id = adInfo.getId();
return id;
} catch (GooglePlayServicesRepairableException e) {
return "Error 1";
} catch (IOException e) {
return "Error 2";
// Unrecoverable error connecting to Google Play services (e.g.,
// the old version of the service doesn't support getting AdvertisingId).
} catch (GooglePlayServicesNotAvailableException e) {
return"Error 3";
// Google Play services is not available entirely.
}
}
private class GetIdTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
// Showing progress dialog before sending http request
pDialog = new ProgressDialog(CommentActivity.this);
pDialog.setMessage("Please wait..");
pDialog.setIndeterminate(true);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... urls) {
return getIdThread();
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(String result) {
new HttpAsyncTask().execute("http://heycrowd.com/requests/questionWithComments.json?questionId="+qid+"&offset="+getOffset());
// closing progress dialog
pDialog.dismiss();
}
}
private List<HashMap<String,String>> getListItems(JSONArray FullJson) {
// Each row in the list stores country name, currency and flag
List<HashMap<String,String>> aList = new ArrayList<HashMap<String,String>>();
for(int i=0; i< FullJson.length() ;i++){
HashMap<String, String> hm = new HashMap<String,String>();
try {
hm.put("text", FullJson.getJSONObject(i).getString("text"));
hm.put("date", FullJson.getJSONObject(i).getString("created_at"));
//get user (picture + name)
JSONObject userObj = FullJson.getJSONObject(i).getJSONObject("user");
hm.put("user_id", userObj.getString("user_id"));
hm.put("user_name", userObj.getString("name"));
hm.put("user_img",userObj.getString("image_url"));
}
catch (JSONException e) {
//some exception handler code.
}
aList.add(hm);
}
return aList;
}
private void populateListView(JSONArray FullJson) {
setContentView(R.layout.activity_comment);
List<HashMap<String,String>> aList = getListItems(FullJson);
ListView listCommentView = (ListView) findViewById(R.id.listComments);
int currentPosition = listCommentView.getFirstVisiblePosition();
CommentAdapter adapter =new CommentAdapter(this, aList );
// Setting the adapter to the listView
listCommentView.setAdapter(adapter);
// Setting new scroll position
listCommentView.setSelectionFromTop(currentPosition + 1, 0);
//get logged user's image (at the moment, default image)
ImageLoader imageLoader = new ImageLoader(this.getApplicationContext());
ImageView image=(ImageView)findViewById(R.id.me_img);
image.setImageResource(R.drawable.ic_launcher);
}
private class HttpAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
return Utils.GET(urls[0]);
}
// onPostExecute displays the results of the AsyncTask.
#Override
protected void onPostExecute(final String result) {
try {
JSONObject json = new JSONObject(result);
JSONArray commentsArr = json.getJSONObject("question").getJSONArray("comments"); // get comments array
populateListView(commentsArr);
} catch (JSONException e) {
//some exception handler code.
}
}
}
}
So when I get for the first time on my page, i get the first 10 comments, but when I click on my "load more" button: nothing happens.
I've set a point break on getIdTask() witch is supposed to be called on the click event, and I never get there. I can't seem to find why my button is not reacting to anything.
Also, I thought maybe calling several times an AsyncTask may be the problem, but I tried on the "OnCreate" to get the first 10 lines without an Asynctask, and then nothing worked anymore...
I'm stuck on this since yesterday, pls help!
I'm adding also the layout XML just in case:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="20dp"
android:orientation="vertical"
>
<Button
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="Load more comments"
android:id="#+id/load_more"
android:layout_marginBottom="10dp"
/>
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/listComments"
android:focusable="false"
android:layout_weight="1.0"
android:layout_gravity="center_horizontal" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<ImageView
android:id="#+id/me_img"
android:layout_width="100dp"
android:layout_height="100dp"
android:contentDescription="user"
android:padding="5dp"
/>
<EditText
android:id="#+id/addComment"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:layout_marginRight="20dp"
android:minLines="3"
android:lines="5"
android:gravity="left|top"
android:scrollbars="vertical"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
</LinearLayout>
Thank you
I finally understood why my onclick listener was not working/triggered at all, it took me some time :-(
I have this code inside my populateListView method (first line)
setContentView(R.layout.activity_comment);
I removed it and it made all by listeners work again...
Probably this confused something here, to be honest i don't really understand :-(
I have googled a lot and even gone through many of this website questions but I just can't find the solution to my problem.
I want to create a spinner like the one below. This is just a normal spinner I have done till now. I tried a variety of spinner examples but they don't give me my desired result.
Here is my code:
public class nextclass extends Activity {
Thread t;
ProgressBar dia;
private ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
MainActivity.progressDialog.dismiss();
setContentView(R.layout.nextclassview);
// requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
((Button) findViewById(R.id.button1))
.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
// progressDialog = findViewById(R.id.progressBar1);
new AuthenticateUserTask().execute();
}
});
}
private class AuthenticateUserTask extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
progressDialog = ProgressDialog.show(
nextclass.this, "","Sucessful", true);
/* progressDialog.setIndeterminate(true);
progressDialog.setIndeterminateDrawable(getResources()
.getDrawable(R.layout.customspinner));
*/
progressDialog = ProgressDialog.show(nextclass.this, "",
"Processing....", true);
progressDialog.getWindow().setLayout(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
}
protected void onPostExecute(String s) {
if (progressDialog.isShowing())
progressDialog.dismiss();
Intent my = new Intent(getApplicationContext(), CountTime.class);
startActivity(my);
}
#Override
protected String doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
Thread.sleep(2000);![custom spinner][2]
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
}
I Don't have Seen any Spinner in your Code. but Anyway you can use below code for making Custom Spinner.
Inside your Layout File:
<Spinnerandroid:id="#+id/spinnerview"
android:layout_width="180dp"
android:layout_height="42dp"
android:layout_marginLeft="105dp"
android:layout_marginTop="45dp"
android:background="#drawable/spinner_back"
android:paddingLeft="5dp"
android:spinnerMode="dropdown"android:visibility="visible" />
inside your String.xml :
<string-array name="spinner_array_environtment">
<item>Test</item>
<item>Production</item>
</string-array>
inside you Java File in OnCreate Method:
spinner_environment = (Spinner) findViewById(R.id.spinnerview);
adapter = ArrayAdapter.createFromResource(this,
R.array.spinner_array_environtment, R.layout.spinner);
adapter.setDropDownViewResource(R.layout.spinner);
spinner_environment.setAdapter(adapter);
Make new spinner.xml file to your layout folder :
inside spinner.xml file :
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/spinnerTarget"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="25dp"
android:textColor="#4C4646" />
Thats it!!!
I need a scrollable table with fixed header, so I followed this great blog and everything is fine.
The idea is using one table for header, one table for content added in scrollview, both of them are in a customized LinearLayout. In customized LinearLayout, we will overwrite the onLayout() to get the max width of each row and set width for each row of both header and content table.
Here is the activity and its layout:
package com.stylingandroid.ScrollingTable;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
public class ScrollingTable extends LinearLayout
{
public ScrollingTable( Context context )
{
super( context );
}
public ScrollingTable( Context context, AttributeSet attrs )
{
super( context, attrs );
}
#Override
protected void onLayout( boolean changed, int l, int t, int r, int b )
{
super.onLayout( changed, l, t, r, b );
TableLayout header = (TableLayout) findViewById( R.id.HeaderTable );
TableLayout body = (TableLayout) findViewById( R.id.BodyTable );
if (body.getChildCount() > 0 ) {
TableRow bodyRow = (TableRow) body.getChildAt(0);
TableRow headerRow = (TableRow) header.getChildAt(0);
for ( int cellnum = 0; cellnum < bodyRow.getChildCount(); cellnum++ ){
View bodyCell = bodyRow.getChildAt(cellnum);
View headerCell = headerRow.getChildAt(cellnum);
int bodyWidth = bodyCell.getWidth();
int headerWidth = headerCell.getWidth();
int max = Math.max(bodyWidth, headerWidth);
TableRow.LayoutParams bodyParams = (TableRow.LayoutParams)bodyCell.getLayoutParams();
bodyParams.width = max;
TableRow.LayoutParams headerParams = (TableRow.LayoutParams)headerCell.getLayoutParams();
headerParams.width = max;
}
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.stylingandroid.ScrollingTable.ScrollingTable
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<TableLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="#+id/HeaderTable">
</TableLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:id="#+id/BodyTable">
</TableLayout>
</ScrollView>
</com.stylingandroid.ScrollingTable.ScrollingTable>
</LinearLayout>
Main activity
package com.stylingandroid.ScrollingTable;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
public class ScrollingTableActivity extends Activity
{
private String[][] tableData = {
{"header11111111111", "header2","header3","header4"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1",
"column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"},
{"column1", "column1","column1","column1"}
};
/** Called when the activity is first created. */
#Override
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.main );
TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable);
TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable);
appendRows(tableHeader, tableBody, tableData);
}
private void appendRows(TableLayout tableHeader ,TableLayout tableContent, String[][] amortization) {
int rowSize=amortization.length;
int colSize=(amortization.length > 0)?amortization[0].length:0;
for(int i=0; i<rowSize; i++) {
TableRow row1 = new TableRow(this);
for(int j=0; j<colSize; j++) {
TextView c = new TextView(this);
c.setText(amortization[i][j]);
c.setPadding(3, 3, 3, 3);
if (i == 0) {
c.setTextColor(Color.BLACK);
}
row1.addView(c);
}
if (i == 0) {
row1.setBackgroundColor(Color.LTGRAY);
tableHeader.addView(row1, new TableLayout.LayoutParams());
} else {
tableContent.addView(row1, new TableLayout.LayoutParams());
}
}
}
The above code work perfectly (), however, when I use AnysnTask to get data from server and add data to table later, the onLayout() in my custom view doesn't work anymore. I simulate getting data by log out some number:
public void onCreate( Bundle savedInstanceState )
{
super.onCreate( savedInstanceState );
setContentView( R.layout.main );
new MyTask().execute();
}
private class MyTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(ScrollingTableActivity.this,
"", "Loading. Please wait...", true);
}
#Override
protected Void doInBackground(Void... reportTypes) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable);
TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable);
appendRows(tableHeader, tableBody, tableData);
}
}
So the onLayout() only work when I call appendRows() from main UI thread by putting it in onCreate() method. If I call from another UI thread (in onPostExecute() of AsyncTask), the onLayout() is called (I checked it by create some logs) but it doesn't effect to the GUI. I tried with invalidate(), forceLayout(), requestLayout() but doesn't change anything.
I think we need to call a method to make the GUI refresh but don't know what it is.
You may want to look at this answer:
Android Set textview layout width dynamically
but, basically, try to set the width of each TextView to be the same as the header.
This may require you to do everything twice, as you will probably need to let the system do the layout, so use View.INVISIBLE, then you will need to exit the AsyncTask, calling another one, so the layout work can happen.
Then in the second one, you can then get the invisible tables, loop through to find the largest width in that column, then set all the TextViews in that column to the largest.
This isn't the best solution, but should work.
I think your main problem in the AsyncTask one is that the layout needs to be done, then you can do the fixing.
I finally find out the answer, the setColumnCollapsed() makes the table layout refreshed, however we need to put it in another AsyncTask, otherwise it will not work, strange :( .I put the latest code here, so hope it is helpful for someone. Besides, this is just workaround, so feel free to post your answer if any...
private class MyTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(ScrollingTableActivity.this,
"", "Loading. Please wait...", true);
}
#Override
protected Void doInBackground(Void... reportTypes) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
appendRows(tableHeader, tableBody, tableData);
new My1Task().execute();
}
}
private class My1Task extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... reportTypes) {
return null;
}
#Override
protected void onPostExecute(Void result) {
tableHeader.setColumnCollapsed(0, false);
tableBody.setColumnCollapsed(0, false);
}
}
The answer is that you should declare your TableLayouts outside onCreate() method and instantiate them in onCreate(). Here is the solution. It works well.
public class ScrollingTableActivity extends Activity {
TableLayout tableHeader;
TableLayout tableBody;
private String[][] tableData = {
{ "header11111111111", "header2", "header3", "header4" },
{ "column1", "column1", "column1", "column1" },
{ "column1", "column1", "column1", "column1" },
{ "column1", "column1", "column1", "column1" },
{ "column1", "column1", "column1", "column1" } };
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tableHeader = (TableLayout) findViewById(R.id.HeaderTable);
tableBody = (TableLayout) findViewById(R.id.BodyTable);
Log.d("ScrollingTable", "Before appendRows");
//appendRows(tableHeader, tableBody, tableData);
new MyTask().execute();
}
private void appendRows(TableLayout tableHeader, TableLayout tableContent,
String[][] amortization) {
int rowSize = amortization.length;
int colSize = (amortization.length > 0) ? amortization[0].length : 0;
for (int i = 0; i < rowSize; i++) {
TableRow row1 = new TableRow(this);
for (int j = 0; j < colSize; j++) {
TextView c = new TextView(this);
c.setText(amortization[i][j]);
c.setPadding(3, 3, 3, 3);
if (i == 0) {
c.setTextColor(Color.BLACK);
}
row1.addView(c);
}
if (i == 0) {
row1.setBackgroundColor(Color.LTGRAY);
tableHeader.addView(row1, new TableLayout.LayoutParams());
} else {
tableContent.addView(row1, new TableLayout.LayoutParams());
}
}
}
private class MyTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progressDialog;
protected void onPreExecute() {
progressDialog = ProgressDialog.show(ScrollingTableActivity.this,
"", "Loading. Please wait...", true);
}
#Override
protected Void doInBackground(Void... reportTypes) {
for (int i = 0; i < 500; i++) {
System.out.println(i);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
progressDialog.dismiss();
TableLayout tableHeader = (TableLayout)findViewById(R.id.HeaderTable);
TableLayout tableBody = (TableLayout)findViewById(R.id.BodyTable);
appendRows(tableHeader, tableBody, tableData);
}
}
}