Android onLayout() and AsyncTask() does not work together - android

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);
}
}
}

Related

Dynamically update RecycleView from inside an AsyncTask

I have the following code:
protected void onCreate(Bundle savedInstanceState) {
RecyclerView recyclerView;
DeviceAdapter deviceAdapter;
List<Device> deviceList;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Context context = this;
g.IP = cf.getIP(this);
g.subNet = g.IP.substring(0, g.IP.lastIndexOf(".") + 1);
deviceList = new ArrayList<>();
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
for(int i = 1; i < 256; i++) {
if(cf.isUp(g.subNet + i, 80)) {
deviceList.add(new Device(g.subNet + i, "PAUSED", "N/A"));
}
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
deviceAdapter = new DeviceAdapter(context, deviceList);
recyclerView.setAdapter(deviceAdapter);
}
}.execute();
}
Which checks if a host is online, and if their port 80 is open, then at the end of the scan, it adds them all to the RecyclerView.
I was wondering how I could add:
deviceAdapter = new DeviceAdapter(context, deviceList);
recyclerView.setAdapter(deviceAdapter);
to the doInBackground() if statement, like this:
#Override
protected Void doInBackground(Void... params) {
for(int i = 1; i < 256; i++) {
if(cf.isUp(g.subNet + i, 80)) {
deviceList.add(new Device(g.subNet + i, "UP", "OPEN"));
deviceAdapter = new DeviceAdapter(context, deviceList);
recyclerView.setAdapter(deviceAdapter);
}
}
return null;
}
but without it crashing my app, so that the RecyclerView updates straight away when a new item is added to deviceList<>, rather then when the task is finished.
Your app is crashing because only the main thread can handle UI elements such as RecyclerView. So what you need to do is create a listener that will be called whenever your AsyncTask finds a new device.
Example:
public interface OnDeviceFoundListener {
void onDeviceFound(Device device);
}
#Override
protected void doInBackground(Void... params) {
for (int i = 1; i < 256; i++) {
if (cf.isUp(g.subNet + 1, 80)) {
listener.onDeviceFound(new Device(g.subNet + 1, "UP", "OPEN"));
}
}
}
Then, in the Activity or Fragment where the RecyclerView is located, you will implement this listener interface, for example:
public class MyActivity extends AppCompatActivity implements OnDeviceFoundListener {
private List<Device> devices;
#Override
public void onDeviceFound(Device device) {
devices.add(device);
deviceAdapter = new DeviceAdapter(context, devices);
recyclerView.setAdapter(adapter);
recyclerView.getAdapter().notifyDataSetChanged();
}
}
Don't forget to call the notifyDataSetChanged method in your adapter after you add the new device(s) you add.

AsyncTask request data later than I create button depending on these data

