I am planning on having 3 fragmentlists contained within one activity. The goal is you select the talk option from the first list, then it transitions to the run list based on what you clicked in talk list, and then in the run list, based on what you click it will transition to the final eat list. Should this be happening in the fragments themselves(like i have it) or calling the activity to handle passing data back and forth to the fragments?
public class OptionsActivity extends Activity {
protected TalkFragment talk;
protected RunFragment run;
protected EatFragment eat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
talk = new TalkFragment();
run = new RunFragment();
eat = new EatFragment();
}
}
public class TalkFragment extends ListFragment {
private Cursor mCursor;
int mCurCheckPosition = 0;
#Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);
}
#Override
public void onListItemClick(ListView l, View v, int pos, long id) {
mCurCheckPosition = pos;
// We can display everything in-place with fragments.
// Have the list highlight this item and show the data.
getListView().setItemChecked(pos, true);
// Check what fragment is shown, replace if needed.
RunFragment run_frag = (RunFragment) getFragmentManager().findFragmentById(R.id.fragment_run);
if (run_frag == null || run_frag.getShownIndex() != pos) {
run_frag = RunFragment.newInstance(pos);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.details, details);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.commit();
}
}
}
This is obviously just snippits, but you get the idea. If I do it this way, I am not really sure how to pass certain parameters to fragment properly. Ideally, the RunFragment would know what to display based on the id of the item clicked in the TalkFragment. Should these be going through the Activity instead?
The way I typically do it is have the Activity be the traffic cop for handling the fragments. Your onListItemClick implementation could just tell the Activity what it wants to do:
public class OptionsActivity extends Activity {
protected TalkFragment talk;
protected RunFragment run;
protected EatFragment eat;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
talk = new TalkFragment();
run = new RunFragment();
eat = new EatFragment();
}
public void showRunFragment() {
showFragment(R.id.fragment_run);
}
public void showEatFragment() {
showFragment(R.id.fragment_eat);
}
public void showFragment(int fragmentId) {
// Check what fragment is shown, replace if needed.
...
}
}
public class TalkFragment extends ListFragment {
private Cursor mCursor;
int mCurCheckPosition = 0;
#Override
public void onActivityCreated(Bundle savedState) {
super.onActivityCreated(savedState);
}
#Override
public void onListItemClick(ListView l, View v, int pos, long id) {
mCurCheckPosition = pos;
// We can display everything in-place with fragments.
// Have the list highlight this item and show the data.
getListView().setItemChecked(pos, true);
getActivity().showRunFragment()
}
}
Related
I have a RecyclerView inside a AppCompatActivity. Item insertions and changes are shown and animated correctly after rotating the device.
The problem happens when you:
Tap on an item in the RecyclerView.
A DialogFragment opens prompting if you want to the delete the item.
Rotate the device.
Confirm the deletion in the dialog.
Check the array list. The item has been deleted.
The RecyclerView still shows the item.
Tried using notifyDataSetChanged instead of notifyItemRemoved but didn't work either because the item is still being shown in the RecyclerView.
This is happening with any version of Android.
Simplified code of how the process is being handled:
public class MyAppCompatActivity extends AppCompatActivity {
int positionOfDeletedItem;
MyObjectRecyclerViewAdapter adapter;
ArrayList<MyObject> someTestData;
MyItemDeletionHandler deletionHandlerRemover;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity_layout);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerview);
positionOfDeletedItem = 1;
deletionHandlerRemover = new MyItemDeletionHandler(this);
someTestData = new ArrayList<MyObject>(3);
someTestData.add(new MyObject("A"));
someTestData.add(new MyObject("B"));
someTestData.add(new MyObject("C"));
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
adapter = new MyObjectRecyclerViewAdapter(new MyAdapterOnClickEvent.OnItemClick() {
#Override
public void onClick(int posicion, int idViaje, View view) {
String tag = "Some tag value";
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
Fragment prev = getSupportFragmentManager().findFragmentByTag(tag);
if(prev != null)
ft.remove(prev);
ft.addToBackStack(null);
DialogFragment newFragment = MyDeletionConfirmationDialog.newInstance(deletionHandlerRemover);
newFragment.show(ft, tag);
}
}, someTestData);
recyclerView.setAdapter(adapter);
}
private final static class MyItemDeletionHandler extends Handler {
private final WeakReference<MyAppCompatActivity> theActivity;
private MyItemDeletionHandler(MyAppCompatActivity act) {
theActivity = new WeakReference<MyAppCompatActivity>(act);
}
#Override
public void handleMessage(Message msg) {
MyAppCompatActivity activity = theActivity.get();
if(activity != null) {
if(msg.what == 1) {
activity.deleteTheItem();
}
}
}
}
public void deleteTheItem() {
someTestData.remove(positionOfDeletedItem);
adapter.notifyItemRemoved(positionOfDeletedItem);
}
}
public class MyDeletionConfirmationDialog extends DialogFragment {
private Message handlerMessage;
public static MyDeletionConfirmationDialog newInstance(Handler callbackHandler) {
MyDeletionConfirmationDialog myDialog = new MyDeletionConfirmationDialog();
Bundle args = new Bundle();
args.putParcelable("handlerMessage", callbackHandler.obtainMessage(1, true));
myDialog.setArguments(args);
return myDialog;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handlerMessage = getArguments().getParcelable("handlerMessage");
}
#Override
#NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
alertDialogBuilder.setMessage("Some message");
alertDialogBuilder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
final Message toSend = Message.obtain(handlerMessage);
toSend.sendToTarget();
}
});
alertDialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
Dialog dialog = alertDialogBuilder.create();
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
}
How can I get the RecyclerView to work correctly?
Edit 1:
I have other RecyclerViews in which this works correctly. The only difference is those are inside Fragments instead of AppCompatActivity. I am suspecting that this has something to do with the events onDetachedFromWindow and onAttachedToWindow of the RecyclerView.
Edit 2:
If the dialog is closed (step 4) and opened again it works as expected.
Edit 3:
If the RecyclerView is extracted as a Fragment the problem disappears and works as intended. It is impossible to have the use case described above working correctly in conjunction with AppCompatActivity instead of a Fragment.
I was facing a similar problem with RecyclerView.
When I swiped left to delete an item and then rotate the screen, the item was removed from my dataset but the screen wasn't refreshing like it normaly does when we do the same action without rotating. It seems the adaptar.notifyItemRemoved() wasn't refreshing the screen at all.
I'm using the Nemanja Kovacevic source code as starting point, but I did some changes on it (like adding item click, edit with a dialog, database support, etc).
So I read this post which gave me a hint about what could be going wrong.
It seems the adapter.notify was still pointing to the previous adapter referece before rotation. Every time we rotate a new adapter is created at the Activity:OnCreate
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,
AddAlertDialog.OnAlertSavedListener,
AlertListAdapter.OnItemDeletedListener {
static ListAdapter mListAdapter;
RecyclerView mRecyclerView;
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
mRecyclerView = (RecyclerView) findViewById(R.id.mainListView);
mDB = new DatabaseTable(this);
// Reading all alerts
ArrayList<Alert> alerts = mDB.getAllAlerts();
if (mListAdapter == null)
mListAdapter = new ListAdapter(this, alerts);
}
}
Maybe it is not ideal (creating static objects is not a good idea), but it solved the problem.
I hope it may help you too.
I have and application in which I am using the Single activity and different fragments let say on activity start I call fragment A , and then after taking inputs I switch to fragment B and then Fragment C .
For Some reasons I have changed the Overflow Icon successfully from styles. But now The only problem is that for some reasons I want to show the overflow icons on Fragment B but not on Fragment A and C . for this I am doing this
public static void setOverflowButtonColor(final Activity activity, final int i) {
final String overflowDescription = activity.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
TintImageView overflow = null;
final ArrayList<View> outViews = new ArrayList<View>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
overflow = (TintImageView) outViews.get(0);
//overflow.setColorFilter(Color.CYAN);
overflow.setImageResource(R.drawable.my_overflow_image);
if (i == 1 && overflow!=null) {
overflow.setEnabled(false);
overflow.setVisibility(View.GONE);
} else if (overflow != null) {
overflow.setEnabled(true);
overflow.setVisibility(View.VISIBLE);
}
overflow.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(activity, "Overflow", Toast.LENGTH_SHORT).show();
}
});
removeOnGlobalLayoutListener(decorView, this);
}
});
}
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
}
else {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
}
So from Fragment A I am sending 1 in parameter so to hide the Icon but from Activity B I am sending 0 in parameter to re visible it , but it is not getting call.
Let me tell you this function working when it is called from Fragment A , I mean it is calling one time but not 2nd time or so on .
please tell me how to do this , if you know any other best method
Define an interface like below.
public interface FragmentHost{
public void onFragmentChange(int currentFragment);
}
Activity A should implement this interface.
class A extends Activity implents FragmentHost {
public static final int FRAGMENT_B = 0;
public static final int FRAGMENT_C = 1;
#Override
public void onFragmentChange(int currentFragment) {
if (currentFragment == FRAGMENT_A) {
// enable or disable button
} else if(currentFragment == FRAGMENT_B) {
// enable or disable button
}
}
}
And in each fragment . OnResume function call the onFragmentChange() method and pass the fragment id.
class B extends Fragment {
#Override
public void onResume() {
((FragmentHost) getParentActivity()).onFragmentChange(A.FRAGMENT_B);
}
}
I'm having a bit of trouble having the ViewPager displaying and running properly with a single fragment class.
So a bit of background. The Activity itself is supposed to allow users to answer questions in a survey. Each question consists of a question title, an input box, and a submit button. I've made a layout and a corresponding fragment (QuestionFragment) class to hold all of this.
My idea is to have the ViewPager hold a bunch of QuestionFragment's and the user will be able to swipe to the questions they would like to answer or edit. Basically each page will be using a QuestionFragment, but each will contain a unique question.
However my implementation doesn't look like its working out. The first page in the activity will have the UI set up (page 1) but the rest of the pages will have the default layout xml applied.
Note: at the moment I'm trying to set up the UI with the index number. You can ignore the Question[] array and any reference to it as the UI doesnt use it at this time. However I do try to set the typeface, which only works on the first page. You can take a look at the screenshots at the bottom, "How many moons does Saturn have" is the default xml in the layout. I've also noticed that the textview displays question 9, instead of 1.
Here is the fragment
public class SurveyTakerFragment extends Fragment {
private Question question;
private int index;
private TextView tv_question_title;
private EditText et_sms_response;
private Button btn_submit_response;
private SharedPreferences sharedPrefs;
private Typeface typeface;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_question, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setup();
}
void setup(){
Activity activity = getActivity();
tv_question_title = (TextView) activity.findViewById(R.id.tv_question_title);
et_sms_response = (EditText) activity.findViewById(R.id.et_sms_response);
btn_submit_response = (Button) activity.findViewById(R.id.btn_submit_response);
tv_question_title.setTypeface(typeface);
tv_question_title.setText("Question: " + index);
//TODO: Set question title.
//TODO: Pre-fill previous answer if any.
btn_submit_response.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String response = et_sms_response.getText().toString();
//TODO: Submit response.
}
});
}
public void setQuestion(Question question, int index){
this.question = question;
this.index = index;
}
public void setSharedPrefs(SharedPreferences sharedPrefs){
this.sharedPrefs = sharedPrefs;
}
public void setTypeface(Typeface typeface){
this.typeface = typeface;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
}
Here is the adapter:
public class SurveyTakerAdapter extends FragmentPagerAdapter{
private Question[] questions;
private SharedPreferences sharedPrefs;
private Typeface typeface;
public SurveyTakerAdapter(FragmentManager fm, Question[] questions,
SharedPreferences sharedPrefs, Typeface typeface) {
super(fm);
this.questions = questions;
this.sharedPrefs = sharedPrefs;
this.typeface = typeface;
}
#Override
public Fragment getItem(int index) {
SurveyTakerFragment surveyTakerFragment = new SurveyTakerFragment();
surveyTakerFragment.setQuestion(questions[index], index);
surveyTakerFragment.setSharedPrefs(sharedPrefs);
surveyTakerFragment.setTypeface(typeface);
return surveyTakerFragment;
}
#Override
public int getCount() {
return questions.length;
}
#Override
public CharSequence getPageTitle(int position) {
return "Question: " + (position + 1);
}
}
Pager Activity
public class SurveyTaker extends FragmentActivity{
private final String APP_DATA = "appData";
private SurveyTakerAdapter surveyTakerAdapter;
private ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_survey);
Question[] questions = new Question[10];
FragmentManager fragmentManager = getSupportFragmentManager();
SharedPreferences sharedPrefs = getSharedPreferences(APP_DATA, MODE_PRIVATE);
Typeface robot = Typeface.createFromAsset(getAssets(), "Roboto-Thin.ttf");
surveyTakerAdapter = new SurveyTakerAdapter(fragmentManager, questions, sharedPrefs, robot);
viewPager = (ViewPager) findViewById(R.id.vp_survey_taker);
viewPager.setOffscreenPageLimit(10);
viewPager.setAdapter(surveyTakerAdapter);
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
#Override
public void onPageSelected(int index) {
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
});
}
}
I'm assuming this is the case because I'm using a single fragment to populate all the pages in the viewpager, but I don't know how else to go about this. Is my design bad? Or is there something im missing?
Any help would be greatly appreciated!
Thanks!
It looks like the R.id.tv_question_title, R.id.tv_question_title and R.id.tv_question_title views are part of your R.layout.fragment_question layout. You should be referencing those views through your SurveyTakerFragment instance using getView(), not through the Activity via getActivity(). You are also duplicating effort in onActivityCreated() and setup().
Replace your onActivityCreated() and setup() implementations with this:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setup();
}
void setup(){
View view = getView();
tv_question_title = (TextView) view.findViewById(R.id.tv_question_title);
et_sms_response = (EditText) view.findViewById(R.id.et_sms_response);
btn_submit_response = (Button) view.findViewById(R.id.btn_submit_response);
tv_question_title.setTypeface(typeface);
tv_question_title.setText("Question: " + index);
//TODO: Set question title.
//TODO: Pre-fill previous answer if any.
btn_submit_response.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
String response = et_sms_response.getText().toString();
//TODO: Submit response.
}
});
}
I have an android tabhost with a listview inside, when I click on a listviewitem I want to show a new list at the place of the old list inside the tablayout.
How can I implement this? (I need to use listviews not fragments)
Thanks!
I found a solution: I put an activitygroup inside the tabhost, like so:
public class DrillDownWrapper extends ActivityGroup {
private ArrayList<View> history;
public static DrillDownWrapper group;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
history = new ArrayList<View>();
group = this;
//put the first listactivity
Intent i = new Intent(DrillDownWrapper.this, ListActivity.class);
View view = getLocalActivityManager().startActivity("ListActivity", i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)).getDecorView();
replaceView(view);
}
public void replaceView(View v) {
history.add(v);
setContentView(v);
}
public void back() {
if(history.size() > 1) {
history.remove(history.size()-1);
setContentView(history.get(history.size()-1));
} else {
finish();
}
}
#Override
public void onBackPressed() {
DrillDownWrapper.group.back();
return;
}
}
inside the listactivity you can get the context (ie to show a dialog) by calling getParent() method
i am new to Android and i am facing a problem in calling different activities from the same screen with same user interface.
Actually i want to implement d functionality of a tab activity but instead of tabs i am providing buttons and the buttons should act like tabs.
I am unable to do that. I am going wrong some where.
Can anyone help me please.....
HomeScreen class is:
public class HomeScreen extends Activity implements OnItemClickListener {
public Integer[] images = { R.raw.mobile, R.raw.note_books, R.raw.ac,
R.raw.drivers, R.raw.camera, R.raw.home_theaters, R.raw.pda,
R.raw.tv, R.raw.washing_machines, R.raw.scanners };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.grid);
GridView gv = (GridView) findViewById(R.id.gridV);
LayoutInflater inflater = getLayoutInflater();
gv.setAdapter(new GridViewAdapter(images, inflater));
gv.setOnItemClickListener(this);
if (StaticUtils.scheckStatus){
parseData();
}
}
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
Intent contents = new Intent(HomeScreen.this, Cat.class);
contents.putExtra("homescreen", arg2);
startActivity(contents);
}
Cat.class is this:
class Cat extends Activity implements OnClickListener{
private Button mBtnContents, mBtnBrand, mBtnCategory, mBtnBack;
#Override
public void onCreate(Bundle si){
super.onCreate(si);
setContentView(R.layout.gridtab);
int i = getIntent().getIntExtra("homescreen", 0);
mBtnContents=(Button) findViewById(R.id.btnContents);
mBtnContents.setOnClickListener(this);
mBtnBrand=(Button) findViewById(R.id.btnBrand);
mBtnBrand.setOnClickListener(this);
mBtnCategory=(Button) findViewById(R.id.btnCategory);
mBtnCategory.setOnClickListener(this);
mBtnBack=(Button) findViewById(R.id.btnBack);
mBtnBack.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v==mBtnContents){
int i = getIntent().getIntExtra("homescreen", 0);
Intent in=new Intent(Cat.this, Pc.class);
in.putExtra("homescreen", i);
startActivity(in);
} else if(v==mBtnBrand){
startActivity(new Intent(Cat.this, Sd.class));
} else if(v==mBtnCategory){
startActivity(new Intent(Cat.this, Sbc.class));
} else if(v==mBtnBack){
startActivity(new Intent(Cat.this, Hs.class));
}
}
}
When i click on contents button its displaying the details but when i click on the other buttons its not showing anythng
Instead of "v==mBtnContents" use "v.equals(mBtnContents)" because View is an object.