I have a TableLayout with some hundreds of tablerows.
I'm filling it with a thread, which notifies to a handler when a row is created, and the handler adds the row in the UI thread. But the problem is that in some cases some users are reporting ARN due to:
Input dispatching timed out (Waiting to send key event because the
focused window has not finished processing all of the input events
that were previously delivered to it. Outbound queue length: 0. Wait
queue length: 1.)
The Android OS handles creating a ANR when it detects the UI/Main thread has been blocking for 5 seconds.
I thought using AsyncTask but is going to be deprecated in Android 11.
This is my thread:
private class PopulateTableThread extends Thread {
private Context context;
private ArrayList<Player> players;
public PopulateTableThread(Context context, ArrayList<Player> players) {
super();
this.context = context;
this.players = players;
}
public void run() {
for (int i=0; i<players.size(); i++) {
TableRow row = new TableRow(context);
row.setLayoutParams(rowParams);
row.setBackgroundResource(R.drawable.table_row_not_selected);
String strings[] = {players.get(i).getName(),
"" + players.get(i).getTeam().getName(),
"" + players.get(i).getPositionInString(context),
"" + players.get(i).getYearsOfContractFormatted(),
"" + players.get(i).getValue() + " M€",
"" + players.get(i).getSalary() + " M€",
"" + players.get(i).getAge(),
"" + players.get(i).getBaseLevel()};
for (int j = 0; j < strings.length; j++) {
TextView text = new TextView(context);
text.setBackgroundResource(R.drawable.table_cell_background);
if (j == 0) {
text.setLayoutParams(nameParams);
text.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
text.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0);
text.setMaxLines(1);
text.setEllipsize(TextUtils.TruncateAt.END);
}else if (j == 1) {
text.setLayoutParams(teamNameParams);
text.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
text.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0);
text.setMaxLines(1);
text.setEllipsize(TextUtils.TruncateAt.END);
} else if (j == 2 || j == 3) {
text.setLayoutParams(positionAndContractParams);
text.setGravity(Gravity.CENTER);
} else if (j == 4) {
text.setLayoutParams(valueParams);
text.setGravity(Gravity.CENTER);
} else if (j == 5) {
text.setLayoutParams(salaryParams);
text.setGravity(Gravity.CENTER);
} else if (j == 6 || j == 7) {
text.setLayoutParams(ageAndLevelParams);
text.setGravity(Gravity.CENTER);
}
if (j == 3 && strings[3].split("/")[0].equals("1")) {
text.setBackgroundResource(R.drawable.table_cell_background_danger);
}
text.setMinHeight((int) getResources().getDimension(R.dimen.cell_height));
text.setText(strings[j]);
row.addView(text);
}
ProgressBar levelProgress = new ProgressBar(new ContextThemeWrapper(context, R.style.ProgressBar), null, 0);
levelProgress.setBackgroundResource(R.drawable.table_cell_background);
levelProgress.setLayoutParams(levelBarParams);
levelProgress.setMinimumHeight((int) getResources().getDimension(R.dimen.cell_height));
levelProgress.setProgress(players.get(i).getBaseLevel());
levelProgress.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0);
row.addView(levelProgress);
final int finalIndex = i;
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (searchProgressBar.getVisibility() == View.VISIBLE) {
return;
}
SoundEffectsManager.getInstance().play(context, SoundEffectsManager.button);
displaySignDialog(players.get(finalIndex));
}
});
Message message = new Message();
message.what = HANDLER_ROW_CREATED;
message.obj = row;
updateTableHandler.sendMessage(message);
}
Message message = new Message();
message.what = HANDLER_TABLE_FILLED;
updateTableHandler.sendMessage(message);
}
}
And this is the handler that it's updating the ui thread when the thread has created a new TableRow:
updateTableHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what){
case HANDLER_ROW_CREATED:
TableRow row = (TableRow) msg.obj;
tableLayout.addView(row);
break;
case HANDLER_TABLE_FILLED:
tableLayout.setAlpha(1f);
searchProgressBar.setVisibility(View.GONE);
break;
}
}
};
How can i avoid these ARN reports?
Trying to do David Wasser solution, but with same problem:
private class PopulateTableThread extends Thread {
private Context context;
private ArrayList<Player> players;
public PopulateTableThread(Context context, ArrayList<Player> players) {
super();
this.context = context;
this.players = players;
}
public void run() {
Log.d("XXX_SeekerActivity","filling table with "+players.size()+" players");
for (int i=0; i<players.size(); i++) {
final String strings[] = {players.get(i).getName(),
"" + players.get(i).getTeam().getName(),
"" + players.get(i).getPositionInString(context),
"" + players.get(i).getYearsOfContractFormatted(),
"" + players.get(i).getValue() + " M€",
"" + players.get(i).getSalary() + " M€",
"" + players.get(i).getAge(),
"" + players.get(i).getBaseLevel()};
final int finalI = i;
runOnUiThread(new Runnable() {
#Override
public void run() {
TableRow row = new TableRow(context);
row.setLayoutParams(rowParams);
row.setBackgroundResource(R.drawable.table_row_not_selected);
for (int j = 0; j < strings.length; j++) {
TextView text = new TextView(context);
text.setBackgroundResource(R.drawable.table_cell_background);
if (j == 0) {
text.setLayoutParams(nameParams);
text.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
text.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0);
text.setMaxLines(1);
text.setEllipsize(TextUtils.TruncateAt.END);
}else if (j == 1) {
text.setLayoutParams(teamNameParams);
text.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
text.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0);
text.setMaxLines(1);
text.setEllipsize(TextUtils.TruncateAt.END);
} else if (j == 2 || j == 3) {
text.setLayoutParams(positionAndContractParams);
text.setGravity(Gravity.CENTER);
} else if (j == 4) {
text.setLayoutParams(valueParams);
text.setGravity(Gravity.CENTER);
} else if (j == 5) {
text.setLayoutParams(salaryParams);
text.setGravity(Gravity.CENTER);
} else if (j == 6 || j == 7) {
text.setLayoutParams(ageAndLevelParams);
text.setGravity(Gravity.CENTER);
}
if (j == 2) {
switch (players.get(finalI).getPosition()) {
case Player.PLAYER_POSITION_GOALKEEPER:
text.setBackgroundResource(R.drawable.table_cell_background_position_gk);
break;
case Player.PLAYER_POSITION_DEFENDER:
text.setBackgroundResource(R.drawable.table_cell_background_position_def);
break;
case Player.PLAYER_POSITION_MIDFIELDER:
text.setBackgroundResource(R.drawable.table_cell_background_position_mid);
break;
case Player.PLAYER_POSITION_FORWARD:
text.setBackgroundResource(R.drawable.table_cell_background_position_fw);
break;
}
}
if (j == 3 && strings[3].split("/")[0].equals("1")) {
text.setBackgroundResource(R.drawable.table_cell_background_danger);
}
text.setMinHeight((int) getResources().getDimension(R.dimen.cell_height));
text.setText(strings[j]);
row.addView(text);
}
ProgressBar levelProgress = new ProgressBar(new ContextThemeWrapper(context, R.style.ProgressBar), null, 0);
levelProgress.setBackgroundResource(R.drawable.table_cell_background);
levelProgress.setLayoutParams(levelBarParams);
levelProgress.setMinimumHeight((int) getResources().getDimension(R.dimen.cell_height));
levelProgress.setProgress(players.get(finalI).getBaseLevel());
levelProgress.setPadding((int) getResources().getDimension(R.dimen.spacing_small), 0, (int) getResources().getDimension(R.dimen.spacing_small), 0);
row.addView(levelProgress);
final int finalIndex = finalI;
row.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (searchProgressBar.getVisibility() == View.VISIBLE) {
return;
}
SoundEffectsManager.getInstance().play(context, SoundEffectsManager.button);
displaySignDialog(players.get(finalIndex));
}
});
row.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(final View view, MotionEvent motionEvent) {
if (searchProgressBar.getVisibility() == View.VISIBLE) {
return true;
}
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
delayColorizeHandler.postDelayed(new Runnable() {
#Override
public void run() {
Util.getInstance().colorizeBackgroundCheckingApiLevel(view);
}
}, Util.WAIT_TIME_BEFORE_TOUCH_COLORIZE);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
delayColorizeHandler.removeCallbacksAndMessages(null);
Util.getInstance().clearBackgroundColorFilter(view);
break;
}
return false;
}
});
tableLayout.addView(row);
}
});
}
runOnUiThread(new Runnable() {
#Override
public void run() {
tableLayout.setAlpha(1f);
searchProgressBar.setVisibility(View.GONE);
}
});
}
}
You can't create and manipulate UI elements (TableRow, TextView, etc.) on a background thread. All this stuff needs to be done on the main (UI) thread directly. You are probably creating object locks on parts of the UI framework that is blocking the main (UI) thread and causing your ANR.
Have your background thread loop over your players and get the data for each one. Then it can post a Runnable to the main (UI) thread (once for each player) with the player data and in the Runnable (which will run on the main (UI) thread) you can create the UI elements and add them to your layout.
By doing this in a loop in a background thread, you won't block the UI thread.
I want to play the audio two times before playing the next item.
This is my class where I want to display the items.
public void startSlides() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
runOnUiThread(new Runnable() {
public void run() {
Intent intent = getIntent();
int setId = intent.getIntExtra("SelectedSetId",0);
databaseAccess.open();
setId = setId + 1;
List<byte[]> audio = databaseAccess.getAudioA(setId);
if (i > audio.size()){
i = 0;
}else{
playAudio(audio.get(i));
playAudio(audio.get(i));
i++;}
List<String> vocab = databaseAccess.getVocabNameA(setId);
textView2.setText(vocab.get(k));
k++;
textView.setText(+j + "/" + vocab.size());
j++;
databaseAccess.close();
if (j == vocab.size() + 1) {
timer.cancel();
}
}
});
}
}, 0, DURATION);
}
I think I have to add something at the playAudio(audio.get(i)), but I have no idea how should I do. If I do this, it plays the audio at the same time. Thanks.
if (i > audio.size()){
i = 0;
}else{
playAudio(audio.get(i));
playAudio(audio.get(i));
i++; }
I want slider in my imageview but it gives me only one image at a time if any one of you have a solution please tell me.
here in my activity class.
images come from the API and there is a whole path of every image and its a web url
ArrayList<String> imagepath1 = i.getExtras().getStringArrayList("event_photo");
for (int i1 = 0; i1 < imagepath1.size(); i1++) {
stockArr = new String[imagepath1.size()];
stockArr = imagepath1.toArray(stockArr);
// imagepath = stockArr.toString();
String imagepath = stockArr[i1];
}
if (!TextUtils.isEmpty(imagepath)) {
if (imagepath.endsWith(".jpeg") || imagepath.endsWith(".jpg")
|| imagepath.endsWith(".gif") || imagepath.endsWith(".png")) {
imageLoader = new ImageLoader(mcontext);
mUpdateResults = new Runnable() {
public void run() {
Animation rotateimage = AnimationUtils.loadAnimation(
getApplicationContext(), R.anim.alpha);
for (int i2 = 0; i2 < stockArr.length; i2++) {
imageLoader.DisplayImage(imagepath1.get(i2),
imagetop);
// imagetop.startAnimation(rotateimage);
/*imagetop.setImageResource(number[currentimageindex
% stockArr.length]);*/
}
}
};
final Handler mHandler = new Handler();
int delay = 500; // delay for 1 sec.
int period = 5000; // repeat every 4 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
mHandler.post(mUpdateResults);
}
}, delay, period);
} else {
}
}
Please Help if any one have a solution
After 3 hours of try i decided to ask here and see if someone can provide me a solution for this error: java.lang.IndexOutOfBoundsException: Invalid index 4, size is 4
Here is my code.
private ProgressBar progressBar;
private int progressStatus = 0;
private Handler handler = new Handler();
--------------------
status.setText(getString(R.string.init));
progressBar.setVisibility(View.VISIBLE);
final Map<String,?> keys = prefs.getAll(); //4 prefs atm inside.
final ArrayList<String> props = new ArrayList<String>();
final ArrayList<String> values = new ArrayList<String>();
if (keys != null) {
for(final Map.Entry<String,?> entry : keys.entrySet()) {
props.add(entry.getKey());
values.add(entry.getValue().toString());
}
final int total = props.size();
progressBar.setMax(total);
new Thread(new Runnable() {
public void run() {
while (progressStatus < total) {
progressStatus += 1;
handler.post(new Runnable() {
public void run() {
progressBar.setProgress(progressStatus);
if (props.get(progressStatus) != null) {
writeProps(props.get(progressStatus), values.get(progressStatus));
status.setText(getString(R.string.writing) + ": " + props.get(progressStatus));
}
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (progressStatus == total) {
handler.post(new Runnable() {
public void run() {
progressBar.setVisibility(View.GONE);
progressStatus = total + 1;
myVoidOnFinish();
}
});
}
}
}).start();
}
I get the stuck here:
writeProps(props.get(progressStatus), values.get(progressStatus));
status.setText(getString(R.string.writing) + ": " + props.get(progressStatus));
The main problem is here
while (progressStatus < total) {
progressStatus += 1;
}
check value of your progress status it should be not greater than 3 while in you code it is 4 in last while index is only from 0 to 3. please set value of your progress status accordingly.
try this
while (progressStatus < total-1) {
progressStatus += 1;
}
The problem is you are setting the progressstatus value like following
final int total = props.size();
progressBar.setMax(total);
and you in the following line you are trying to get values of props ase
writeProps(props.get(progressStatus), values.get(progressStatus));
see that for the total size of 4 your progressStatus will be 4. But the maximum index of props and values will be 3. So here is the problem
you can set the value to 1 less than the size like
final int total = props.size() - 1;
You are using one extra index as you can use maximum up to 3. So please start it form zero and use less then check instead of less then equal to.
I want to make a timer that changes a picture on the screen when the interval of the picture is over.
for(int x = 0; x < intervals.size(); x++)
{
t.schedule(new TimerTask(){
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
ImageView foto = (ImageView) findViewById(R.id.imageView1);
Bitmap bmp = sponsorlijst.get(index).getFoto();
foto.setImageBitmap(bmp);
if(index < sponsorlijst.size() -1)
{
index ++;
}
else
{
index = 0;
}
}
}
);
};}, 0, intervals.get(x));
Intervals are a list with the different displaytime of the pictures and the pictures are in sponsorlijst.
Does anyone know how to change the interval of the timer while running? Thanks