This is my first time to write Android code and I am stark with a problem.
In the MainActivity, I use AsyncTask to request "Category" list to create buttons. The MainActivity buttons can be clicked and it redirects to GetProductsActivity with an extras String "Category(e.g.drink)". In the GetProductsActivity, I request server again using "Category" to get "Products" list to create product button.
Here is the problem: the code create button first, then AsyncTask request server to get "Products" list, I want to get the "Products" list before creating the button. What should I do?
"orga.getAttributes" is the function to request server.
Here is MainActivity
public class MainActivity extends AppCompatActivity {
private ArrayList<String> data = new ArrayList<String>();
List<String> attributes = new ArrayList<String>();
List<String> categoryList = new ArrayList<String>();
final Organisation orga = Organisation.getInstance();
private class CallSocketTask extends AsyncTask<Integer, Integer, String> {
protected String doInBackground(Integer... nochnix) {
orga.SetInit();
categoryList = orga.getAttributes(orga.GET_CATEGORIES,null,true);
return null;
}
protected void onPostExecute(String string) {
//attributes = orga.getAttributes(orga.GET_PRODUCTS_BY_CATEGORY,null,true);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new CallSocketTask().execute();//orga.stop();
//requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.activity_main);
LinearLayout layer = (LinearLayout) findViewById(R.id.layer);
//getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.activity_main);
for(int i=0; i < categoryList.size(); i++)
{
Button button = new Button(this);
button.setId(i);
final String category = categoryList.get(i);
button.setText(category);
//click action
View.OnClickListener productHandler = new View.OnClickListener(){
public void onClick(View v) {
// doStuff
Intent intentMain = new Intent(MainActivity.this ,
GetProductsActivity.class);
intentMain.putExtra("categroy",category);
MainActivity.this.startActivity(intentMain);
Log.i("Content "," Main layout Click to Get Products by Category");
}
};
button.setOnClickListener(productHandler);
layer.addView(button);
}
}
}
Here is the GetProductsActivity
public class GetProductsActivity extends AppCompatActivity{
private ArrayList<String> data = new ArrayList<String>();
List<String> attributes = new ArrayList<String>();
final Organisation orga = Organisation.getInstance();
String category;
private class CallSocketTask extends AsyncTask<Integer, Integer, String> {
protected String doInBackground(Integer... nochnix) {
Bundle extras = getIntent().getExtras();
if (extras != null) {
category = extras.getString("categroy");
Log.i("Category Selected",category);
}
//orga.SetInit();
attributes = orga.getAttributes(orga.GET_PRODUCTS_BY_CATEGORY,category);
Log.i("Product number ",attributes.size()+"");
//attributes = orga.getAttributes("getProducts","getCategories","Orangensaft");
return null;
}
protected void onPostExecute(String string) {
//Log.i("Result ","");
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//this.notifyAll();
CallSocketTask myTask = new CallSocketTask();
myTask.execute();//orga.stop();
setContentView(R.layout.get_products);
LinearLayout layer = (LinearLayout) findViewById(R.id.productsLayer);
//getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.activity_main);
//Bundle extras = getIntent().getExtras();
//data= extras.getStringArrayList("products");
Log.i("Product number OnCreate",attributes.size()+"");
for(int i=0; i < attributes.size(); i++)
{
Log.i("Product",attributes.get(i));
Button button = new Button(this);
button.setId(i);
button.setText(attributes.get(i));
layer.addView(button);
}
}
}
Move your code for setting up the buttons into onPostExecute.
Solve the problem quite easy: use Thread.sleep() in onCreate() function, so loop button can wait for the AsyncTask running.
Non-static inner AsyncTask may lead to memory leaks, check some gotchas.
Thread.sleep() is a bad way. What if the request "Category" runs longer because of network issues?
Buttons can be created in a method YourActivity.createButtons() which should be called in onPostExecute().

Inner class issue when using onclicklistener

I keep getting repeated issues with: variable is accessed from within inner class
every time i want to use an object etc from an onclicklistener etc.
I know the problem is that its not set to final, but if i set to final im not able to do anything to it before pressing the onclicklistener button...
Example i have an EditText field, which is filled with getText from an object, then i want to press an apply button and the object with the new text from the textfield.
This doesnt work when the object need to be final for the "inner class" to use it.
How do i best handle this? i keep running into this bloody phenonemon...
public class EditPicture extends Activity{
private EditText text;
private Button applyBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID itemID = (UUID)getIntent().getSerializableExtra("itemUUID");
PictureItem pi = new PictureItem("","");
final ArrayList<PictureItem> tempArray = PictureTalkFragment.array;
for(int i = 0; i < tempArray.size(); i++){
if(itemID.equals(tempArray.get(i).getId())){
pi = tempArray.get(i);
tempArray.remove(i);
}
}
setContentView(R.layout.picturetalk_edit_pic);
text = (EditText)findViewById(R.id.editName);
text.setText(pi.getTitle());
applyBtn = (Button)findViewById(R.id.applyChangeBtn);
applyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tempArray.add(pi);
}
});
}
}
you should define tempArray variable outside of onCreate method.
public class EditPicture extends Activity{
private EditText text;
private Button applyBtn;
ArrayList<PictureItem> tempArray
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID itemID = (UUID)getIntent().getSerializableExtra("itemUUID");
PictureItem pi = new PictureItem("","");
tempArray = PictureTalkFragment.array;
for(int i = 0; i < tempArray.size(); i++){
if(itemID.equals(tempArray.get(i).getId())){
pi = tempArray.get(i);
tempArray.remove(i);
}
}
setContentView(R.layout.picturetalk_edit_pic);
text = (EditText)findViewById(R.id.editName);
text.setText(pi.getTitle());
applyBtn = (Button)findViewById(R.id.applyChangeBtn);
applyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tempArray.add(pi);
}
});
}
}
The problem is that you add th picture to a temporary array which is not accesible when you click on it. I think that you can do something like this to define the array outside the inCreate function.
public class EditPicture extends Activity{
private EditText text;
private Button applyBtn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID itemID = (UUID)getIntent().getSerializableExtra("itemUUID");
PictureItem pi = new PictureItem("","");
final ArrayList<PictureItem> tempArray = PictureTalkFragment.array;
for(int i = 0; i < tempArray.size(); i++){
if(itemID.equals(tempArray.get(i).getId())){
pi = tempArray.get(i);
tempArray.remove(i);
}
}
setContentView(R.layout.picturetalk_edit_pic);
text = (EditText)findViewById(R.id.editName);
text.setText(pi.getTitle());
applyBtn = (Button)findViewById(R.id.applyChangeBtn);
applyBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(PictureTalkFragment.array != null){
PictureTalkFragment.array.add(pi);
}
}
});
}
}

