Make AsyncTask inside fragment run after FragmentTransaction.commit() - android

I have a FragmentTransaction in the activity, and I want the AsyncTask to run in the fragment after fragmentTransaction.commit(). How do I make AsyncTask run after commit? Because AsyncTask runs 2 times before and after the commit. Can anyone help?
*note: AsyncTask run with String of the activities that I sent using FragmentTransaction
Activity :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menudisplay);
Bundle extras = getIntent().getExtras();
language = extras.getString("language");
lang_id = extras.getInt("id");
MyListFragment mylist = new MyListFragment();
FragmentTransaction fragmentTrans = getFragmentManager()
.beginTransaction();
mylist.language = language;
fragmentTrans.add(mylist, "language");
fragmentTrans.commit();
Log.d("tes", "data loaded");
}
Fragment :
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_menulist_overview, container,
false);
System.out.println("tes="+language+" sama ini = "+asdf);
onActivityCreated(inflater, container, savedInstanceState);
return view;
}
public void onActivityCreated(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
run();
}
public void run(){
Log.d("Test","How many called?");
if(language != null)
new loadcat().execute();
}

I didn't get the note you wrote but you can run the AsyncTask after you have .commit() the transaction simple by creating a public method inside of the fragment that executed you desired AsyncTask and to call it from the Activity at the desired point in code.
So for example if you crate this method inside the Fragment:
public void executeAsyncTask(String language, int lang_id)
{
...
asyncTask.execute(language, lang_id);
}
And in Activity, you can call this method:
...
fragmentTrans.commit();
Log.d("tes", "data loaded");
mylist.executeAsyncTask(language,lang_id);

As far as I know, commit execution callback is not exposed(or maybe even doesn't exist).
So the question is - when do you want to execute your AsyncTask?
If you want it to be executed once at the fragment creation, your code is right, except you should remove your explicit onActivityCreated() call from onCreateView like this:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_menulist_overview, container,
false);
System.out.println("tes="+language+" sama ini = "+asdf);
onActivityCreated(inflater, container, savedInstanceState); // REMOVE THIS LINE
return view;
}
onActivityCreated is a callback. Calling it explicitly cause double execution of your task

Related

Can't find where context is missing

I've been refactoring a previous project to use fragments instead of creating separate activities as a school assignment. I've been trying to find out where this error is for close to an hour now and no luck. I get context missing when I add this line canvas.setColor(color, position);
Here's the Main activity:
public class MainActivity extends AppCompatActivity implements PaletteFragment.SpinnerSelectedInterface {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PaletteFragment palette = PaletteFragment.newInstance();
Bundle bundle = new Bundle();
bundle.putStringArray(KeyData.PASS_COLOR, getResources().getStringArray(R.array.colors));
bundle.putStringArray(KeyData.PASS_POSITION, getResources().getStringArray(R.array.colorNames));
palette.setArguments(bundle);
getSupportFragmentManager().beginTransaction().add(R.id.palette_fragment, palette).commit();
}
#Override
public void setCanvasColor(String color, int position) {
CanvasFragment canvas = CanvasFragment.newInstance(null);
getSupportFragmentManager().beginTransaction().add(R.id.canvas_fragment, canvas).addToBackStack(null).commit();
canvas.setColor(color, position);
}
}
And here's the fragment:
public class CanvasFragment extends Fragment {
private TextView displayColor;
private View background;
public CanvasFragment() {
// Required empty public constructor
}
public static CanvasFragment newInstance(Bundle bundle) {
CanvasFragment fragment = new CanvasFragment();
fragment.setArguments(bundle);
return fragment;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_canvas, container, false);
displayColor = (TextView) v.findViewById(R.id.displayColor);
background = (View) v.findViewById(R.id.canvas_fragment);
return v;
}
public void setColor(String color, int position){
String[] names = getResources().getStringArray(R.array.colorNames);
displayColor.setText(names[position]);
background.setBackgroundColor(Color.parseColor(color));
}
I've tried override onAttach and onDetach on the canvas fragment and adding a message listener, but still get the error as well. Would appreciate anything that could steer me in the right direction.
Error
java.lang.IllegalStateException: Fragment CanvasFragment{69925d5 (240edefb-318c-4983-bd15-cf45142e849a) id=0x7f080047} not attached to a context.
When you call
getSupportFragmentManager()
.beginTransaction()
.add(R.id.canvas_fragment, canvas)
.addToBackStack(null)
.commit();
You're using commit(). As per its Javadoc:
Schedules a commit of this transaction. The commit does not happen immediately; it will be scheduled as work on the main thread to be done the next time that thread is ready.
So when you immediately call canvas.setColor(color, position) directly afterwards, the Fragment is not attached and it doesn't yet have a Context associated with it.
If you want the Fragment to be immediately added, you want to use commitNow(), which forces the transaction to happen immediately. This ensures that it'll be done before your setColor method is called:
getSupportFragmentManager()
.beginTransaction()
.add(R.id.canvas_fragment, canvas)
.addToBackStack(null)
.commitNow();

