onActivityResult not called in fragment dialog via custom adapter - android

Fairly new to Android. I've the following scenario:
App starts in Main Activity and here I add a fragment
In that fragment is a listview populated with a custom adapter, I am passing an instance of the FragmentActivity to the adapter.
Call:
ExpandableListAdapter listAdapter new ExpandableListAdapter(mContext, mActivity, listDataHeader, listDataChild);
Implementation:
public ExpandableListAdapter(Context context, FragmentActivity activity, List<String> listDataHeader, HashMap<String, List<String>> listChildData) {
this._context = context;
this._activity = activity;
this._listDataHeader = listDataHeader;
this._listDataChild = listChildData;
}
When you click an item in the list, it opens a dialog with edittext fields namely: Name, Surname, Cell. I am passing the FragmentActivity to the dialog as the context:
txtListChild.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Dialog dialog = new SelectContactDialog(_activity);
dialog.show();
}
});
Then when you focus any of the 3 fields a Select contact opens up, I am using the passed FragmentActivity to call startActivityForResult like so:
private class ContactListener extends Activity implements View.OnFocusChangeListener
{
#Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
_activity.startActivityForResult(intent, CONTACTS_RESULT);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CONTACTS_RESULT && resultCode == RESULT_OK) {
String cell = "?", firstName = "?", lastName = "?";
uriContact = data.getData();
Cursor cursor = null;
mCell.setText(cell);
mLastName.setText(lastName);
mFirstName.setText(firstName);
}
}
}
Everything works fine up until this point. So my problem now is I would like to get the results when a user selects a contact. I tried below but the onActivityResult override method is never called. I've no idea what to do and seems that other people have had a different from mine and their solutions doesn't work for me.
Anyone know what I can do?

I'd recommend to use an interface for this. For example create the interface ContactCallback which you have to implement in your activity. When you create your adapter, pass this (which means the interface). When you click on an item call inside your adapter the passed callback like callback.onContactSelected(). Inside onContactSelected() which is implemented in your activity you can open your dialog.
Update:
To your problem that your onActivityResult() is never called:
Is there a line in your manifest called "android:launchMode="singleTask"? Remove it and it should be called. Following cases can cause an issue with receiving the result:
check you are using startActivityForResult() correctly, do not use startActivity().
if you do something in overriden onBackPressed method, super.onBackPressed(); has to be positioned at the last of the method, not at the first line.
remove android:launchMode="singleInstance" in manifest or equivalent argument to create a intent.
remove noHistory="true" in manifest of the called activity.
check setResult() is missed.
finish() is called to close the activity. use finishActivity() to close called activity.
use requestCode more than zero. negative value does not work.

You need to call this to get your onActivityResult called. on your dialog while your are closing put this code
Intent returnIntent = new Intent();
returnIntent.putExtra("result",result);
setResult(Activity.RESULT_OK,returnIntent);
finish();

Related

Correct way to refresh a ListView adapter in Android

I have a list of items. I have a button that sends you to another activity in order to create a new item. When the new item is saved an intent sends you back to the activity with the list where the new item should be added. The adapter extends from BaseAdapter without filtering, it just sets the data to the views.
My code is this:
onCreate(){
ListView listView = findItemById......
listView.setListeners.......
}
onResume(){
data = getData();
adapter = new ListAdapter(context,data);
listView.setAdapter(adapter);
}
It works but is this correct?
Can I use creation of adapter and setAdapter in onCreate and use notifyDataSetChanged() only in onResume somehow?
I think the correct way to do it is a use
startActivityForResult(...)
method to launch your Second activity (where your new items is added).
And in your second activity use
setResults(RESULT_OK or RESULT_CANCELLED)
(diffrent result when new items is added or user just back to prev screen).
Then in your ListAdapter class add method
public void updateData(List data) {
this.data = new ArrayList<>(data);
notifyDataSetChanged();
}
And call it in your onActivityResults(...)
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == YOUR_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
adapter.updateData(...your data from result Intent, or from anywhere else...);
}
}
Also i strongly recommend you to use RecyclerView instead of ListView
UPD: to answer your question - i think that biggest mistake in your code, is to create new instance of ListAdapter object in onResume() method, when it's not necessary
Add this method to your adapter and then call it with new data using adapter.udpateData(data):
public void updateData(List data) {
this.data = data;
notifyDataSetChanged();
}
Also, you can use notifyItemRangeInserted(0, data.size())
Hi OnActivityResult read all data create the new object and add to the list and call notifyDatasetChanged() , i will automatically refresh ui

delete item from Activity after receive it in Fragment / Lifecycle issue