android: set visibility from AsyncTask

after this thread, i tried to make a variable status bar with this code:
private int[] loadingElementIDs;
private void initLoadingBar() {
final DisplayMetrics displayMetrics=getResources().getDisplayMetrics();
final float screenWidthInDp = displayMetrics.widthPixels/displayMetrics.density;
final int elementAmount = (int) (Math.floor(screenWidthInDp * 0.5f / 30) * 5);
//set margins
LinearLayout container = (LinearLayout)findViewById(R.id.loading_outer);
...
container.requestLayout();
//declare length
loadingElementIDs = new int[elementAmount];
LayoutParams LLParams = new LayoutParams(0, LayoutParams.MATCH_PARENT);
LLParams.weight = 1f;
LinearLayout element;
for (int i=0; i<elementAmount; i++) {
int id = generateViewId(); //creates unique id
element = new LinearLayout(this);
element.setVisibility(View.INVISIBLE);
element.setLayoutParams(LLParams);
element.setBackgroundDrawable(getResources().getDrawable(R.drawable.loading_inner));
element.setId(id);
element.requestLayout();
container.addView(element);
loadingElementIDs[i] = id;
}
}
this is working fine for me, but now i want to calculate sth with an asynctask and make the elements visible (code within my activity class):
private class PrefetchData extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#SuppressWarnings("static-access")
#Override
protected Void doInBackground(Void... arg0) {
try {
int step = 0;
float totalSteps = 100f;
while (...) {
step++;
// ...................
//show status
setLoadingStatus( step / totalSteps);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Intent i = new Intent(SplashScreen.this, MainActivity.class);
startActivity(i);
finish();
}
}
public void setLoadingStatus(float percentage) {
int max = (int) Math.min( Math.floor(percentage * loadingElementIDs.length),
for (int d=0; d<max; d++ ) {
((LinearLayout)findViewById(loadingElementIDs[d])).setVisibility(View.VISIBLE);
LinearLayout el = (LinearLayout)this.findViewById(loadingElementIDs[d]);
el.setVisibility(LinearLayout.VISIBLE);
}
}
And this does not work. if i call setLoadingStatus(20f); from onCreate it works perfectly, but not in the AsyncTask. Of course i do start initLoadingBar(); and new PrefetchData().execute(); in activities onCreate().
do you know what i'm doing wrong?
Use UI thread for update UI components. If you need to update task progress, you can use publishProgress(xxx) and onProgressUpdate(xxx). For more dateils: http://developer.android.com/reference/android/os/AsyncTask.html
I don't know how this got merged, the comment is all borked, but the requested code snippet is below for managing this with a Handler:
define a handler in your activity:
Handler handler = new Handler(){
handleMessage(Message msg)
{
if (msg.what == STATUS)
{
//do something if it's a message form your AsyncTask
}
else
//other messages..
}
};
when creating your AsyncTask, give it your handler. define a constructor to accept this and keep a local reference to it.
new PrefetchData(handler).execute(...);
and then inside your AsyncTask: (STATUS would be a constant setup as the message code.. )
while (...) {
step++;
// ...................
//show status
handler.obtainMessage(STATUS, step / totalSteps).sendToTarget();
}
thank you guys, i solved it with onProgressUpdate. instead of setLoadingStatus i call this:
private class PrefetchData extends AsyncTask<Void, Float, Void> {
....
protected void onProgressUpdate(Float... values) {
for (int d=0; d<Math.min( Math.floor(values[0] * loadingElementIDs.length), loadingElementIDs.length); d++ ) {
LinearLayout el = (LinearLayout)findViewById(loadingElementIDs[d]);
el.setVisibility(LinearLayout.VISIBLE);
}
}
}
You can runOnUiThread method to call Ui functions from any thread
runOnUiThread(new Runnable() {
public void run() {
// some code #3 (Write your code here to run in UI thread)
}
}); // enter code here

Using 'Async Tasks' on Android to generate random number and output

I am writing an random number generator program to show the output every sec.
The overview is that every second when the random number change I would want to random number to be output to the 'EditText' box. Is it possible?
I have research on it but result in unsuccessfully (mainly because of how the async works).
This is the code that I have written:
package com.example;
import java.util.Random;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class AsyncTasksActivity extends Activity {
EditText txtMessage;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String ranString = "";
try{
ranString = "";
for(int a = 0; a < 33; a++)
{
Random rn = new Random();
int i = rn.nextInt(256);
ranString = ranString + i + " ";
}
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
txtMessage = (EditText) findViewById(R.id.txtMessage);
txtMessage.setText(ranString);
}
public class runRandomly extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(String... values) {
// TODO Auto-generated method stub
super.onProgressUpdate(values);
}
}
}
In case you need to run the code to ensure it works, I have place the xml code here:
<?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"
android:weightSum="1">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Null"
/>
<EditText
android:id="#+id/Null"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:inputType="numberDecimal"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Random Key"/>
<EditText
android:id="#+id/txtMessage"
android:layout_width="fill_parent"
android:gravity="center"
android:editable="false" android:layout_height="61dp" android:layout_weight="0.14"/>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Much Thanks!
From my point of view,
Make a constructor of your AsyncTask class passing activity signature,
like,
public runRandomly(Activity activity) {
this.activity = activity;
context = activity;
}
also override this method
#Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
if (values[0] == 0) {
mDialog.setTitle("Processing...");
}
mDialog.setProgress(values[0]);
}
update the onProgressUpdate(call it) from your doInBackground(String... params) method
EDIT: you can also give a reference of your EditText view in AsyncTask constructor and do update in onProgressUpdate method.
EDIT: use this code..
public class NewClass extends Activity {
/** Called when the activity is first created. */
EditText edt;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newclass);
edt=(EditText)findViewById(R.id.ed);
new runRandomly(this,edt).execute();
}
public class runRandomly extends AsyncTask<String, String, String> {
String ranString="";
Activity activity;
EditText edtt;
public runRandomly(Activity activity,EditText edit) {
this.activity = activity;
edtt=edit;
}
#Override
protected String doInBackground(String... params) {
// TODO Auto-generated method stub
try{
for(int a = 0; a < 33; a++)
{
Random rn = new Random();
int i = rn.nextInt(256);
ranString = ranString + i + " ";
}
onProgressUpdate();
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
return null;
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
}
#Override
protected void onProgressUpdate(String... values) {
// TODO Auto-generated method stub
edtt.setText(""+ranString);
super.onProgressUpdate(values);
}
}
}
Simple, Thanx.
put this line outside of the for loop it will re-generate new object so no need it in loop
Random rn = new Random();
for(int a = 0; a < 33; a++)
{
int i = rn.nextInt(256);
ranString = ranString + i + " ";
}
you need to Handler and Runnable object which call the AsynTask execute method using runRandomly object
like create this object
Handler handler = new Handler();
runRandomly randomly = new runRandomly();
Runnable callRandom = new Runnable(){
public void run(){
//// call the execute method
randomly.execute();
///// here handler call this runnable every 1 sec i.e 1000 delay time
handler.postDelay(callRandom,1000);
}
}
in onBackground generate the number
#Override
protected String doInBackground(String... params) {
String ranString = "";
Random rn = new Random();
for(int a = 0; a < 33; a++)
{
int i = rn.nextInt(256);
ranString = ranString + i + " ";
}
return ranString;
}
this above method will generate the random number string and when it finish this will return that string to the postExecute();
#Override
protected void onProgressUpdate(String values) {
super.onProgressUpdate(values);
if(values!=null & !values.equals(""))
txtMessage.setText(ranString);
}

Categories

Resources