How do you pass an intent from activity to a fragment that is already opened

This is the answer that I got from other topic and applied it to my codes:
From Activity you send data with intent as:
Bundle bundle = new Bundle();
bundle.putString("edttext", "From Activity");
// set Fragmentclass Arguments
Fragmentclass fragobj = new Fragmentclass();
fragobj.setArguments(bundle);
and in Fragment onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String strtext = getArguments().getString("edttext");
return inflater.inflate(R.layout.fragment, container, false);
}
These are the codes that I applied, it is not working somehow. The fragment is already opened at the start.
public void onInfoWindowClick(Marker marker) {
if (tag.equals("Click to show all routes in this point")) {
Bundle bundle = new Bundle();
bundle.putString("route1", "Divisoria - San Juan");
// set Fragmentclass Arguments
hideShowFragment fragobj = new hideShowFragment();
fragobj.setArguments(bundle);
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction ft = manager.beginTransaction();
Fragment intersectionFragment = manager.findFragmentById(R.id.fragmentContainer2);
ft.setCustomAnimations(R.anim.fade_in, R.anim.fade_out);
ft.add(R.id.fragmentContainer2, fragobj);
ft.show(intersectionFragment);
ft.commit();
}
}
The codes in my onCreateView method:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_hide_show, container, false);
if (!routes.equals(none)) {
routes = getArguments().getString("route1");
} else {
routes = "Food";
}
return view;
}
What I want to happen is that the fragment will always update to what marker Tag that I click on the map. In other words, pass the string to the fragment (that is opened) and update it.
I do not want to use startActivityForResult because I can't move around the map if I don't use fragments. Is there a way to send result from activity to fragment that is already opened and running? If none, then how can I make the fragment not running from the start (using supportFragmentManager)? I only know is to hide it
If you have running Fragment and want to pass some data to it, you should create some way to communicate. For that purposes, you can use Observer pattern.
First of all create interface inside Activity if you want to pass data to Fragment:
public interface OnInfoClickedListener {
void onInfoClicked(String info);
}
Implement this interface inside Fragment:
#Override
public void onInfoClicked(String info) {
infoTextView.setText(info);
}
Now, inside your Activity, create variable to store this interface implementation:
private OnInfoClickedListener listener;
And when instantiating Fragment, save instance of it to variable:
InfoFragment fragment = InfoFragment.newInstance();
listener = fragment;
And when needed just provide data through this interface:
listener.onInfoClicked("Info - " + UUID.randomUUID());

Presenter in MVP(Android) gets deleted/gets null inside Fragment

I am using MVP. My activity contains one Fragment. I am initializing and then setting presenter to fragment inside Main-Activity's on Create method as follow.
public class MainActivity extends AppCompatActivity {
private StashPresenter stashPresenter;
private MainFragment mainFragment;
FragmentManager fm;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
App.getInstance().getAppComponent().inject(this);
setContentView(R.layout.activity_main);
fm = getSupportFragmentManager();
fm.beginTransaction()
.add(R.id.fragment_container, MainFragment.newInstance(),"mainFragment")
.commitNow();
mainFragment = (MainFragment) fm.findFragmentById(R.id.fragment_container);
stashPresenter = new StashPresenter(mainFragment);
mainFragment.setPresenter(stashPresenter);
}
Inside my mainFrgament class I am settinf Presenter in setPresenterFunction as follow.
public class MainFragment extends Fragment implements
StashContract.PublishToView {
public StashContract.ToPresenter forwardInteraction;
public void setPresenter(StashContract.ToPresenter forwardInteraction)
{
this.forwardInteraction = forwardInteraction;
}
Sometimes while performing searching operation as shown in my following code inside OnCreateView of mainFragment, I gets an error saying my forward
"Attempt to invoke interface method on a null object reference"
Sometime I get this error, sometimes I do not. I do not understand why this is happening
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_main, container, false);
unbinder = ButterKnife.bind(this, view);
searchView.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
progressBar.setVisibility(View.VISIBLE);
forwardInteraction.searchButtonClick(actionId, searchView.getText().toString());
return true;
}
return false;
});
String[] artistNames = getResources().getStringArray(R.array.artistNamesSuggestion);
ArrayAdapter<String> adapterArtist = new ArrayAdapter<>(getActivity().getApplicationContext(), R.layout.fragment_main, R.id.search_phrase, artistNames);
searchView.setAdapter(adapterArtist);
searchView.setThreshold(1);
recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new SpaceItemDecoration(space, space, space, space));
return view;
}
Solution
In the "onCreateView" method of the fragment, only initialize the views.
Move rest of the code in the "onResume" method.
Reason for error
Check this image
As you can see, "onCreateView" of your fragment is called when you are in the "onCreate" method in you activity.
In the current state of your code, there maybe times you when you will try to use the presenter before it is initialized.
Therefore, set your presented in the "onCreate" method of your activity and use it either it on the "onStart" or "onResume" of your fragment.
You can check this project to understand the MVP architecture more.