I need some help. I've got activity where I create item. Next I want to send it to the fragment in second activity so I need to firstly send it to that Activity (am I correct ?). This is how I create item :
public void savePart() {
Part part = new Part(name,quantity,"","",tag,"","2");
Intent intent = new Intent(this,InvActivity.class);
intent.putExtra("Part", (Serializable) part);
setResult(2,intent);
finish();
}
This is how I receive it in second activity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == 2) {
part = (Part) data.getSerializableExtra("Part");
}
}
I've got method to return the part in fragment :
public Part getMyData() {
return part;
}
In Fragment's onResume() I receive the Part object, check if object with similar code exists and add it to the ListView if not:
#Override
public void onResume() {
super.onResume();
List<Part>subList = new ArrayList<>();
if (mActivity.getMyData() != null) {
Part part = mActivity.getMyData();
for(Part parts : mParts) {
if (parts.getCode().contains(part.getCode())) {
subList.add(parts);
}
}
if (subList.size() == 0) {
mParts.add(part);
adapter = new PartAdapter(getContext(), R.layout.part_item, mParts, mActivity, new AdapterCallback() {
#Override
public void onMethodCallback() {
}
});
mPartsLV.setAdapter(adapter);
} else {
Toast.makeText(getContext(), R.string.equipment_exists, Toast.LENGTH_SHORT).show();
}
}
}
So far everything works well. items are added correctly and shown in ListVIew in fragment.Here is where the problem begins :) In listView row I've got imageView which deletes item from ListView.
mDelete.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mParts.remove(part);
notifyDataSetChanged();
}
});
That works great to but ... when fragment comes back to onResume() deleted item shows again is ListView. That is because each time I receive Part and check if exists in List. I think I should somehow clear intent after receiving Part from Activity where Part was created but I don't know how ? Maybe any other solution,please ?
Declare your subList as public and populate it once. So you need to modify your onResume function a bit. Check if the list is populated already. If not, populate the list from the extras and vice versa.
ListsubList = new ArrayList<>();
your list is created every time when onResume() called that's why delete entries could not managed. So either take a copy of this list or every time check which elements got deleted,and then set data to listview.

Updating list in one class after action in another

I have a problem where by I have two activities, activity 1 and activity 2. Activity 1 contains a listview of contents in my SQLite database, activity 2 contains a button that when pressed preforms a query on the database. This query when run will alter the information in activity 1's list.
When I press the button the query works fine but the listview in activity 1 does not get updated. I know I have to use notifyDataSetChanged on the listview in order to have the list information updated.
My problem is how do I call this method on the list in activity 1 from the button listener in activity 2?
Listview and adapter in activity 1
String[] columns = new String[] {adapter.KEY_CONTENTS_NAME, adapter.KEY_CONTENTS_MEASUREMENT, adapter.KEY_CONTENTS_UNIT};
int[] to = new int[] {R.id.ingredientName, R.id.ingredientMeasurement, R.id.ingredientUnit};
SimpleCursorAdapter myCursorAdapter = new SimpleCursorAdapter(this,R.layout.row2, cursor, columns, to, 0);
ListView ingredientList = (ListView) findViewById(R.id.ingredientList);
ingredientList.setAdapter(myCursorAdapter);
Button in activity 2
Button cookButton = (Button) findViewById(R.id.cookButton);
cookButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//simple SQL query
//call to activity 2 to update the list
}
});
You can use startActivityForResult to achieve this.
In your first activity when you want to start the second activity like this using startActivityForResult.
Intent myIntent = new Intent(FirstActivity.this, SecondActivity.class);
int FIRST_ACTIVITY_CODE = 100
startActivityForResult(intent, FIRST_ACTIVITY_CODE);
In your second activity when doing the click you want to setResult okay and then quit the activity to return to the first activity.
Button cookButton = (Button) findViewById(R.id.cookButton);
cookButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//simple SQL query
setResult(RESULT_OK);
finish();
}
});
In your first activity you have to override onActivityResult and then update your list.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FIRST_ACTIVITY_CODE) {
myCursorAdapter.notifyDataSetChanged();
}
}
So you can communicate with activities by using onActivityResult. If you want to pass the data you got back from your SQL query in the second activity to your first activity you can use setResult(int resultCode, Intent data)
Then write this function in your list activity:
#onResume
public void onResume(){
super.onResume();
myCursorAdapter.notifyDataSetChanged();
}
As you go back to that activity, this function will be called and you can notify about the changes here by calling notifyDataSetChanged.
You could start activity using startActivityForResult. Here is the documentation and an example: http://developer.android.com/training/basics/intents/result.html
On the first activity you should have something like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// load data from db
// add data to the list view (create a new adapter or clear the items from the old one and add the new items)
// notifyDataSetChanged on adapter
}
}
}
Before calling notifyDataSetChanged. Load again info from db (and check if it was updated) and add it to the list view. Then call notifyDataSetChanged

