I have a main activity called Chessboard. Within Chessboard, in the onCreate, I set a fragment activity GameInfoFragment. After this, a call is made to query an SQLite database, immediately after which a method in class SQLiteDataInterpreter is called. From here, a call is made to a method in the GameInfoFragment class, where imageViews in the fragment I set in Chessboard's onCreate should be populated.
When I attempt to start the Chessboard activity, I receive the following error:
Caused by: java.lang.IllegalStateException: Fragment GameInfoFragment{2ef389d9 id=0x7f09008d InfoTest} not attached to Activity
The code in Chessboard's onCreate is the following:
FragmentManager manager = this.getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
if (chessboard.moveCounter % 2 == 0) {
transaction.add(com.zlaporta.chessgame.R.id.game_play_screen, gameInfo, "InfoTest");
} else {
transaction.add(com.zlaporta.chessgame.R.id.game_play_black_screen, gameInfo, "InfoTestBlack");
}
transaction.commit();
Toolbar toolbar = (Toolbar) findViewById(R.id.app_bar);
toolbar.setTitle("Current Game");
setSupportActionBar(toolbar);
DBAdapter boardstateDB = new DBAdapter(chessboard.this);
boardstateDB.open();
Cursor cur = boardstateDB.getAllRows();
if (cur != null && cur.moveToFirst()) {
cur.moveToLast();
String pieceData = cur.getString(cur.getColumnIndex("piecepositions"));
whiteKingMoved = cur.getInt(cur.getColumnIndex("whitekingmoved"));
blackKingMoved = cur.getInt(cur.getColumnIndex("blackkingmoved"));
leftWRMoved = cur.getInt(cur.getColumnIndex("whiterook1moved"));
rightWRMoved = cur.getInt(cur.getColumnIndex("whiterook2moved"));
leftBRMoved = cur.getInt(cur.getColumnIndex("blackrook1moved"));
rightBRMoved = cur.getInt(cur.getColumnIndex("blackrook2moved"));
moveCounter = cur.getInt(cur.getColumnIndex("movecount"));
String madeMoves = cur.getString(cur.getColumnIndex("mademoves"));
storedTakenPieces = cur.getString(cur.getColumnIndex("takenpieces"));
SQLiteDataInterpreter boardRefresher = new SQLiteDataInterpreter();
boardRefresher.refreshBoard(pieceData, madeMoves, chessboard.this, storedTakenPieces);
} else {
boardstateDB.updateGameState("r00 k01 b02 q03 a04 b05 k06 r07 p10 p11 p12 p13 p14 p15 p16 p17 P60 P61 P62 P63 P64 P65 P66 P67 R70 K71 B72 Q73 A74 B75 K76 R77",
0, 0, 0, 0, 0, 0, 0, " ", " ");
Cursor curs = boardstateDB.getAllRows();
curs.moveToLast();
String pieceData = curs.getString(curs.getColumnIndex("piecepositions"));
whiteKingMoved = curs.getInt(curs.getColumnIndex("whitekingmoved"));
blackKingMoved = curs.getInt(curs.getColumnIndex("blackkingmoved"));
leftWRMoved = curs.getInt(curs.getColumnIndex("whiterook1moved"));
rightWRMoved = curs.getInt(curs.getColumnIndex("whiterook2moved"));
leftBRMoved = curs.getInt(curs.getColumnIndex("blackrook1moved"));
rightBRMoved = curs.getInt(curs.getColumnIndex("blackrook2moved"));
moveCounter = curs.getInt(curs.getColumnIndex("movecount"));
String madeMoves = curs.getString(curs.getColumnIndex("mademoves"));
storedTakenPieces = curs.getString(curs.getColumnIndex("takenpieces"));
SQLiteDataInterpreter boardRefresher = new SQLiteDataInterpreter();
boardRefresher.refreshBoard(pieceData, madeMoves, chessboard.this, storedTakenPieces);
And the relevant code in my GameInfoFragment class which is causing problems:
public void setTakenPiece(String[] takenpiecerecord) {
takenPiece = takenpiecerecord;
int c;
for (c = 0; c < takenPiece.length; c++) {
String takenPieceHolder = "t" + c;
String pieceCheck = takenPiece[c];
//System.out.println(square);
int takenPieceHolderID = this.getResources().getIdentifier(takenPieceHolder, "id", getActivity().getPackageName());
ImageView takenPieceHolderSquare = (ImageView) v.findViewById(takenPieceHolderID);
The main line of code that is causing issues is where I try to set the value of takenPieceHolderID in the code directly above.
How can I ensure that my fragment is added so that its imageViews will be populated upon the start of my Chessboard Activity?
You should check if Activity exists and if isAdded() is True
public void setTakenPiece(String[] takenpiecerecord) {
activity = getActivity();
if (isAdded() && activity) {
takenPiece = takenpiecerecord;
int c;
for (c = 0; c < takenPiece.length; c++) {
String takenPieceHolder = "t" + c;
String pieceCheck = takenPiece[c];
//System.out.println(square);
int takenPieceHolderID = this.getResources().getIdentifier(takenPieceHolder, "id", getActivity().getPackageName());
ImageView takenPieceHolderSquare = (ImageView) v.findViewById(takenPieceHolderID);
}}
I use the fragment manager to find the fragment by tag. If it returns null I have problems with fragment creation. This depends on whether my fragment has a valid container, calls an adapter and the adapter is unhappy, or if it calls a view improperly, so double check all. Make sure your container is added to your ViewGroup, if you are using one, and that the container is detached from any parent.
I create my fragments programatically and set tag names that can be searched.
Using debug, be sure that the fragment constructor is called, then make sure onCreateView is called. If so, single step through onCreateView and look for a line that bombs. Make sure the fragment returns a view.
Also be sure what type of fragment you are using, android or android.support.v4.app.Fragment.
At times I have had to use FragmentManager whatever_your_name_is.executePendingTransactions to ensure that the fragment has been added prior to being accessed. Be sure to use the fragment manager that launched the fragment.
That's my brain dump, good luck.
Related
I'm trying to pre-populate a FragmentStatePagerAdapter with a list of objects but I cannot instantiate a new fragment.
Background:
My PagerAdapter consists of an ArrayList of Msg objects (mMsgConvoList).
MsgConvoList is an ArrayList of all messages from a given thread.
The partitioning of mMsgConvoList creates sublists of 3 msgs each (msgSublist).
Each sublist is put through the while loop to be handled by the PagerAdapter in creating new fragments, and adding additional textviews:
How the logic in the while loop works:
If the count == 2, that means there should be a new fragment, otherwise if the count is 1 to 0, locate the currentFragment and add the Msg (this is where the error occurs).
Error:
The error is occurring after the count == 2. The currentFragment is NULL on the 'else' portion of the while loop (count = 1 or 0). It seems like instantiateItem on the MsgFragment is never called. I'm not sure why this doesn't work when using the loop below.
Caused by: java.lang.NullPointerException
at to.testing.viewpagertest.MsgPagerActivity.onCreate(MsgPagerActivity.java:55)
If I remove the all the code within the 'else' condition from while loop, the fragment is created and the object is added to the text view:
if (count == 2){
mAdapter.addMessages(msgSublist.get(count));
mAdapter.notifyDataSetChanged();
mViewPager.setCurrentItem(mAdapter.getCount(), true);
This tells me a few things: The above code, outside of the while loop works, so the dataset is working correctly inside the textView and the fragment is being created successfully. It is only when I try to add an additional Msg object to the existing Array, that the currentFragment never seems to get created. Any suggestions would be much appreciated.
MsgPagerActivity:
if(mMsgConvoList.size() > 0) {
List msgPartitions = daoMsg.partitionArray(mMsgConvoList, 3);
mAdapter = new CustomPagerAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mAdapter);
for(int i = msgPartitions.size() - 1; i >= 0; i--){
//extract msg objects from each sublist
List<Msg> msgSublist = (List<Msg>)msgPartitions.get(i);
int count = msgSublist.size() -1;
while(count >= 0){
if (count == 2){
mAdapter.addMessages(msgSublist.get(count));
mAdapter.notifyDataSetChanged();
mViewPager.setCurrentItem(mAdapter.getCount(), true);
}else{
mViewPager.setCurrentItem(mAdapter.getCount(), true);
MsgFragment currentFragment = (MsgFragment)mAdapter.getFragmentAtPosition(
mAdapter.getCount() - 1);
currentFragment.addMessage(msgSublist.get(count));
}
count--;
}
I'm trying to download some data from a server : a list of products and associate icons. This two are in two differents services.
In the class RPCS.java {list of products}, I have :
public void importPCR() {
final List<PriceCollectRow> priceCollectRows = mWebServices.getPriceCollectRows(mApplicationProperties.getProperty("store_id"));
final ContentValues[] pcrAsContentValues = pcrToContentValues(priceCollectRows);
int k = mContext.getContentResolver().delete(PriceCollectRowContract.CONTENT_URI, null, null);
mContext.getContentResolver().bulkInsert(PriceCollectRowContract.CONTENT_URI, pcrAsContentValues);
}
This work fine (k = 35).
In the RIS.java {icons}:
public void download() {
List<Integer> artList = new ArrayList<>();
artList.add(101640);
final List<Image> images = mWebServices.getImages(artList);
final ContentValues[] imagesAsContentValues = imagesToContentValues(images);
int m = mContext.getContentResolver().delete(ImageContract.CONTENT_URI, null, null);
int l = mContext.getContentResolver().bulkInsert(ImageContract.CONTENT_URI, imagesAsContentValues);
}
m = 0 (doesn't work), and l = 1.
So, this two are very similary, but only one work.
Have you any idea why ?
EDIT :
Found : I didn't implement the delete method in my ImageProvider (noob)
Thanks to zozelfelfo, I have to implement the delete method in my ImageProvider
I have a ListView with each row containing a TextView. On user click, I'm getting the value of the TextView and storing it in a String variable, and the user is navigated to another activity where he / she needs to input some data on said TextView. In order to not lose the information state of the first activity, I had to use startActivityForResult() and later get the information from the second activity with the method onActivityResult().
The problem is this: I need to compare a value with that of the TextView in question, however the String variable which supposedly contains the TextView's value is null.
Before starting up the second activity I toasted the String value and it returned the correct string, however not in the onActivityResult(), where it returns null.
Why is this happening? Isn't the Intent I used suppose to retain all information of the opened activity?
ListView's onItemClick
#Override
public void onItemClick(AdapterView<?> listView, View itemView, int itemPosition, long itemID)
{
clickedError = ((TextView)itemView).getText().toString();
String errorIDQuery = "SELECT _id FROM " + TABLE_ERROR + " WHERE error_description LIKE '" + clickedError + "';";
Cursor getErrorID = db.rawQuery(errorIDQuery, null);
getErrorID.moveToFirst();
errorID = getErrorID.getInt(0);
Intent intent = new Intent(Repair.this, Material.class);
intent.putStringArrayListExtra("materialList", materialList);
startActivityForResult(intent, 1);
Toast.makeText(getApplicationContext(), clickedError, Toast.LENGTH_LONG).show();
}
onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(resultCode == RESULT_OK)
{
#SuppressWarnings("unchecked")
HashMap <String, String> materialDetails = (HashMap <String, String>)data.getSerializableExtra("map");
Set<?> set = materialDetails.entrySet();
Iterator<?> i = set.iterator();
ArrayList<String> materialNames = new ArrayList<String>();
ArrayList<String> materialAmounts = new ArrayList<String>();
do
{
#SuppressWarnings("rawtypes")
Map.Entry me = (Map.Entry)i.next();
materialNames.add(me.getKey().toString());
materialAmounts.add(me.getValue().toString());
}
while (i.hasNext());
for(Error e : errorList)
{
// ----- COMPARING THE VALUES -----
// here clickedError is null
if(e.description.equals(clickedError))
{
for(int j = 0; j < materialNames.size(); j++)
{
MaterialClass mc = new MaterialClass();
mc.setName(materialNames.get(j));
mc.setAmount(Integer.parseInt(materialAmounts.get(j)));
e.materialList.add(mc);
}
if (e.materialList.size() != 0)
e.checked = true;
else
e.checked = false;
}
}
My guess: the activity is destroyed and restarted while moving to the second activity. This is easy to confirm with log messages in the activity life cycle methods(onCreate/onRestart/etc).
The following link might be of use to persist data during activity switching: http://developer.android.com/training/basics/activity-lifecycle/recreating.html
Make your String value as static so that it will retain its value. or you can use shared preference to save value and use it later.
This is working if its not ask me
TextView textviewDate=(TextView)findViewById(R.id.yourtextviewid);
clickedError=textviewDate.getText().toString();
Searched and working on this a long while - no luck. ( It must be simple ? Thanks for the assist. )
Trying to get / set a screen full of EditTexts' text, but not with the usual, more hard-coded way:
... findViewById (R.id.SomeTextWidgetId) ;
Instead, I'm trying to figure out a reusable way via a variable holding the (String) name_of_widget.
In psuedo code:
findViewById (R.id.>> StringVarHere << ); // how to do that ?
I tried also this findViewById method, but it didn't work (!?)
//// given:
static final String FIELD_TV_FEE = "TextViewFee" ;
static final String FIELD_TV_FOO = "TextViewFoo" ;
static final String FIELD_TV_FUM = "TextViewFum" ;
//// and some arbitrary number more of similar fields
static final String [] ALL_FIELDS = {
FIELD_TV_FEE ,
FIELD_TV_FOO ,
FIELD_TV_FUM // ...
} ;
//// ...
//// this part works
int ResourceID;
String stringVarHere = FIELD_TV_FEE;
//// outputs a correct id, say '0x7f05000f' as in R.id.xxx below
ResourceID = context
.getResources()
.getIdentifier ( stringVarHere,
"id",
context
.getApplicationInfo()
.packageName
) ;
Log.d ("MyClass" , "RESID = " + Integer.toHexString(ResourceID) ) ;
/*
* that's where I'm stuck ^^^ ... how do I do:
*/
String field_name ;
for ( field_name : ALL_FIELDS ) {
(EditText) SomethingLike_a_findViewById(field_name).setText ("Hello Wurld") ;
}
I've tried .setId ...
//// details
<!-- excerpt from working xml layout -->
<EditText
android:id="#+id/TextViewFee"
android:inputType="text"
android:layout ... etc ...
/>
<EditText
android:id="#+id/TextViewFoo"
android:inputType="text"
android:layout ... etc ...
/>
<EditText
android:id="#+id/TextViewFum"
android:inputType="text"
android:layout ... etc ...
/>
As expected, the gen'ed R file has something like this:
// ...
public static final class id {
public static final int TextViewFee=0x7f05000f;
public static final int TextViewFum=0x7f05001c;
public static final int TextViewFoo=0x7f05001d;
// ... etc
Yes, thanks - it makes sense to do it in the activity. I was trying to keep it from getting too code bulky. Here's what I'm doing now, based on your and A-C's helpful suggestions. The intention is to get all the text of fields of a form back in one String[]. (I know I could brute force all the fields too.)
What do you all think about this below - seems very similar to your suggestion, madlymad ? I am wondering if this is a poor design approach ?
public class FoodBar {
private Activity activity;
private Context ctx;
public FoodBar ( Activity _activity ) {
this.activity = _activity;
this.ctx = this.activity.getApplicationContext() ;
}
public String[] getTextFromAllEditTexts () { // the UI views
int res_id = 0;
int i = 0;
String [] retValues = new String [MyClassName.ALL_FIELDS_LENGTH] ;
for (String field : MyClassName.ALL_FIELDS_ALL_VEHICLES) {
res_id = this.ctx.getResources()
.getIdentifier ( field, "id", this.ctx.getPackageName() );
((EditText) this.activity
.findViewById (res_id))
.setText( "Meat and Potatoes" ) ;
// redundant - get it right back to make sure it really went in !
retVal[i++] = ((EditText) this.activity
.findViewById (res_id))
.getText().toString() ;
}
return retVal;
} // end func
} // end class
Then from the Activity class, it's just:
String [] theFields = null;
FoodBar = new FoodBar (this);
try {
theFields = FoodBar.getTextFromAllEditTexts ();
} catch (Exception e) {
Log.d ("OOPS", "There's a big mess in the Foodbar: " + e.toString() );
}
The way you could do it is (as I understand the way you are trying):
This can be in non-Activity (YourClassname.java):
public static int getMyId(Context context, String field) {
return context.getResources().getIdentifier (field, "id", context.getPackageName());
}
in Activity-class:
for ( String field_name : YourClassname.ALL_FIELDS ) {
int resid = YourClassname.getMyId(context, field_name);
if(resid != 0) { // 0 = not found
EditText et = (EditText) findViewById(resid);
if (et != null) {
et .setText ("Hello Wurld") ;
}
}
}
But I think it's better to code in the activity class like:
String packageName = getPackageName();
Resources res = getResources();
for ( String field_name : YourClassname.ALL_FIELDS ) {
int resid = res.getIdentifier (field_name, "id", packageName);
if(resid != 0) {// 0 = not found
EditText et = (EditText) findViewById(resid);
if (et != null) {
et .setText ("Hello Wurld") ;
}
}
}
A-C suggested something along the lines of:
res_id = getResources().getIdentifier (field, "id", getPackageName());
((EditText)findViewById (res_id)).setText("NoLongerFubar");
this DOES work - when I tried it standalone in a test rig. Thanks ! Still not sure what was blowing up, but I suspect it was Context or Resource items not being accessible.
Note that variable names (such as R.id.some_id) are only available at compile time and cannot be accessed from a String value at run time. Since these ids are declared as ints, you might consider using an int[] or List<Integer> to store the ids. Depending on how dynamic your layout is and what you are doing with the Views in it, you might even want to simply create the Views at run time and store an array or List of them without using any ids at all.
I have two identical views with a number of editTexts. In one, pre-defined answers are populated in the editTexts (but not shown to the user). In the second, the user starts with all blank editTexts, and then fills them out in an attempt to make them the same as the pre-defined answers.
So I want to loop through the user's view, checking it against the pre-defined one, until an inequality is found, in which case the method will return false.
My code is below. Inside the onCreate I have a buttonListener (when the user is ready to check answers)
btnSolution.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(checkAnswer() == true){
Toast.makeText(getBaseContext(), "all good!", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(getBaseContext(), "no good", Toast.LENGTH_LONG).show();
}
}
});
the checkAnswer() method is then defined as follows
public boolean checkAnswer() {
final int ROW_COUNT = 15;
final int COL_COUNT = 10;
final String ROWS[] = {"R1","R2","R3","R4","R5","R6","R7","R8","R9","R10","R11","R12","R13","R14","R15"};
final String COLS[] = {"C1","C2","C3","C4","C5","C6","C7","C8","C9","C10"};
for(int i=0; i<ROW_COUNT; i++) {
for(int j=0; j<COL_COUNT; j++) {
String a = ROWS[i];
String b = COLS[j];
int editTextBaseId = getResources().getIdentifier("box" + a + b, "id", getPackageName());
int editTextAnswerId = getResources().getIdentifier("boxA" + a + b, "id", getPackageName());
EditText editTextBase = (EditText)findViewById(editTextBaseId);
EditText editTextAnswer = (EditText)findViewById(editTextAnswerId);
String textBase = editTextBase.getText().toString();
String textAnswer = editTextAnswer.getText().toString();
if(textBase.equals(textAnswer)) {
}
else {
return false;
}
}
}
return true;
}
Unfortunately when I try and run this I am getting a crash and the following error in my LogCat
12-17 00:05:02.075: E/SKIA(16370): FimgApiStretch:stretch failed
Any obvious errors?
That's not an error itself. I guess you're using a Samsung as your target device, if so, don't worry about it.
In the other hand, maybe it's better to compare only the strings. All those findViewById are inneficient.
Looking at your code:
EditText editTextAnswer = (EditText)findViewById(editTextAnswerId);
Do you have both views in the same layout, and the one with the answers is hidden? I mean, if you have the view with blank editTexts as the content of your activity, you can't find the editText with the answer as it's in other xml (assuming you did it as a different xml).