Android Fragment forgets button

My fragment initializes the button, i can see that in the debugger.
When i call the method setButtonText from the activity that has the fragment in it's layout, the button becomes null. I've looked on the internet but so far i didn't found any solution
public class PrepareTrainingFragment extends Fragment
{
private Button button;
private TextView tv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.preparetrainingfragment, container, false);
button=(Button) v.findViewById(R.id.ptfragmentbtn);
Log.w("button init","button init");
return v;
}
public void setButtonText(String text)
{
button.setText(text);
}
in the class that encapsulates the fragment:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); //hide navigation bar temporarily
driverFragment=new PrepareTrainingFragment();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, driverFragment);
driverFragment.setButtonText("hello");
}
A FragmentTransaction is not executed in real time, you have to call boolean result = fragmentTransaction.executePendingTransactions(); before updating your button. Also, why dont you update the button within your Fragment ?

using bundle to pass data between fragment to another fragment example

I have 3 sherlockListFragments in my app. Every fragment has some editTexts and the last fragment has a button which when it's pressed all data in the first and second fragments should be accessed and stored.
I used bundle to send data between fragments. with the simple following example,
This is the code of my first fragment :
public class PersonalDataFragment extends SherlockListFragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragmet_personal_data, container, false);
return v;
}
#Override
public void onCreate(Bundle savedInstanceState) {
PersonalDataFragment fragment = new PersonalDataFragment();
Bundle bundle = new Bundle();
bundle.putString("y", "koko"); //any string to be sent
fragment.setArguments(bundle);
super.onCreate(savedInstanceState);
}
}
and this is the code of the fragment that receives the text :
public class WorkExpRefFragment extends SherlockListFragment {
String myInt;
#Override
public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_workexp_ref, container, false);
final EditText t = (EditText) view.findViewById(R.id.editText5);
final Button generate = (Button)view.findViewById(R.id.button2);
generate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
t.setText(myInt + "sadfigha");
}
});
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
Bundle bundle = this.getArguments();
if(getArguments()!=null) {
myInt = getArguments().getString("y");
}
super.onCreate(savedInstanceState);
}
}
Now I have a null in the third fragment, what should i do ?
Thanks in advance
It's normal that your code fails. In the first fragment all you do is create a new instance of PersonalDataFragment and you pass it a Bundle with the data. The problem is although fragment holds the data in the Bundle, the fragment itself is not the one used by the app(isn't even attached to the Activity). You also set the Bundle on a PersonalDataFragment instance but you try to access the data in a WorkExpRefFragment which will obvious not work as the two fragments don't have a direct connection.
One simply solution for what you want to do is to let the Activity "save" the data for your fragments as the Activity is available for all fragments. First create two methods in the Activity holding the three fragments:
public void saveData(int id, Bundle data) {
// based on the id you'll know which fragment is trying to save data(see below)
// the Bundle will hold the data
}
public Bundle getSavedData() {
// here you'll save the data previously retrieved from the fragments and
// return it in a Bundle
}
Then your fragments will save their data like this:
public class PersonalDataFragment extends SherlockListFragment {
// this will identify the PersonalDataFragment fragment when trying to save data
public void static int id PERSONAL_ID = 1;
//...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle bundle = new Bundle();
bundle.putString("y", "koko"); //any string to be sent
YourActivity activity = (YourActivity) getActivity();
activity.saveData(PERSONAL_ID, bundle);
}
}
To retrieve the data in the WorkExpRefFragment fragment:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
YourActivity activity = (YourActivity) getActivity();
Bundle savedData = activity.getSavedData();
}
Depending on how you used those fragments this solution might not work. Also, keep in mind that the Bundle you pass like above will not be retained for a configuration change.

Categories

Resources