onActivityResult not beeing called

First I think I should describe my problem:
I want to do a BluetoothRequest for turning it on, but I don't want to create a new Activity. I want to keep it in the MainActivity and put the code in subclasses. How is this possible? Down is my own idea of how to do it, but it don't works.
I have the MainActivity and a BluetoothActivity. The following code is from BluetoothActivity:
public class Bluetooth extends Fragment{
private Context context;
private TextView textView;
private final int REQUEST_ENABLE_BT = 1;
private String BtName;
private String BtAddress;
private BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
public Bluetooth(Context context){
//constructor
this.context=context;
textView = new TextView(this.context);
}
public boolean bluetoothUnterstuetz(){
if(mBluetoothAdapter == null) {
//Device doesn't support Bluetooth
textView.setText("Device doesn't support Bluetooth");
}
return true;
}
public void bluetoothActivate(){
if(mBluetoothAdapter.getState()== BluetoothAdapter.STATE_ON){
textView.setText("Bluetooth already on.");
}
if(!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
((Activity) context).startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
((Activity) context).setContentView(textView);
}
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
textView.setText(resultCode);
Log.i("bluetooth", "called");
((Activity) context).setContentView(textView);
}
With extends Fragment nothing happens, also logcat is empty. With extends Activity, the app crashs after starting.
When I test the App on my Phone, I get the BluetoothRequest and can Choose my answer but afterwards the ContentView shows nothing, also Logcat stays empty
Somebody knows how to get the Result?
Well now it works.
The onActivityResult() has to be in the MainActivity. If I put it into the subclass it won't be called
You have forgotten tag override.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
AndroidStudio tells me the function onActivityResult is never used.
Using the annotation #Override will make this warning to disappear. It is also a good way to check you overrided properly (with the right parameters in the right order) as you will get an error should the override be wrong. Which doesn't look to be the case here if you extended Activity.
When I test the App on my Phone, I get the BluetoothRequest and can Choose my answer but afterwards the ContentView shows nothing.
Are you sure your startActivityForResult() was called and returned a result (ie. didn't call finish() for example)? I'll update my answer according to the details you will provide.
onActivityResult is a protected method of Activity and a public method of Fragment. If ide is warning you that the method is never used is because your class does not extend neither Activity nor Fragment

Coming back from intent, do something

I have an android application which is using listView. After clicking on any item on the list it shows you AlertDialog where you can chose either edit or delete. After clicking edit it starts a new intent sending some extra strings to fill up the form for editing. I would like to refresh the list after I click on button save in that EditActivity.
I have read about notifyDataSetChanged() and I think it could work I just would like to know if there is any method which is in MainClass (listView class) and it is executed right after I came back from intent, right after clicking save button in EditActivity.
Or may I just add notifyDataSetChanged() method after I start an activity in the MainActivity?
public class yourClass extends ListActivity {
//define a class variable here.
private ArrayAdapter<Friend> adapter;
#Override
public void onCreate(Bundle savedInstanceState){
//Change this line setListAdapter(new ArrayAdapter<Friend>(this, android.R.layout.simple_list_item_1, db.getAllFriends()));
to
adapter = new ArrayAdapter<Friend>(this, android.R.layout.simple_list_item_1, db.getAllFriends());
setListAdapter(adapter);
}
#Override
public void onResume(){
super.onResume();
adapter.notifyDataSetChanged();
}
}
You can add listView.notifyDataSetChanged() in your activity onResume() function.
#Override
public void onResume(){
super.onResume();
yourListView.notifyDataSetChanged();
}
Use the method startActivityForResult() when opening your EditActivity then implement onActivityResult method in your main class. There you will be able to use notifyDataSetChanged
Read this from the doc
use startActivityForResult to call your EditActivity (this isn't simplest way to do what you want but is good way to do), by using this you can find out what is the result of your edit
Intent i = new Intent(this, EditActivity.class);
startActivityForResult(i, 1);
In your EActivity set the data which you want to return back to MainActivity
Intent returnIntent = new Intent();
returnIntent.putExtra("result",YOUR_RESULT); // skip if you do not want to return special result
setResult(RESULT_OK,returnIntent);
finish();
if you want to send cancel action (in your case fail edit) use this
Intent returnIntent = new Intent();
setResult(RESULT_CANCELED, returnIntent);
finish();
Now in your MainActivity class write following code for onActivityResult() method
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if(resultCode == RESULT_OK){
String result=data.getStringExtra("result"); // result sent from EditActivity
listViewAdapter. notifyDataSetChanged();
}
if (resultCode == RESULT_CANCELED) {
//Write your code if there's no result
}
}
}//onActivityResult

Categories

Resources