I am trying to get a QR code to be encoded based on data collected throughout the other fragments and sent to the MainActivity. Then, at the end, I want to call getAllData(), which returns all data in one string. It will do this when a FloatingActionButton is clicked (fabGenerate). Currently, it will load the fragment, and when you click on the fab, it will go into the correct case (R.id.fabGenerate) and run until "//error here". Also, I do NOT get an error message, due to the crash only occurring on the emulator.
String data;
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.fabGenerate:
Activity activity = getActivity();
if (activity != null && activity instanceof MainActivity) {
data = ((MainActivity) activity).getAllData(); //error here
}
qrgEncoder = new QRGEncoder(data, null, QRGContents.Type.TEXT, ((MainActivity)getActivity()).getDimen());
break;
}
}
I have tried first having data within the qrgEncoder line, where it will only do
qrgEncoder = new QRGEncoder(((MainActivity) getActivity).getAllData(), null, QRGContents.Type.TEXT, ((MainActivity)getActivity()).getDimen());
This did not work, and would still crash ONLY when it was run, not built.
I have also tried using Toast.makeText's to print a line, which determined that the error is within this piece of code.
Related
I have an app that connects to bluetooth and displays information received.
when pressing back, the activity isn't killed and I can go back to the activity and everything is the same. The activity collects the data in the background and everything is okay
I have a button, that when pressed, kills all activities (including the activity that displays the data).
When I try to create that activity again, the data keeps coming, and I can still handle it and write it to a file, but it won't show it in the UI. It seems the setText function in the handler doesn't work after the activity is created the second time (setText does work outside of the handler).
The boolean value synced is true if the activity is created a second time.
This is OnCreate
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_admin);
loading_panel = findViewById(R.id.loadingPanel);
loading_panel.setVisibility(View.GONE);
connectionButton = (Button) findViewById(R.id.connection_button);
gsrTextView = (TextView) findViewById(R.id.gsr_textview);
emgTextView = (TextView) findViewById(R.id.emg_textview);
adxlTextView = (TextView) findViewById(R.id.adxl_textview);
fsrTextView = (TextView) findViewById(R.id.fsr_textview);
textviews_set=true;
if(synced)
{
setConnected(currMac);
manageConnection();
Button sync_button = (Button) findViewById(R.id.sync_button);
sync_button.setText(R.string.synced_text);
}
// more code
}
Implementation of OnBackPressed:
#Override
public void onBackPressed() {
Intent i = new Intent(AdminActivity.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);
}
This is (part of) the handler:
#SuppressLint("HandlerLeak")
public final Handler handler = new Handler() {
#Override
public void handleMessage(#NonNull Message msg) {
super.handleMessage(msg);
switch (msg.what) {
//a lot of code for other cases
case READ_SUCCESS:
String s = (String) msg.obj;
showData(s);
break;
}
}
}
This is (part of) showData:
private void showData(String s) {
// todo: 1.parse the json; 2.show data (json components) on the textViews
try {
//Log.d(LOG_TAG, "the new string is " + s);
JSONObject json = new JSONObject(s);
// Collect the sensors measurements
String gsrMeasure = json.getString("gsr");
String emgMeasure = json.getString("emg");
String adxlMeasure = json.getString("adxl");
String fsrMeasure = json.getString("fsr");
String time_str = json.getString("time");
// Show the data
if(textviews_set) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(LOG_TAG, "ABOUT TO SET TEXT");
gsrTextView.setText(gsrMeasure);
emgTextView.setText(emgMeasure);
adxlTextView.setText(adxlMeasure);
fsrTextView.setText(fsrMeasure);
}
});
}
//more code
}
}
I even made sure that I'm running the setText on UI thread even though it works on the first run of the activity without the runOnUiThread
I also thought that maybe the handler is called before the findViewByIDs are called but I used a boolean variable textviews_set to make sure it doesn't happen
It is worth mentioning that when I create the activity for the first time, the bluetooth device isn't connected and thus the handler isn't running, so there's a really good chance that the problem lies there. I just don't know exactly where, or how to solve it.
I found out what the problem was, if anyone gets stuck with the same issue.
I declared all the textviews as non-static, thus when creating the activity the second time, for some reason the handler still referred to the textviews of the first instance of the activity.
All I had to do was declare the textviews in the class as static, so when I create the activity for the second time, the textviews are already declared and refer to the actual textviews in the xml.
Based on the information provide the follow is the best suggestion.
So try the following in onCreate() before textviews_set=true;
gsrTextView.setText(" ");
emgTextView.setText(" ");
adxlTextView.setText(" ");
fsrTextView.setText(" ");
Hope this solves issue.
Reference:
How do I declare a TextView variable so that I can use it anywhere?
I'm new to Android Development and am trying to make a simple habit tracking app. The initial screen is a fragment called HabitFragment. It has a button that, when clicked, takes the user to an activity, called HabitDialogueActivity, where they create a new habit that they would like to keep track of. When the "done" button is pressed, I call the "finish()" method. In the app, this takes me back to the original screen. However, my code does not seem to continue as my log entries do not show up.
I have this onClickListener and some code after it, it is inside of my OnCreateView():
Button newHabitButton = view.findViewById(R.id.newHabitButton);
newHabitButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
goToDialogue();
}
});
if (HabitDialogueActivity.getHabitListSize() > habitListSize) {
Log.d("TAG", "adding to linearLayout, am in if statement");
habitListSize = HabitDialogueActivity.getHabitListSize();
Habit newHabit = HabitDialogueActivity.habitList.get(habitListSize - 1);
TextView text = new TextView(this.getContext());
text.setText(newHabit.habitName);
text.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(text);
} else {
Log.d("TAG", "habit list size not changed");
}
and this is my goToDialogue():
private void goToDialogue() {
Log.d("TAG", "HabitFragment goToDialogue");
Intent intent = new Intent(HabitFragment.this.getActivity(), HabitDialogueActivity.class);
startActivity(intent);
}
My HabitDialogueActivity just has a few text fields, an ArrayList of habits, and a "done" button which calls finish(). It takes me back to my HabitFragment, but the Log entries in the if statement that follow the setOnClickListener do not show in the log. Why doesn't the code in HabitFragment continue to execute after I leave HabitDialogueActivity?
I am new to this website, so I'm sorry if I've left anything out.
Put your code inside onResume to rerun it when you go back to previously screen and remove it from on Create View. onResume will run after oncreate when you open the screen for the first time.
Check the docs
https://developer.android.com/guide/components/activities/activity-lifecycle
#Override
public void onResume() {
super.onResume();
// put your code here...
if (HabitDialogueActivity.getHabitListSize() > habitListSize) {
Log.d("TAG", "adding to linearLayout, am in if statement");
habitListSize = HabitDialogueActivity.getHabitListSize();
Habit newHabit = HabitDialogueActivity.habitList.get(habitListSize - 1);
TextView text = new TextView(this.getContext());
text.setText(newHabit.habitName);
text.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(text);
} else {
Log.d("TAG", "habit list size not changed");
}
}
OnCreateView is only called when the Fragment is created. Since it wasn't destroyed when you navigated to the HabitDialogueActivity, OnCreateView isn't called again.
You can move your if statement inside the Fragment's onResume() method in order to check if new data is available each time you navigate back to the activity to which the Fragment is attached.
#Override
public void onResume() {
super.onResume();
if (HabitDialogueActivity.getHabitListSize() > habitListSize) {
Log.d("TAG", "adding to linearLayout, am in if statement");
habitListSize = HabitDialogueActivity.getHabitListSize();
Habit newHabit = HabitDialogueActivity.habitList.get(habitListSize - 1);
TextView text = new TextView(this.getContext());
text.setText(newHabit.habitName);
text.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
linearLayout.addView(text);
} else {
Log.d("TAG", "habit list size not changed");
}
}
I'm new to Android (just completed my first class) and am struggling with a memory leak issue that I'm not sure is a real issue or not. I've taken the sample code for reading the contacts database that can be downloaded via the "download sample" button on the Android Developer site here:
https://developer.android.com/training/contacts-provider/retrieve-details.html
The app runs fine on its own (API 22 or less due to the READ_CONTACTS permission changes). I want to use the main activity in the sample in my own app as a child of the main activity to pick a contact and pass back its URI to be used to store some custom contact info. I'm using startActivityForResult() tied to a menu icon to launch the activity as a child of my main activity. I've changed very little in the sample code aside from executing finish() when a contact is clicked rather than launching the detail activity in the sample app:
Original:
#Override
public void onContactSelected(Uri contactUri) {
if (isTwoPaneLayout && mContactDetailFragment != null) {
// If two pane layout then update the detail fragment to show the selected contact
mContactDetailFragment.setContact(contactUri);
} else {
// Otherwise single pane layout, start a new ContactDetailActivity with
// the contact Uri
Intent intent = new Intent(this, ContactDetailActivity.class);
intent.setData(contactUri);
startActivity(intent);
}
}
New:
#Override
public void onContactSelected(Uri contactUri) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setData(contactUri);
Log.d(LOG_TAG, contactUri.toString());
setResult(RESULT_OK, intent);
finish();
}
The UI functionality is working fine and I get the URI as expected on the callback. However, StrictMode is enabled and reports that there is a new instance of the child activity each time I call it. This doesn't happen in the original app even with multiple orientation changes. I've tried many things to eliminate this issue in my new app to no avail. Here's what I've tried so far:
I tried setting the intent flags FLAG_ACTIVITY_REORDER_TO_FRONT and FLAG_ACTIVITY_CLEAR_TOP.
I tried forcing garbage collection prior to each new call to the activity:
if (BuildConfig.DEBUG)
{
System.gc();
}
startActivityForResult(intent, 1);
I removed the fragment definition from the XML layout and replace any existing instance via the FragmentManager:
if (getSupportFragmentManager().findFragmentByTag(ADDCONTACTSFRAGMENT_TAG) == null) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.add_contacts_container, new AddContactsFragment(), ADDCONTACTSFRAGMENT_TAG)
.commit();
}
I read that any listeners not re-initialized to null could cause a leak, so I've attempted to create a member variable for all of them and reset them in the onDestroyView and onDestroy methods of the child activity fragment:
#Override
public void onDestroy() {
super.onDestroy();
if (mCursor != null) {
mCursor.close();
mCursor = null;
}
mAdapter.swapCursor(null);
mAdapter = null;
mLoader = null;
mContext = null;
Log.d(LOG_TAG, "In onDestroy()");
}
#Override
public void onDestroyView() {
super.onDestroyView();
getListView().setOnItemClickListener(null);
getListView().setOnScrollListener(null);
mSearchView.setOnQueryTextListener(null);
if (Utils.hasICS()) {
// This listener added in ICS
MenuItemCompat.setOnActionExpandListener(mSearchItem, null);
}
mSearchTerm = null;
mSearchItem = null;
mSearchView = null;
//setListAdapter(null);
mView = null;
mOnContactSelectedListener = null;
mDialogClickListener = null;
mImageLoader.setPauseWork(false);
mImageLoader = null;
if (mAdapterView != null) {
mAdapterView.setOnItemClickListener(null);
mClickView.setOnClickListener(null);
mClickView = null;
mAdapterView = null;
}
Log.d(LOG_TAG, "In onDestroyView()");
}
I also found several examples of an unbindDrawables() method that was said to be necessary to remove all the View objects, but it doesn't work for an AdapterView, which this fragment is. Could this be the problem?
I've used both the Allocation Tracking tab in the Device Monitor and heap analysis via the stand-alone MAT application to verify that there are in fact multiple instances of the child fragment in memory, but I'm not sure at this point if this is really a leak or if garbage collection just won't remove the fragment instances until memory is constrained. Any advice would be greatly appreciated.
There is an Android library that could help to properly analyse memory leaks: leakcanary
Currently finishing up an app I have been working on but I'm kinda stuck on this last thing.
The app has 2 activities, one with buttons that are categories and the other shows the information according to the button pressed. For example if you click the button Fast food, it goes to the 2nd screen and displays info on that.
I'm trying to get a refresh button on the 2nd activity that will call a method in the 1st activity to refresh new information depending on the button pressed. The problem is that I don't know how to make it so the method keeps the same argument when called. What I mean is, if fast food was clicked, the refresh button would get new info that still relates to the fast food category.
Here's the relevant code in the Main activity:
public void yelpSearch(View view) {
switch (view.getId()) {
case R.id.button: buttoncategory = "Restaurant";
break;
case R.id.button2: buttoncategory = "Chinese restaurant";
break;
case R.id.button3: buttoncategory = "Fast Food";
break;
and this on the 2nd Activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.refresh:
Refresh();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void Refresh() {
MainActivity mActivity = new MainActivity();
mActivity.yelpSearch();
}
I'm not sure what to put inside mActivity.yelpSearch();
I tried using (View view) but it'll say cannot resolve symbol view. And if I make a local variable for view, it'll say not initialized and I don't know what to set it as
Any help would be awesome, been googling on this for a while now and searched through tons of questions on here as well. I'm still new at this so bear with me
I think you want to pass data between activities?
First Activity(Send DATA):
String data="YourXXXdata"
Intent intent = new Intent(getBaseContext(), MainActivity.class);
intent.putExtra("DATANAME", data);
startActivity(intent)
second Activity(Receive DATA):
Bundle extras = getIntent().getExtras();
if (extras != null) {
String value = extras.getString("DATANAME");
}
The data now is in String value
*you have to put in data the value you need depend you preview select button.
Make your yelpSearch method static
and call it like this from 2nd activity MainActivity.yelpSearch();
I checked a string variable from web service every 15 min, if returns "0", then new layout open with new class. I want that if returns me different from "0" again main layout shown again. When I press back it shows whitout background music but I want it whole mainactivity and layout automaticly.
intent_second= new Intent(this, second.class);
if (str.equals("0")) {
startActivity(intent_second);
} else {
//Can I do something here for what I want?
qst.setText(str);
}
this is my code for showing second screen, what Can I do for my request with which class?
Can I do that from mainactivity (calling itself) or how can I send this variable to second class and how can I listen it and start again mainactivity?
if flag == 0 then start second activity and on second activity if flag == 1 then call finish() from second activity
onCreate() {
intent_second= new Intent(this, second.class);
if (str.equals("0")) {
startActivityForResult(intent_second,intent_code);
} else {
//Can I do something here for what I want?
qst.setText(str);
}
}
onActivityResult(Intent intent, code) {
if(code == intent_code) {
// update your main layout
String result=data.getStringExtra("result");
// here u get you data from second activity "result" is key and it should be used on second activity
}
}