My main activity kicks off a secondary activity (using
startActivityForResult) that invites the user to input details of one of
four players at a bridge table.
When the user has chosen a player and clicked OK, the following things
happen (triggered by code in onActivityResult)
1. The player details (passed back in the Intent returned by the secondary
activity) are written to a text file.
2. An AsyncTask is started to send that file to a server PC using SMB.
3. While the AsyncTask is still running, the same secondary activity is
invoked again to get the next player's details.
This sequence is repeated until all four players' details have been sent to
the server.
On my tablet, this works perfectly every time but one of my beta testers
has a bizarre problem. He can usually enter the first player's name
successfully, sometimes the second and occasionally the third but
eventually one of the names screens appears for a short time later only to
disappear again without the user clicking my OK button.
Note that the player-names screen allows the user to type a partial name
and uses a ListView to display all players in a club membership list that
contain the letters typed. I don't know if that's significant.
What I am seeing in my trace file is that the onCreate method of the select
player activity is called. The OKClicked method is never called. In fact, I
have trace points before every finish() call in the select player activity
and none of them is called. After the onCreate call, the next thing I see
in my trace file, about 30 seconds later, is onActivityResult reporting a
ResultCode of zero and the returned Intent pointer of null. In other words,
the select player activity has spontaneously closed without the user
clicking OK or it going through any of my code designed to close the
activity tidily.
This never happens on my tablet, which is running Android 4.4.2. It always
happens on my beta tester's tablet, which is running 4.4.
After reading reports of a similar Android problem, I changed all the
activities' settings in my manifest (including the main activity) to
launchMode singleTop but this made no difference.
Any suggestions? This is particularly awkward because I cannot reproduce
the problem on my kit. I am having to do all my debugging remotely by
adding trace points and asking my beta tester to repeat the experiment.
I have uploaded the code for the select player activity in case it's of
interest.
Kind regards
Keith
--
You received this message because you are subscribed to the Google Groups
"Android Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/android-developers.
To view this discussion on the web visit
https://groups.google.com/d/msgid/android-developers/6502018f-b8b0-4dbb-a3a8-b132458cca3d%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
package uk.org.writerman.scoresheet;
import android.content.Intent;
import android.os.SystemClock;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
public class SelectPlayer extends AppCompatActivity {
private cClubMembers MembershipList = new cClubMembers();
private cClubMembers EBUList = new cClubMembers();
private cClubMembers MatchingPlayers = new cClubMembers();
private cClubMemberDetails ChosenPlayer;
private String TableName;
private boolean UseExternalFilestore;
private boolean HaveNamesFile;
private boolean HaveEBUList;
private String SeatName;
private Button OKButton;
private ImageButton SearchButton;
private ListView lvMatches;
private long LastAbortClick;
private boolean m_InternalChange;
private boolean VisitorOnDisplay;
@Override
protected void onCreate(Bundle savedInstanceState) {
// SelectPlayer. Parameters are Table identity string, Seat (as string) UseExternalFilestore and HaveNames
// If it's a repeat, may also have ParamPlayerID, ParamPlayerName and ParamPlayerEBUNo
// Return values are ParamPlayerID, ParamPlayerName and ParamPlayerEBUNo
// We use the prompt above the input box (instructions when input is empty) to show
// no matches, number of matches or full details of exact match. Colour code the background
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_player);
// STAW
Statics.log(getApplicationContext(), "Start SelectPlayer activity");
m_InternalChange = false;
VisitorOnDisplay = false;
LastAbortClick = SystemClock.elapsedRealtime() - 4000; // To ensure first click doesn't abort
TableName = getIntent().getStringExtra(GLOBALS.ParamChosenTable);
SeatName = getIntent().getStringExtra(GLOBALS.ParamCompassPole);
UseExternalFilestore = getIntent().getBooleanExtra(GLOBALS.ParamUseExternalFilestore, true);
HaveNamesFile = getIntent().getBooleanExtra(GLOBALS.ParamHaveNames, false);
HaveEBUList = getIntent().getBooleanExtra(GLOBALS.ParamHaveEBUList, false);
final TextView tvCaption = (TextView) findViewById(R.id.spTableCaption);
tvCaption.setText(getString(R.string.Table) + " " + TableName + " " + SeatName);
OKButton = (Button)findViewById(R.id.bOK);
lvMatches = (ListView)findViewById(R.id.spMatchList);
if (HaveNamesFile) {
try {
MembershipList.ProcessNamesFile(getApplicationContext(), UseExternalFilestore, GLOBALS.NamesFileName);
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), R.string.CannotParseNames, Toast.LENGTH_LONG).show();
}
}
if (HaveEBUList) {
try {
EBUList.ProcessNamesFile(getApplicationContext(), UseExternalFilestore, GLOBALS.EBUNamesFile);
EBUList.isEBUList = true;
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), R.string.CannotParseEBUNames, Toast.LENGTH_LONG).show();
}
}
// Monitor for selection from list
lvMatches.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position < MatchingPlayers.size()) {
// Copy matching player info to name box
String HisName = ChoosePlayer(MatchingPlayers.get(position));
// As amn internal change, copy the name to the input box
TextView tvInput = (TextView) findViewById(R.id.spUserInput);
m_InternalChange = true;
tvInput.setText(HisName);
m_InternalChange = false;
}
}
});
// Monitor for changes to name box
final TextView tvUserInput = (TextView) findViewById(R.id.spUserInput);
tvUserInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
if (m_InternalChange) return;
LookForMatches();
}
});
// Have we been here before?
String MemberName = getIntent().getStringExtra(GLOBALS.ParamPlayerName);
if (MemberName != null) {
int MemberNo = getIntent().getIntExtra(GLOBALS.ParamPlayerID, -1);
int EBUNo = getIntent().getIntExtra(GLOBALS.ParamPlayerEBUNo, -1);
cClubMemberDetails LastChoice = new cClubMemberDetails(MemberNo, MemberName.trim(), cClubMemberDetails.EBUNoToString(EBUNo));
if (!LastChoice.getMemberName().isEmpty())
ChoosePlayer(LastChoice);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.abortmenu, menu);
return super.onCreateOptionsMenu(menu);
}
/**
* Event Handling for Individual menu item selected
* Identify single menu item by it's id
* */
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.closeapp:
if ((SystemClock.elapsedRealtime() - LastAbortClick) <= GLOBALS.AbortTime) {
Statics.log(getApplicationContext(), "SelectPlayer: User selected ahort");
setResult(GLOBALS.RetValCloseApp);
finish();
}
else {
Toast.makeText(getApplicationContext(), getString(R.string.AbortPrompt), Toast.LENGTH_LONG).show();
LastAbortClick = SystemClock.elapsedRealtime();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void ClearMatchList() {
// Also disables the OK button
// Now populate the array list with one empty entry
ArrayList<HashMap<String, String>> nList = new ArrayList<HashMap<String, String>>();
HashMap<String, String> nLine = new HashMap<String, String>();
nLine.put(namesListAdapter.NameColumn, "");
nList.add(nLine);
namesListAdapter adapter = new namesListAdapter(getApplicationContext(), this, nList);
lvMatches.setAdapter(adapter);
// String[] MatchList = new String[1];
// MatchList[0] = "";
// ArrayAdapter<String> lvAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, MatchList);
//
// lvMatches.setAdapter(lvAdapter);
Statics.enableButton(OKButton, false);
}
private void hideVisPanel() {
setVisPanel("");
}
private void setVisPanel(String Text) {
TextView visPrompt = (TextView) findViewById(R.id.ifVisPrompt);
LinearLayout visPanel = (LinearLayout) findViewById(R.id.ifVisPanel);
visPrompt.setText(Text);
if (Text.isEmpty()) {
visPrompt.setVisibility(View.GONE);
visPanel.setVisibility(View.GONE);
} else {
visPrompt.setVisibility(View.VISIBLE);
visPanel.setVisibility(View.VISIBLE);
}
}
private void LookForMatches() {
// If single digit, look only for club number
MatchingPlayers.clear();
final TextView tvUserInput = (TextView) findViewById(R.id.spUserInput);
String NewInput = tvUserInput.getText().toString().trim();
final TextView tvPrompt = (TextView)findViewById(R.id.spNamePrompt);
boolean AllNumeric = Statics.isEntirelyNumeric(NewInput);
VisitorOnDisplay = false;
if (NewInput.isEmpty() || (!AllNumeric && NewInput.length()<3)) {
// Clear the prompt. User instructions will appear as hint if the box is empty
tvPrompt.setBackgroundColor(GLOBALS.PromptColour);
tvPrompt.setText("");
ClearMatchList();
hideVisPanel();
return;
}
// If it's entirely numeric, check for club number
// If it's text, search by name
cClubMemberDetails Match;
int MatchType = GLOBALS.mtNoMatch;
if (AllNumeric) {
int NumberInput = Integer.parseInt(NewInput);
// Check for club number or EBU number, first in members list then in EBU list
if (HaveNamesFile) {
// Search names file by club number
try {
Match = MembershipList.findByNumber(NumberInput);
// If we find a match on number, don't search any further
MatchingPlayers.add(Match);
MatchType = GLOBALS.mtPerfectMatch;
}
catch (Exception ex) { }
}
// Not found in club members list. How about EBU list?
if (MatchingPlayers.size() < 1 && HaveEBUList) {
try {
Match = EBUList.findByNumber(NumberInput);
// If we find a match on number, don't search any further
MatchingPlayers.add(Match);
MatchType = GLOBALS.mtPerfectMatch;
}
catch (Exception ex) { }
}
} else {
// Not numeric. Search the list(s)for name matches. There could be several partials
if (HaveNamesFile) {
MatchType = MatchingPlayers.findMatchesIn(MembershipList, NewInput);
}
if (MatchType == GLOBALS.mtNoMatch && HaveEBUList)
MatchType = MatchingPlayers.findMatchesIn(EBUList, NewInput);
}
switch (MatchType){
case GLOBALS.mtPerfectMatch: {
ChoosePlayer(Match = MatchingPlayers.get(0));
}
break;
case GLOBALS.mtAmbiguousMatch: {
// Populate our ListView with possible matches
String[] MatchList = MatchingPlayers.toStringArray();
int nMatches = MatchingPlayers.size();
ArrayList<HashMap<String, String>> nList = new ArrayList<HashMap<String, String>>();
for (int n=0; n<nMatches; ++n) {
HashMap<String, String> nLine = new HashMap<String, String>();
nLine.put(namesListAdapter.NameColumn, MatchList[n]);
nList.add(nLine);
}
namesListAdapter adapter = new namesListAdapter(getApplicationContext(), this, nList);
lvMatches.setAdapter(adapter);
// ArrayAdapter<String> lvAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, MatchList);
//
String Prompt = (nMatches == 1) ? getString(R.string.OnePlayerMatch)
: Integer.toString(nMatches) + " " + getString(R.string.MultiplePlayerMatches);
tvPrompt.setText(Prompt);
tvPrompt.setBackgroundColor(GLOBALS.ExactMatchColour);
// lvMatches.setAdapter(lvAdapter);
Statics.enableButton(OKButton, false);
}
break;
default: {
// No matches
tvPrompt.setText(getString(R.string.NoPlayerMatches));
tvPrompt.setBackgroundColor(GLOBALS.NoMatchColour);
ClearMatchList();
// It could be an explicitly typed name. Note that ClearMatchList() will
// have disabled the OK button
if (!NewInput.isEmpty() && !AllNumeric) {
ChosenPlayer = new cClubMemberDetails(NewInput);
Statics.enableButton(OKButton, true);
tvPrompt.setText(getString(R.string.NoPlayerMatches));
String Prompt=getString(R.string.If) + " \"" + NewInput + "\" " + getString(R.string.isVisitor);
setVisPanel(Prompt);
VisitorOnDisplay = true;
}
}
}
}
private String ChoosePlayer(cClubMemberDetails TheOne) {
ChosenPlayer = TheOne;
String EBUNo = ChosenPlayer.getEBUNumber().trim();
String EBUString;
String DetailsString;
if (EBUNo.isEmpty())
EBUString = "";
else
EBUString = " (" + EBUNo + ")";
if (ChosenPlayer.getClubNumber() > 0) {
// We have found a matching club member
DetailsString = Integer.toString(ChosenPlayer.getClubNumber()) + ": " + ChosenPlayer.getMemberName() + EBUString;
} else {
// Matching non-member
DetailsString = ChosenPlayer.getMemberName()+ EBUString;
}
final TextView tvPrompt = (TextView)findViewById(R.id.spNamePrompt);
Statics.setTextViewHTML(getApplicationContext(), tvPrompt, DetailsString);
// tvPrompt.setText(DetailsString);
tvPrompt.setBackgroundColor(GLOBALS.ExactMatchColour);
VisitorOnDisplay = false;
Statics.enableButton(OKButton, true);
return ChosenPlayer.getMemberName();
}
public void ClearClicked(View callingView) {
final TextView tvInput = (TextView)findViewById(R.id.spUserInput);
tvInput.setText("");
ClearMatchList();
}
public void PromptClicked(View callingView) {
// if (VisitorOnDisplay) OKClicked(callingView);
}
public void OKClicked(View callingView) {
if (ChosenPlayer != null) {
Statics.log(getApplicationContext(), "OK clicked. Returning player details " + ChosenPlayer.toString());
Intent results = new Intent();
results.putExtra(GLOBALS.ParamPlayerID, ChosenPlayer.getClubNumber());
results.putExtra(GLOBALS.ParamPlayerName, ChosenPlayer.getMemberName());
results.putExtra(GLOBALS.ParamPlayerEBUNo, ChosenPlayer.getEBUNumber());
setResult(GLOBALS.RetValNormal, results);
// STAW
Statics.log(getApplicationContext(), "Finish");
finish();
}
}
@Override
public void onBackPressed() {
setResult(GLOBALS.RetValGoBack);
// STAW
Statics.log(getApplicationContext(), "Back was pressed");
finish();
}
}