I have a dialogfragment that I use for the user to input information into. when the user clicks ok the info is passed back to the main activity through an interface where I attempt to put it into a database.
this is the dialog positive click code:
.setPositiveButton("Ok", new DialogInterface.OnclickListener(){
#Override
public void onClick(DialogInterface dialog, int which){
name = edittextname.getText().toString();
details = edittextdetails.getText().toString();
bundle.putString("name", name);
bundle.putString("detail", detail);
mListener.OnAddInfo(Bundle);
and on the mainactivity I implemented the interface and this in code:
public void OnAddInfo(Bundle bundle){
name = bundle.getString("name");
detail = bundle.getString("detail");
db.open();
long id = db.insertInfo(name, detail);
db.close();
Toast.makeText(this, "Added " + name, Toast.LENGTH_SHORT).show();
}
I know the data is being passed through because when I comment out the db parts the toast comes up correctly. I don't think there is a problem with my db because in other activities not using a dialogfragment it works fine. The error msg i get is this:
FATAL EXCEPTION: main
java.lang.NullPointerException at
android.database.sqlite.SQLiteOpenHelper
.getDatabaseLocked(SQLiteOpenHelper.java:224)
I have tried many things to fix this and just cant figure it out. Is this just something that isnt allowed or am I just missing something? The mainactivity is also a fragmentactivity.
I spent hours on this and gave up, only to accidentally discover a solution. Declaring the new database at the beginning of the DialogFragment class where you usually declare stuff doesn't work, but declaring it inside the onCreateDialog method works!
Example:
onCreateDialog(){
DatabaseHandler db = new DatabaseHandler(getActivity());
// use db now with no lock.
}
Related
I'm very new to Android, and have a basic question. I need at certain points to display a user notification in a dialog box, which they can simply acknowledge with the OK button.
I'm using:
myActivity.runOnUiThread(new Runnable() {
public void run() {
AlertDialog alertDialog = new AlertDialog.Builder(myContext).create();
alertDialog.setTitle("Alert");
alertDialog.setMessage("My message");
alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
alertDialog.show();
}
});
This works well in the Main program, but within a called method it needs the Activity and the Context from the main program. Can anybody tell me how to pass these? getApplicationContext() seems to be acceptable, but I can't figure out how to pass the Activity.
Better still of course would be to get the parent Context and Activity within the method, but I can't get that to work either.
I'd be grateful for any help.
-update 10/07/21
Rahul has given me the solution to the problem I posed: how to pass in the Activity and Context.
The problem is that the dialog still doesn't show.
I found a variation online as follows:
AlertDialog.Builder builder = new AlertDialog.Builder(myContext);
builder.setTitle("Alert")
.setMessage("My message")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
but this doesn't work either.
I'm puzzled that such a common and simple task needs so much code. In the desktop languages I'm used to it can be done in a single line.
So my titled question stands, but can anyone see where the code is faulty?
Many thanks
You can either pass activity to the class when initializing the object or you can pass activity when calling the function.
Case 1 (Recommended)
Pass Activity when calling the function:
MyObj myObj = new MyObj();
myObj.showDialog(myValue, ActivityName.this);
Where function will look like this:
public void showDialog(int myValue, Activity activity){
...
}
Then you can use this activity instance inside the method.
Case 2
Pass Activity when initializing the object:
MyObj myObj = new MyObj(ActivityName.this);
Where Class will look like this:
class MyObj{
private Activity thisActivity;
public MyObj(Activity activity){
thisActivity = Activity;
}
...
}
Then you can use this activity instance.
When you have activity object available you can replace context object with it.
I have a fragment that adds data to my database. When I close it with dismiss(), it returns to my activity. I want to then update my recyclerView in that activity.
My understanding of the activity lifecycle is that onResume should be called correct? I have a Log in my onResume method and as far as I can tell it is not being called.
What is the better solution, and why is this not being called?
onResume
#Override
public void onResume() {
super.onResume();
Log.e("Resume", "Resuming");
}
The button click listener in my fragment. The Log here works perfectly fine.
//save button for saving workouts
mButton2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String title = mEditText.getText().toString();
String category = mSpinner.getSelectedItem().toString();
String weight = mEditText2.getText().toString();
int icon = buildIcon(category);
//pass all the data into a new object for the Recycler View to store and show also refresh
db.addWorkout(new Workout(title, weight, "8/8/8", icon));
Log.e("Database Build", "Added a new workout: " + title);
dismiss();
}
});
The Activity was never paused when you started dealing with the fragment. onResume won't get called in that scenario and that's expected lifecycle behavior.
You should consider implementing some type of callback to let the Activity know when the Fragment has closed. The android documentation has a really good explanation of how to communicate with fragments. Use the pattern in the documentation and build yourself an OnFragmentClosedListener
I need to clear password field on exit of app,i am exiting the app in other activity and on exit it goes to mainActivity which has login details in which i need to clear password field,how will i do this in other activity ,i tried using setText("") but in vain.
public void backButtonHandler() {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(
ReminderActivity.this);
// Setting Dialog Title
alertDialog.setTitle("Leave application?");
// Setting Dialog Message
alertDialog.setMessage("Are you sure you want to leave the application?");
// Setting Positive "Yes" Button
alertDialog.setPositiveButton("YES",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
//I need to clear here all pwd data present in MainActivity in edittext
finish();
}
});
// Setting Negative "NO" Button
alertDialog.setNegativeButton("NO",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Write your code here to invoke NO event
dialog.cancel();
}
});
// Showing Alert Message
alertDialog.show();
}
In your MainActivity do like this:
#Override
public void onResume() {
super.onResume(); // Always call the superclass method first
editText.SetText("");
}
So, it will clear editText value, whenever your MainActivity will get resumed.
Or when you click the login button do
editText.SetText("");
Then it will be cleared before another activity starts
Using setText won't work and may even throw some type of NPE if your activity is no longer in memory.
There are a couple of ways you can do this depending on your requirements:
You can simply clear the text field in the activity/fragment's onStop or onDestroy overrides
If you absolutely have to set the text field from a different activity, then I suggest the following design:
In your Application class, create a nested class that implements ActivityLifeCycleCallbacks. This is a great class to implement as it allows you to monitor the state of all of your activities. It resolved a lot of problems for me
If you have a singleton model, or static String value that binds to your password TextView then you're almost there (other workarounds available if you give us more info).
So let's look at some code:
Design 1:
public void onStop()
{
super.onStop();
myTextField.setText("");
}
Your Application class:
public class MyApplication extends Application
{
...
private static final class MyActivityLifeCycleCallback implements ActivityLifecycleCallbacks
{
#Override
public void onActivityStopped(Activity activity)
{
//Here, I am assuming that your class name is MainActivity
Log.i(TAG, "onActivityStopped:" + activity.getLocalClassName());
if("MainActivity".isEqual(activity.getLocalClassName())
{
myDataModel.getInstance().setPassword("");
//or if your password String member is static
//((MainActivity)activity).myPasswordMember = "";
}
//Or if you want to only clear the password text when RAActivity stops, simply replace "MainActivity" with the RAActivity class name.
}
#Override
public void onActivityDestroyed(Activity activity,
Bundle savedInstanceState)
{
Log.i(TAG, "onActivityDestroyed:" + activity.getLocalClassName());
if(activity.getLocalClassName().contains("MySecondActivity"))
{
//reset your password here - implementation will depend on how you have your data model organized (private, singleton, static, etc.)
}
}
....
}
Remember that this design would work well with some type of a singleton or central data model (think MVC architecture) so that you can propagate the change in data to your components.
Hope it helps
EDIT:
I have added the code according to your comment. But to be honest, I think it's a better idea to simply call the setText("") method in the MainActivity's onStop function like I suggested. This is a simple problem and my second design might be a bit too much. Anyway, the code is updated, so if you like it, mark it as an answer :)
Here's another idea. IF RAActivity calls MainActivity again (probably not) using startActivity, you can simply pass a bundle value to MainActivity that tells it that it's coming from RAActivity. That way, MainActivity can clear the password if it was called from RAActivity. Lots of options.
I have an ArrayList which has objects of type Person. Person class has fields name, address1, address2, city, state, postcode and country. I want to be able to edit a particular person and then update the changes such that the ListAdapter which displays the Persons shows updated data. This ListView is contained in RecipientActivity (Activity A)
In the custom Adapter I start the Activity RecipientAddressActivity (Activity B) using an intent in the TextView's onClick event:
holder.txtRecName.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent rec_Intent = new Intent(context,
RecipientAddressActivity.class);
rec_Intent.putExtra("Current_Recipient",
recipientArray.get(index));
rec_Intent.putExtra("RecipientIndex",index);
context.startActivity(rec_Intent);
}
});
In the Activity B I get the Current_Recipient and the index in onCreate() event like this:
current_rec = (Person) getIntent().getSerializableExtra(
"Current_Recipient");
Recipient_Index = getIntent().getIntExtra("RecipientIndex", 151);
In the same activity, I have a button "Save" and on its Onclick I create a Person object which can be either a new Person or an old person being edited.
Button Save's onClick() event
{
Intent Recipient_info = new Intent();
Person recipient = new Person(edt_rec_name.getText().toString(),
edt_rec_addr1.getText().toString(),edt_rec_addr2.getText().toString(),
edt_rec_city.getText().toString(), edt_rec_state.getText().toString(),
edt_rec_pcode.getText().toString(), edt_rec_country.getText().toString());
Recipient_info.putExtra("Person", recipient);
Recipient_info.putExtra("RecipientIndex", Recipient_Index);
setResult(RESULT_OK, Recipient_info);
finish();
}
The problem is there are 2 ways of starting Activity B. I don't know where or how to catch the result when Actvity B is started using ListView's Adapter.
Please help me asap. Kindly let me know if some more code or explanation is required.
Thanks.
I have noticed that in your code:
you are not starting activity as activityForResult.
check that and try now! if you still face this problem than here are some links, that will be useful in your problem:
calling onActivityResult from CustomArray adapter
onActivityResult in not called in the class extended from ArrayAdapter
How to add item in Custom listView in onActivityResult method?
How to Call onActivityResult in adapter listview?
I did try the "fixed" jar here:
http://code.google.com/p/android/issues/detail?id=15394
and also reinstalled the SDK completely and neither approach still fixed the issue I have here. So is startActivityForResult just a no go from ListFragment?
Original post:
I have this ClientListView which is a ListFragment, that when the button on the action bar is clicked it takes what is selected in the ListFragment view and starts a new activity to edit the selected client (or if the other option is clicked a new client all together).
This all launches fine. The ClientListView fragment and the ClientDetailsFragment are replaced by my EditClientActivity FragmentActivity (which calls the ClientEdit fragment). This takes up the whole screen and creates a save/cancel button in the action bar.
The problem is that when the save is clicked, I cannot update my ListFragment with the newly created client or edited client. For completeness this is my calling order:
MainActivity FragmentActivity sets up the ClientListView ListFragment and the ClientDetailsActivity FragmentActivity (which has the ClientDetails fragment). Then the ClientListView ListFragment upon its new or edit client option being selected can startActivityForResult on the EditClientActivity (Which has the ClientEdit fragment in it).
The ClientEdit Fragment sets up the options menu for save cancel, once the save in the ClientEdit fragment is selected several things happen:
new client or edited client is saved to the database.
mEditListener.onEditComplete() is called. As the calling FragmentActivity EditClientActivity implements an onEditCompleteListener that i use onAttach in the ClientEdit fragment.
So then my EditClientActivity has the onEditComplete(long id) method:
public void onEditComplete(long id) {
Intent in = new Intent();
this.setResult(1, in); //just something to let the ClientListView that the client i saved refresh the list.
Toast.makeText(this.getBaseContext(), "Client Saved", Toast.LENGTH_LONG).show();
finish(); //go back to our listview and client details view
}
In my ClientListView (of type 'ListFragment') I have this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
this.setHasOptionsMenu(true);
//which columns to put as the cursor
String[] columns = new String[] { "firstname", "lastname" };
//how to post those columns into the layout. check client_row.xml for these ids
int[] to = new int[] { R.id.client_first_name_list_label, R.id.client_last_name_list_label};
myCursor = getClientsCursor(); //this is NOT closing the database connection if it does it gets an error
theClients = new SimpleCursorAdapter(this.getListView().getContext(),
R.layout.client_row, myCursor, columns, to);
setListAdapter(theClients);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case R.id.new_client:
// TODO: add recipe
showClientEdit(-1);
return true;
case R.id.client_delete:
// TODO: delete recipe
Toast.makeText(getActivity(), "Delete Client selected", Toast.LENGTH_LONG).show();
return true;
case R.id.client_edit:
if(mCurrentSelectedItemIndex!=-1)
showClientEdit(mCurrentSelectedItemIndex);
else
Toast.makeText(getActivity(), "Select client to edit!", Toast.LENGTH_LONG).show();
return true;
case android.R.id.home:
// TODO: Handle app icon click
Toast.makeText(getActivity(), "Home icon selected", Toast.LENGTH_LONG).show();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
void showClientEdit(long someId)
{
..do stuff to get the right client to pass to the intent
Intent intent = new Intent(getActivity(), EditClientActivity.class);
// Send the recipe index to the new activity
intent.putExtra(EditClientActivity.SELECTED_CLIENT, clientId);
startActivityForResult(intent, Activity.RESULT_OK);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
//never gets here :(
super.onActivityResult(requestCode, resultCode, data);
Toast.makeText(this.getListView().getContext(), "Result code: " +resultCode , Toast.LENGTH_LONG).show();
if(resultCode ==1)
{
myCursor = getClientsCursor(); //not sure if i need this for the next line or not, want my list to update with newly
//added client or edited client names etc...
theClients.notifyDataSetChanged();
Toast.makeText(this.getListView().getContext(), "Data set notified!!!" , Toast.LENGTH_LONG).show();
}
}
Is the issue is that my startActivityForRestult calls the EditClientActivity from a ListFragment? As far as I can tell never calls the onActivityResult. I provided all this information to try to figure out and get a handle on how Fragment/FragmentActivities and the like are all supposed to interact with each other. I am doing it this way from things I learned poking around tutorials, the developer guide etc. I am pretty happy with my progress but at a wall now...and probably realizing the way I am doing things is just not the right way...I would love to be enlightened. This is the hardest part of android to me is managing how all these activities and views interact with each other....
Are you using the compatibility library for Fragments?
There is an issue with the Compatibility package, onActivityResult within fragments is broken. Take a look here http://code.google.com/p/android/issues/detail?id=15394 . There you can also download a jar file with the fixed version.
I understand that this question is old, but I wanted to provide a solution for those that are hitting this question like I did when they were searching for why your onActivityResult is not running when the Intent is called from inside a fragment (ListFragment or regular Fragment will have the same result).
You must call your startActivityForResult from your main Activity. So make sure to call getActivity() when you call it from inside a fragment like this:
getActivity().startActivityForResult(Intent,ACTIVITY_INT);
Freaking figured this out. It was the way I was using the Result/request code:
startActivityForResult(intent, Activity.RESULT_OK);
was not the way to start it, added another number in there instead of Activity.RESULT_OK and it worked, I must of gotten confused.