In my app i have a tab layout (4 total), each tab contain a ListFragment managed by a ViewPagerAdapter, what i want to do is update the content of one of these ListFragment when an activity (called with a button in the Action bar) finishes, and possibly set the focus on the right Tab.
I've searched for a solution and i have found this one : update ListFragment when Activity finishes , but seems doesn't works in my case.
For start the activity (the one for adding an user to display in the list) in the MainActivity i've used:
Intent intent = new Intent(this, CreateUser.class);
startActivityForResult(intent, 101);
At the end of the CreateUser activity i've set:
setResult(Activity.RESULT_OK);
finish();
And in the ListFragment class:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if ((requestCode == MYACTIVITY_REQUEST_CODE) && (resultCode == Activity.RESULT_OK)){
((BaseAdapter)adapter).notifyDataSetChanged();
}
}
But when the activity finishes nothing happens because onActivityResult is never called. How can i do?
EDIT : Added class for best understanding
CreateUser.java
public class CreateUser extends AppCompatActivity {
//The user creation process is done inside class ProcessCreateUser
//that extend AsycTask
private class ProcessCreateUser extends AsyncTask<String, String, JSONObject> {
//...
//onPreExecute, doInBackground
//...
#Override
protected void onPostExecute() {
super.onPostExecute();
//db op...
//at this point the db is updated with the new user and close the activity
finish();
}
}
public void onDestroy(){
Tab3.updateFragmentList();
}
}
Tab3.java (ListFragment class)
public class Tab3 extends ListFragment implements Observer
{
//in onActivityCreated(Bundle savedInstanceState) i get the data from the db and set the adapter
#Override
public void update(Observable observable, Object data) {
}
public static void updateFragmentList() {
//problem: i can't get the adapter from a static function
//but this must be static for be called from CreateUser
((BaseAdapter)adapter).notifyDataSetChanged();
}
}
I think you can use Observer pattern. For example:
public interface Observer {
public void updateFragmentList();
}
public class YourFragment extends Fragment implement Observer {
public void updateFragmentList() {
// You do some magic code here, such as:
// Update your data for each FragmentList
}
}
public class YourActivity extends Activity {
private ArrayList<Observer> observers = new ArrayList<Observer>();
public void onCreate() {
// Here you add all FragmentList to observers
}
public void onDestroy(){
for(Observer ob in observers) {
ob.updateFragmentList();
}
}
}
I finally got it (without Observer), i've moved the onActivityResult method from ListFragment to MainActivity, in the ListFragment i've added a simple public void updateView() method for all the update jobs of the list, and i've added the following method into the ViewPagerAdapter for call the updateView() method:
#Override
public int getItemPosition(Object object) {
if (object instanceof Tab3) {
((Tab3) object).updateView();
}
return super.getItemPosition(object);
}
Related
I have an EditText on Activity2 and whenever a Button is clicked I have to send what is written in the EditText to a certain Fragment of another Activity1.
I tried to send the data from the Activity2 to Activity1 but then I have to send it again from the Activity1 to the Fragment.
Is there any way to send the data directly from Activity2 to Fragment in the Activity1?
create an interface in your Activity2:
public interface OnEditTextData{
public void sendEdtData(String str);
}
and Attach the interface in it's oncreateView():
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
try{
mFragment fragment = new mFragment();
onEditTextData= (OnEditTextData) fragment ; \\ update this line
}catch(ClassCastException ex){
Log.e("Activity2","error"+ ex);
}
}
then init your interface method :
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onEditTextData.sendEdtData(editText.getText().toString());
}
});
then implements Your Fragment from Activity2.OnEditTextData interface :
public class mFragment extends Fragment implements Activity2.OnEditTextData {
.
.
.
#Override
public void sendEdtData(String str) {
// use your string
}
}
You can use the intent with startactivityforresult method also from fragment
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}.
or you can use a static variable you can declare inside activity 1 and change its value from activity b and access from fragment.
you can simply use shared preference if you want the simple way, but not recommended though
I have not found a clear solution anywhere on stack for this.
Here's my basic set up
public class Activity1 extends AppCompatActivity
{
private OnAttributesUpdatedListener onAttributesUpdatedListener;
public interface OnAttributesUpdatedListener
{
public void onAttributesUpdated();
}
public void setTargetFragment(Fragment fragment)
{
this.onAttributesUpdatedListener = (OnAttributesUpdatedListener) fragment;
}
private void whenFinishedSomethingCallback()
{
onAttributesUpdatedListener.onAttributesUpdated();
}
}
public class Fragment1 extends Fragment implements Activity1.OnAttributesUpdatedListener
{
button.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view) {
if(rivalButtonClick == 0)
{
Activity1 activity1 = new Activity1();
activity1.setTargetFragment(Fragment1.this);
startActivity(new Intent(getActivity(), activity1.getClass()));
}
}
});
}
I get a null pointer exception and crashes on : onAttributesUpdatedListener.onAttributesUpdated(); because for some reason my listener never gets set properly. What's the proper way to do this?
You need to set the listener at start of the fragment onCreatView() or in onActivityCreated() only if the Desired Activity is a parent Activity of that particular fragment. Below is an example .
public class Activity1 extends AppCompatActivity {
private OnAttributesUpdatedListener onAttributesUpdatedListener;
public interface OnAttributesUpdatedListener {
public void onAttributesUpdated();
}
public void setListener(OnAttributesUpdatedListener onAttributesUpdatedListener) {
this.onAttributesUpdatedListener = onAttributesUpdatedListener;
}
private void whenFinishedSomethingCallback() {
if(onAttributesUpdatedListener!=null)
onAttributesUpdatedListener.onAttributesUpdated();
}
}
public class Fragment1 extends Fragment implements Activity1.OnAttributesUpdatedListener
{
#Override
public void onAttributesUpdated() {
// Do your stuff here
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
((Activity1)getActivity()).setListener(this);
}
}
Read about fragment Life cycle to make use of getActivity(). also remove the listener when fragment is destroyed .
Use LocalBroadcastManager for communicating between in case the Fragment exists in other Activity.
At first create an Interface like this:
public interface Listener{
void doSomething() }
Then implement this interface in your activity.
And also add
Listener listener
In your fragment
And in onAttach method in fragment use this
listener=(Listener)activity
Then call listener whenever you need .
I have an app which has one MainActivity and two Fragments. These fragments send argument to MainActivity this way:
Bundle args = new Bundle();
args.putLong("id",id);
sf.setArguments(args);
And then MainActivity takes argument in onCreate() method
protected void onCreate(Bundle savedInstanceState) {
private long wayId = getArguments().getLong("id");
}
How can I determine which fragment sent this argument to MainActivity ?
You can add another argument into the bundle like the tag of the fragment.
Bundle args = new Bundle();
args.putLong("id",id);
args.putString("fragmentTag", fragmentTag);
sf.setArguments(args);
and retrive the tag in your onCreate()
You can define a separate inrterface for every fragment
public class FragmentA extends Fragment {
public static interface FragmentAInterface {
void doSomething(String data);
}
}
public class FragmentB extends Fragment {
public static interface FragmentBInterface {
void doSomething(String data);
}
}
And then in your activity:
public class MyActivity extends AppCompatActivity implements FragmentA.FragmentAInterface, FragmentB.FragmentBInterface{
#Override
public void doSomething(String data) {
//Guaranteed to come from Fragment A
}
#Override
public void doOtherThing(String data) {
//Guaranteed to come from Fragment B
}
}
I have a fragment that throws an activity in which user can insert some details.
When the user terminate to fill data the activity close. Then the previous fragment is showed and I want it to be updated (with the data provided by user in the activity).
If it was an activity, instead of fragment, i could use this:
#Override
public void onResume(){
super.onResume();
recreate();
}
How to do the same with fragment?
You would override onResume in the Activity which this Fragment belong, and recreate (restarted) this Fragment in this Activity. For example
public class ActivityA extends Activity {
#Override
public void onResume() {
// here you can get the Fragment instance , so you can recreated this fragment here or invoke this fragment's function to set data or refresh data
}
}
You can throw an Activity in calling startActivityForResult (Intent intent, int requestCode) method in your fragment.
also you need to provide onActivityResult (int requestCode, int resultCode, Intent data) in your fragment,the data is in the Intent parameter.
public class YourFragment extends Fragment {
public void throwActivity() {
// start activity
Intent intent = new Intent();
intent.setClass(getActivity(), YourActivity.class);
int requestCode = 1;
startActivityForResult(intent,requestCode);
}
// callback
#Override
public void onActivityResult (int requestCode, int resultCode, Intent data) {
recreate();
}
public void recreate() {
// your refresh code
}
}
public class YourActivity extends Activity {
public void yourMethod() {
int resultCode = 2;
setResult(resultCode); // goback to your fragment with your data
}
}
Is it possible to call startActivityForResult() from a non-activity class to get the results?
Scenario is something like this:
I have a class NonActivity (it doesn't derive from Activity as its not a UI).
This class will have bunch of functions(steps basically) to run.
One of the steps requires to show UI(Activity) and then get the result (user enter something).
Then been able to use that data in next following steps.
How can this be achieved without deriving from activity class as I don't have UI component?
Also since I don't want to derive from activity class that means I cannot override OnActivityResult(). Where results actually come from?
startActivityForResult() is only available from real on-screen activities, since it is a method in, well, Activity. Please redesign your application so that the user interface is driven from activities.
On the other hand, if your non Activity class is initialized and used from an onscreen Activity, you could pass that instance of the Activity to your class as a parameter in the constructor and use it to launch other Activities.
Be careful though. Using this method increases the risk of a memory leak, as the external class (Utils in my example) might keep a reference to the Activity even after its gone.
If all you want to do is access data, then you could try writing it to SharedPreferences or a Database or some files and then using the application context (passed in via a constructor again) to read it. This reduces the risk of a memory leak. Something like:
MyApiClass myApiClass = new MyApiClass(getApplicationContext());
EXAMPLE CODE
Main Activity:
public class Main extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Utils util = new Utils(this);
util.startTest();
}
#Override
protected void onActivityResult(int arg0, int arg1, Intent arg2) {
Toast.makeText(this, "onActivityResult called", Toast.LENGTH_LONG).show();
super.onActivityResult(arg0, arg1, arg2);
}
}
Utils class (which launches for result):
public class Utils {
Activity activity;
public Utils(Activity ac) {
activity = ac;
}
public void startTest() {
Intent i = new Intent(activity, Test.class);
activity.startActivityForResult(i, 1);
}
}
Test Activity:
public class Test extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "Test", Toast.LENGTH_LONG).show();
this.setResult(Activity.RESULT_OK);
this.finish();
}
}
StartActivityForResult from a class using a fragment with no visible GUI. You might find something like this in a utility class.
see runGetUserAccount below. It creates its own fragment and executes a startActivityForResult. Then it has it's own onActivityResult.
public class MyGooglePlay {
private static final int CONNECTION_FAILURE_RESOLUTION_REQUEST = 31502;
private ActionBarActivity activity;
private FragmentManager fragManager;
public MyGooglePlay(ActionBarActivity activity) {
this.activity = activity;
this.fragManager = activity.getSupportFragmentManager();
}
/**
* Starts an activity in Google Play Services so the user can pick an
* account
*/
private String mEmail = "";
static final int REQUEST_CODE_PICK_ACCOUNT = 1000;
public void runGetUserAccount() {
if (TextUtils.isEmpty(mEmail)) {
// run this code in gui less fragment so we can pickup the
// on activity result from inside the mygoogleplay class.
Fragment f = new Fragment() {
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
String[] accountTypes = new String[] { "com.google" };
Intent intent = AccountPicker.newChooseAccountIntent(null,
null, accountTypes, false, null, null, null, null);
startActivityForResult(intent, REQUEST_CODE_PICK_ACCOUNT);
}
#Override
public void onActivityResult(int requestCode, int resultCode,
Intent data) {
if (requestCode == REQUEST_CODE_PICK_ACCOUNT) {
if (resultCode == Activity.RESULT_OK) {
set_Email(data
.getStringExtra(AccountManager.KEY_ACCOUNT_NAME));
// getUsername();
}
super.onActivityResult(requestCode, resultCode, data);
}
//this is to verify the fragment has been removed.
//you can log or put a breakpoint to verify
#Override public void onDestroy(){
super.onDestroy();
}
};
FragmentTransaction fragmentTransaction = this.fragManager
.beginTransaction();
fragmentTransaction.add(f, "getusername");
fragmentTransaction.commit();
}
}
/**
* #param mEmail
* the mEmail to set
*/
private void set_Email(String mEmail) {
this.mEmail = mEmail;
if (!TextUtils.isEmpty(mEmail)) {
// TODO notify caller email is ready;
// activity.onEmailReady(mEmail);
}
//we are done with the "getusername" fragment
Fragment f = fragManager.findFragmentByTag("getusername");
if (f!=null) {
fragManager.beginTransaction().remove(f).commit();
}
}
}
U should pass context as Activity,then u will get solution.
try this below code.it will work
In non Activity class
public class nonActivity {
public static void method(Activity activity)
{
Intent intent = new Intent(activity, SecondActivity.class);
activity. startActivityForResult(intent, REQUEST_CODE);
}
}
In SecondActivity
Intent intent = getIntent();
intent.putExtra("data", "data"); //here u can pass data to previous activity
setResult(RESULT_OK, intent);
finish();
In firstActivity
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
try {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
String status = data.getStringExtra("data");
//Do what u want with data
}
} catch (Exception e) {
System.out.println("=====Exception=====" + e.toString());
}
}
If you want the result back from the activity to your normal class, supposed it is a class with a custom adapter within it.
you cannot use startActivityForResult because you are not in an activity
what I did is that i launched the activity from the class with an intent. Then I calculated or did what I have to. From this activity I send the information to the main class supposed with a method MainActivity.the_method() and in the main activity I changed the custom adapter o did what I have to using the adapter object and calling adapter.getItem(position)
Hope this can give you an idea