I built a view that contains a EditText as a submit button, therefore it's not focusable in touch mode, the text is centered and it has a background color. Then, I created a fragment with this button.
When this fragment is the first one to be placed in the container to be drawn, the text is centered in the edit text as expected. However, if use an click event to replace this fragment with another fragment that contains it's own submit button, the text is not centered, let alone aligned to the left or to the right. It's not aligned at all.
After put a Hander to add a delay for requesting the layout after 5ms where I create view to be placed in the fragment, the text get centered properly. I realize that for some reason the fragment transaction is needing an extra call for requestLayout.
I isolated the code that is causing the problem. By doing this I realized that the problem is somehow related with the way I handle typefaces in my TestTextField.java. I pasted right bellow.
What could be possibly causing that? Why? If it is something wrong with my code, why it works to the first fragment I placed in the screen, but it does not work with the other ones?
TestActivity.java
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import java.lang.reflect.Method;
/**
* Created by eduardoj on 2017-07-19.
*/
public class TestActivity extends Activity
implements TestFragmentA.Listener, TestFragmentB.Listener {
private FrameLayout fragmentContainer;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup.LayoutParams matchParent = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
fragmentContainer = new FrameLayout(this);
fragmentContainer.setId(View.generateViewId());
fragmentContainer.setLayoutParams(matchParent);
fragmentContainer.setFocusableInTouchMode(true);
setContentView(fragmentContainer);
FragmentManager manager = getFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.add(fragmentContainer.getId(), TestFragmentA.newInstance());
transaction.commit();
}
#Override
public void onASubmitButtonClick() {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.add(fragmentContainer.getId(), TestFragmentB.newInstance());
transaction.commit();
}
#Override
public void onBSubmitButtonClick() {
}
}
TestFragmentA.java
import android.app.Fragment;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
/**
* Created by eduardoj on 2017-07-19.
*/
public class TestFragmentA extends Fragment {
public interface Listener {
void onASubmitButtonClick();
}
private Listener listener;
public static TestFragmentA newInstance() {
Bundle args = new Bundle();
TestFragmentA fragment = new TestFragmentA();
fragment.setArguments(args);
return fragment;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
/*
* This makes sure that the container context has implemented the
* callback interface. If not, it throws an exception.
*/
try {
listener = (Listener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement TestFragmentA.Listener");
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
FrameLayout layout = new FrameLayout(getActivity());
layout.setId(View.generateViewId());
layout.setLayoutParams(params);
layout.setBackgroundColor(Color.CYAN);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
600,
FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER
);
TestTextField view = new TestTextField(getActivity());
view.setId(View.generateViewId());
view.setLayoutParams(lp);
view.setText("Submit A");
view.setBackgroundColor(Color.MAGENTA);
view.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
view.setEnableTextEditing(false);
view.addListener(new TestTextField.Listener() {
#Override
protected void onClick(TestTextField textField, String text) {
super.onClick(textField, text);
listener.onASubmitButtonClick();
}
});
layout.addView(view);
return layout;
}
}
TestFragmentB.java
import android.app.Fragment;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
/**
* Created by eduardoj on 2017-07-19.
*/
public class TestFragmentB extends Fragment {
public interface Listener {
void onBSubmitButtonClick();
}
private Listener listener;
public static TestFragmentB newInstance() {
Bundle args = new Bundle();
TestFragmentB fragment = new TestFragmentB();
fragment.setArguments(args);
return fragment;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
/*
* This makes sure that the container context has implemented the
* callback interface. If not, it throws an exception.
*/
try {
listener = (Listener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement TestFragmentA.Listener");
}
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater,
#Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
FrameLayout layout = new FrameLayout(getActivity());
layout.setId(View.generateViewId());
layout.setLayoutParams(params);
layout.setBackgroundColor(Color.LTGRAY);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
600,
FrameLayout.LayoutParams.WRAP_CONTENT,
Gravity.CENTER
);
TestTextField view = new TestTextField(getActivity());
view.setId(View.generateViewId());
view.setLayoutParams(lp);
view.setText("Submit B");
view.setBackgroundColor(Color.MAGENTA);
view.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
view.setEnableTextEditing(false);
view.addListener(new TestTextField.Listener() {
#Override
protected void onClick(TestTextField textField, String text) {
super.onClick(textField, text);
listener.onBSubmitButtonClick();
}
});
layout.addView(view);
return layout;
}
}
TestTextField.java
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Handler;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
/*
* Created by eduardoj on 2017-07-13.
*/
public class TestTextField extends LinearLayout {
public static class Listener {
protected void onClick(TestTextField textField, String text) {}
}
private int BACKGROUND_COLOR = Color.MAGENTA;
private String HINT = "Enter text here";
private boolean isToUpdateMinHeight;
private EditText editText;
private Typeface textTypeface;
private Typeface hintTypeface;
private List<Listener> listeners;
public TestTextField(Context context) {
super(context);
listeners = new ArrayList<>();
/* Initializing text field */
initView();
bindListeners();
}
public void addListener(Listener listener) {
if (listener != null) {
listeners.add(listener);
}
}
public void setEnableTextEditing(boolean enable) {
editText.setFocusableInTouchMode(enable);
}
public void setHintTypeface(Typeface typeface) {
hintTypeface = typeface;
isToUpdateMinHeight = true;
updateTypeface();
}
public void setText(CharSequence text) {
editText.setText(text);
updateTypeface();
}
#Override
public void setTextAlignment(int textAlignment) {
editText.setTextAlignment(textAlignment);
}
public void setTypeface(Typeface typeface) {
isToUpdateMinHeight = true;
textTypeface = typeface;
updateTypeface();
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
updateMinHeight();
}
private void initView() {
setOrientation(HORIZONTAL);
LayoutParams params = new LayoutParams(0, LayoutParams.WRAP_CONTENT, 1);
editText = new EditText(getContext());
editText.setId(generateViewId());
editText.setLayoutParams(params);
editText.setHint(HINT);
editText.setBackgroundColor(Color.TRANSPARENT); // Removes underline
addView(editText);
updateTypeface();
setBackgroundColor(BACKGROUND_COLOR);
// Custom Typefaces: you have to set the custom typeset to reproduce the problem.
// setTypeface(G.Font.getVegurRegular(getContext()));
// setHintTypeface(G.Font.getVegurLight(getContext()));
/* This is the current work around for this Issue */
(new Handler()).postDelayed(new Runnable() {
#Override
public void run() {
requestLayout();
}
}, 15);
}
private void bindListeners() {
final TestTextField textFieldInstance = this;
editText.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for (Listener listener : listeners) {
listener.onClick(
textFieldInstance,
editText.getText().toString()
);
}
}
});
}
/**
* Updates the minimum height to the size of the considering the biggest
* typeface.
*/
private void updateMinHeight() {
if (!isToUpdateMinHeight) {
return;
}
Typeface original = editText.getTypeface();
editText.setTypeface(textTypeface);
editText.measure(0, 0);
int textHeight = editText.getMeasuredHeight();
editText.setTypeface(hintTypeface);
editText.measure(0, 0);
int hintHeight = editText.getMeasuredHeight();
int minHeight = textHeight > hintHeight ? textHeight : hintHeight;
editText.setMinimumHeight(minHeight);
editText.setTypeface(original);
isToUpdateMinHeight = false;
}
private void updateTypeface() {
boolean hasText = editText.length() > 0;
Typeface typeface = hasText ? textTypeface : hintTypeface;
editText.setTypeface(typeface);
}
}
I came to a solution that doesn't require to call an extra requestLayout, I believe this is the right way to solve this problem.
updateMinHeight and super.onMeasure are in the wrong order in the onMeasure method. The correct way is:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
updateMinHeight();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
For me, this order above makes sense since updateMinHeight can actually change the measured size of the widget. Though this answer shows how to solve, I can't understand why the problem happens and how would this affect only the text position in very specific cases, such as to the first fragment displayed.
Related
This is my first Q on the site, I'll try to form it well.
I have a recyclerView, and the Item is an array of buttons.
Button click shows a popup menu that allows the user to change the color of the button.
I've managed to set that the onClick method will change the color, but I'm clueless about how to save the chosen color in the ButtonArrayList, that Holds the colors.
The problem is that when the button is pressed, I don't know how to understand programatically on which button, in which button array it was pressed.
Thanks!
Just to demonstrate the problem. when button is clicked, How to identify which button of which item was clicked?
1
The code of the fragment:
package com.examples.recyclerViewWithButtonArray;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.LinkedList;
/**
* A simple {#link Fragment} subclass.
* Use the {#link Game#newInstance} factory method to
* create an instance of this fragment.
*/
public class Game extends Fragment {
// TODO: Rename parameter arguments, choose names that match
protected static int[] mButtonsColors;
private final LinkedList<ButtonArray> mButtonArrayList = new LinkedList<>();
RecyclerView mGuessLinesRecyclerView;
ButtonArrayListAdapter mButtonArrayListAdapter;
FloatingActionButton mFab;
// TODO: Rename and change types of parameters
public Game() {
// Required empty public constructor
}
public static Game newInstance(String param1, String param2) {
Game fragment = new Game();
return fragment;
}
private void initGameColors(){
mButtonsColors = new int[4];
int[] c = getContext().getResources().getIntArray(R.array.buttonColors);
//asign colors
for (int i = 0; i < 4; i++) {
this.mButtonsColors[i] = c[i];
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initGameColors();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View vw = inflater.inflate(R.layout.fragment_game, container, false);
return vw;
}
#RequiresApi(api = Build.VERSION_CODES.M)
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mGuessLinesRecyclerView = view.findViewById(R.id.recycler_view);
mFab = view.findViewById(R.id.fab);
//initialize recyclerView
// Create an adapter and supply the data to be displayed.
mButtonArrayListAdapter = new ButtonArrayListAdapter(getContext(), mButtonArrayList, this);
// Connect the adapter with the RecyclerView.
mGuessLinesRecyclerView.setAdapter(mButtonArrayListAdapter);
// Give the RecyclerView a default layout manager.
mGuessLinesRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
//initializeFAB
mFab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
mButtonArrayList.add(new ButtonArray(getContext(),mButtonsColors));
mGuessLinesRecyclerView.setAdapter(mButtonArrayListAdapter);
}
});
//add first array to the recycler view.
// Next guess lines will be added when clicking on movableFab
mButtonArrayList.add(new ButtonArray(getContext(), this.mButtonsColors));
}
}
The code of ButtonArrayListAdapter:
package com.examples.recyclerViewWithButtonArray;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class ButtonArrayListAdapter extends RecyclerView.Adapter<ButtonArrayListAdapter.ButtonArrayViewHolder> {
private final Context mContext;
private final List<ButtonArray> mData;
class ButtonArrayViewHolder extends RecyclerView.ViewHolder {
public ArrayList<Button> mButtons;
final ButtonArrayListAdapter mAdapter;
public ButtonArrayViewHolder(#NonNull View itemView, ButtonArrayListAdapter adapter) {
super(itemView);
this.mAdapter = adapter;
mButtons =new ArrayList<>();
if(4==4)
{
//create an array of button for binding
mButtons.add((Button)itemView.findViewById(R.id.button_Guess1));
mButtons.add((Button)itemView.findViewById(R.id.button_Guess2));
mButtons.add((Button)itemView.findViewById(R.id.button_Guess3));
mButtons.add((Button)itemView.findViewById(R.id.button_Guess4));
}
}
}
public ButtonArrayListAdapter(Context mContext, List<ButtonArray> mData, Game mGame) {
this.mContext = mContext;
this.mData = mData;
}
#NonNull
#Override
public ButtonArrayViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View layout;
layout = LayoutInflater.from(mContext).inflate(R.layout.guess_line,parent,false);
return new ButtonArrayViewHolder(layout,this);
}
#Override
public void onBindViewHolder(#NonNull final ButtonArrayViewHolder buttonArrayViewHolder, final int position) {
//bind data here
//initiate each guessLineButton
for (int i = 0; i < 4; i++) {
int c = mData.get(position).mAnswerButtonsColors[i];
final Button bt = buttonArrayViewHolder.mButtons.get(i);
//set initial button color
bt.setBackgroundColor(c);
//set button clik to open color chooser
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int[] chooseColorButtons = new int[4];
// inflate the layout of the popup window
final View popupView = LayoutInflater.from(mContext).inflate(R.layout.choose_color_popup,null);
// create the popup window
int width = bt.getWidth();
int height = LinearLayout.LayoutParams.WRAP_CONTENT;
boolean focusable = true; // lets taps outside the popup also dismiss it
final PopupWindow popupWindow = new PopupWindow(popupView, width, height, focusable);
// show the popup window
// which view you pass in doesn't matter, it is only used for the window tolken
int[] loc = new int[]{0,0};
bt.getLocationOnScreen(loc);
popupWindow.showAtLocation(v, Gravity.TOP|Gravity.LEFT, loc[0], loc[1] + bt.getHeight());
// dismiss the popup window when touched
popupView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
popupWindow.dismiss();
return true;
}
});
//initiate each color choose button
if(chooseColorButtons.length==4) {
chooseColorButtons[0] = R.id.buttonColor1;
chooseColorButtons[1] = R.id.buttonColor2;
chooseColorButtons[2] = R.id.buttonColor3;
chooseColorButtons[3] = R.id.buttonColor4;
}
for (int j = 0; j < 4 ; j++) {
Button colbt = (Button)(popupView.findViewById(chooseColorButtons[j]));
colbt.setBackgroundColor(Game.mButtonsColors[j]);
colbt.setTextColor(Game.mButtonsColors[j]);
colbt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
bt.setBackgroundColor(((ColorDrawable)(((Button)v).getBackground())).getColor());
//WHAT SHOULD I DO HERE?
popupWindow.dismiss();
}
});
}
}
});
}
}
#Override
public int getItemCount() {
return mData.size();
}
}
After reading your question what I get is you want to save the color against every button so next time when that button click the same color should load if yes then you can consider these tw0 suggestions
1- if the number of buttons is static and you are not adding them dynamically then you can hardcode the color against each button by adding them in the list and assign them manually against each button.
2- you can use key-value pair(hash map), these are the best solution for any case either you're are manually adding the button or dynamically, just store the color against each key. In this case, buttons should be your keys and colors will be value.
Thanku
I am trying to implement fragments for a project in Android Studio. The point of the project is to select a color from a spinner in one fragment then pass it to the parent activity and then pass it from the parent activity to the second fragment to change the background color of the second fragment. The problem I am having is my listener in the palette activity is set to null despite the fact I invoke it in the onAttach function.
This is my code for the Fragment that causes the app to crash
package edu.temple.palettecolorapp;
import android.content.Context;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Spinner;
/**
* A simple {#link Fragment} subclass.
* Activities that contain this fragment must implement the
* {#link PaletteFragment.OnFragmentInteractionListener} interface
* to handle interaction events.
* Use the {#link PaletteFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class PaletteFragment extends Fragment {
private String colorArr[];
private String translationArr[];
Context parent;
private final String mParam1 = "colors";
private final String mParam2 = "translation";
public OnFragmentInteractionListener mListener;
public PaletteFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
*
* #return A new instance of fragment PaletteFragment.
*/
// TODO: Rename and change types and number of parameters
public static PaletteFragment newInstance(String colors[], String translation[]) {
PaletteFragment fragment = new PaletteFragment();
Bundle args = new Bundle();
args.putStringArray("colors", colors);
args.putStringArray("translation", translation);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
this.colorArr = getArguments().getStringArray(mParam1);
this.translationArr = getArguments().getStringArray(mParam2);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.parent = context;
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) parent;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
// this.parent = context;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_palette, container, false);
Spinner spinner = v.findViewById(R.id.spinner);
PaletteAdapter pa = new PaletteAdapter(parent,colorArr,translationArr);
spinner.setAdapter(pa);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String c = colorArr[position];
mListener.onColorSelection(c);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return v;
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onColorSelection(String color);
}
}
This is in the main activity
package edu.temple.palettecolorapp;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.support.constraint.ConstraintLayout;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.AdapterView;
import android.widget.Spinner;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
public class PaletteActivity extends AppCompatActivity implements PaletteFragment.OnFragmentInteractionListener {
PaletteFragment master;
ColorFragment subject;
FragmentTransaction ft;
private final String colors[] = {"blue", "green", "purple", "red", "gray", "cyan", "magenta", "yellow", "lime"};
private boolean isSelected = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = getApplicationContext();
Resources res = context.getResources();
String title = res.getString(R.string.palette_title);
setTitle(title);
setContentView(R.layout.activity_palette);
String translation[] = res.getStringArray(R.array.colors);
PaletteFragment master = PaletteFragment.newInstance(colors,translation);
ColorFragment subject = ColorFragment.newInstance("magenta");
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.fragment1,master);
ft.replace(R.id.fragment2,subject);
ft.addToBackStack(null);
ft.commit();
}
#Override
public void onColorSelection(String color) {
subject.updateBackgroundColor(color);
}
}
I am having trouble in this portion of the fragment in the 'onCreateView' method
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_palette, container, false);
Spinner spinner = v.findViewById(R.id.spinner);
PaletteAdapter pa = new PaletteAdapter(parent,colorArr,translationArr);
spinner.setAdapter(pa);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
String c = colorArr[position];
mListener.onColorSelection(c);
}
#Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
return v;
}
The 'mListener.onColorSelection' call causes the error and this is what the output is
E/AndroidRuntime: FATAL EXCEPTION: main
Process: edu.temple.palettecolorapp, PID: 14867
java.lang.NullPointerException: Attempt to invoke virtual method 'void edu.temple.palettecolorapp.ColorFragment.updateBackgroundColor(java.lang.String)' on a null object reference
at edu.temple.palettecolorapp.PaletteActivity.onColorSelection(PaletteActivity.java:45)
at edu.temple.palettecolorapp.PaletteFragment$1.onItemSelected(PaletteFragment.java:87)
at android.widget.AdapterView.fireOnSelected(AdapterView.java:944)
at android.widget.AdapterView.dispatchOnItemSelected(AdapterView.java:933)
at android.widget.AdapterView.access$300(AdapterView.java:53)
at android.widget.AdapterView$SelectionNotifier.run(AdapterView.java:898)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Edit2: added ColorFragment 'updateBackgroundColor' method
import android.content.Context;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A simple {#link Fragment} subclass.
* Activities that contain this fragment must implement the
* to handle interaction events.
* Use the {#link ColorFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class ColorFragment extends Fragment {
private View v;
TextView t;
String color;
private final String KEY = "color";
public ColorFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters
* #return A new instance of fragment ColorFragment.
*/
// TODO: Rename and change types and number of parameters
public static ColorFragment newInstance() {
ColorFragment fragment = new ColorFragment();
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
this.color = getArguments().getString(KEY);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
v = inflater.inflate(R.layout.fragment_color, container, false);
t = v.findViewById(R.id.textView);
t.setBackgroundColor(Color.BLACK);
return v;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
}
#Override
public void onDetach() {
super.onDetach();
}
public void updateBackgroundColor(String c){ // causing problems
t.setBackgroundColor(Color.parseColor(c));
}
}
Apparently ColorFragment subject in PaletteActivity is null when calling #onColorSelection().
Please check the assignment of value for the variable and make sure it is not null.
#Override
public void onColorSelection(String color) {
subject.updateBackgroundColor(color);
}
EDIT:
change the line:
ColorFragment subject = ColorFragment.newInstance("magenta");
TO:
subject = ColorFragment.newInstance("magenta");
I want to add intent in sliding view pager. As I click different pages of the sliding view pager, a different activity must be called but I can't find the solution.
I have added image text and description in the view pager and a button is there in the layout
I think this would involve the use of page selected but earlier when I used onpageselected by using the position it opens up the page even if we are not clicking but I want to use intent here.
Adapterclass
package com.android.msahakyan.expandablenavigationdrawer.adapter;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.msahakyan.expandablenavigationdrawer.R;
import com.android.msahakyan.expandablenavigationdrawer.fragment.CardAdapter;
import com.android.msahakyan.expandablenavigationdrawer.fragment.CardItemString;
import java.util.ArrayList;
import java.util.List;
/**
* Created by tanis on 21-06-2018.
*/
public class CardPagerAdapterS extends PagerAdapter implements CardAdapter {
private List<CardView> mViews;
private List<CardItemString> mData;
private float mBaseElevation;
public CardPagerAdapterS() {
mData = new ArrayList<>();
mViews = new ArrayList<>();
}
public void addCardItemS(CardItemString item) {
mViews.add(null);
mData.add(item);
}
public float getBaseElevation() {
return mBaseElevation;
}
#Override
public CardView getCardViewAt(int position) {
return mViews.get(position);
}
#Override
public int getCount() {
return mData.size();
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
View view = LayoutInflater.from(container.getContext())
.inflate(R.layout.adapter, container, false);
container.addView(view);
bind(mData.get(position), view);
CardView cardView = (CardView) view.findViewById(R.id.cardView);
if (mBaseElevation == 0) {
mBaseElevation = cardView.getCardElevation();
}
cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
mViews.set(position, cardView);
return view;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
mViews.set(position, null);
}
private void bind(CardItemString item, View view) {
TextView titleTextView = (TextView) view.findViewById(R.id.titleTextView);
TextView contentTextView = (TextView) view.findViewById( R.id.contentTextView);
ImageView imageView=(ImageView) view.findViewById( R.id.image12 ) ;
titleTextView.setText(item.getTitle());
contentTextView.setText(item.getText());
imageView.setImageResource( item.getImages() );
}
}
FragmentAction
package com.android.msahakyan.expandablenavigationdrawer.fragment;
import android.content.Context;
import android.content.Intent;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.Fragment;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
//import android.support.v7.widget.LinearLayoutManager;
//import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.msahakyan.expandablenavigationdrawer.R;
import com.android.msahakyan.expandablenavigationdrawer.Registration;
import com.android.msahakyan.expandablenavigationdrawer.adapter.CardPagerAdapterS;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import in.goodiebag.carouselpicker.CarouselPicker;
import technolifestyle.com.imageslider.FlipperLayout;
import technolifestyle.com.imageslider.FlipperView;
/**
* A simple {#link Fragment} subclass.
* Use the {#link FragmentAction#newInstance} factory method to
* create an instance of this fragment.
*/
public class FragmentAction extends Fragment {
ViewPager mViewPager;
CardPagerAdapterS mCardAdapter;
ShadowTransformer mCardShadowTransformer;
private Context context;
ViewPager viewPager;
String titlesText [] = {" Website Design", " Digital Marketing", " Domain Registration", "Graphics Design", " Mobile Apps", " Server Hosting",
" Software Development", " Content Marketing", " Security (SSl)"};
String detailsArray [] = {
"Your website is your digital home. We create, design, redesign, develop, improvise, and implement. We make beautiful websites",
"We help your business reach potential customers on every possible digital device through all possible media channels ",
"To launch your website the first thing you need is the domain name. You can choose your domain name with us here ",
"We generate creative solutions and can create a wide range of graphic for your clients which match their business ",
"We are mobile. And we make you mobile. We make responsive websites and mobile apps which compliment your business ",
"When you are hosting your website in the India you will benefit from a higher ping rate and lowest latency ",
"Our team is competent at coding web apps with keen attention to detail & intuitive functionality that is high on design & creativity",
"Content is the heart of your digital presence. We create the right content with the right focus for your business",
"Secure your site with the world's leading provider of online security and get these exclusive features at no added cost",
};
int[] images = {R.drawable.website_design, R.drawable.digita,R.drawable.domain_registration,R.drawable.graphic,
R.drawable.mob,R.drawable.server,R.drawable.software_development,R.drawable.ontent,R.drawable.ssl};
private static final String KEY_MOVIE_TITLE = "key_title";
public FragmentAction() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment.
*
* #return A new instance of fragment FragmentAction.
*/
public static FragmentAction newInstance(String movieTitle) {
FragmentAction fragmentAction = new FragmentAction();
Bundle args = new Bundle();
args.putString(KEY_MOVIE_TITLE, movieTitle);
fragmentAction.setArguments(args);
return fragmentAction;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_action,container,false);
TextView txt = (TextView)v.findViewById( R.id.textView12 );
txt.setText("\u25BA Creative & Dedicated Team");
TextView txt1 = (TextView)v.findViewById( R.id.textView13 );
txt1.setText("\u25BA Affordable Cost");
TextView txt2 = (TextView)v.findViewById( R.id.textView14 );
txt2.setText("\u25BA Maintain Long Relationship");
TextView txt3 = (TextView)v.findViewById( R.id.textView15 );
txt3.setText("\u25BA Timely Deliverly ");
context = this.getContext();
mViewPager = (ViewPager)v.findViewById(R.id.viewpager1);
mCardAdapter = new CardPagerAdapterS();
for (int i=0; i<titlesText.length; i++){
mCardAdapter.addCardItemS(new CardItemString( titlesText[i], detailsArray[i],images[i]));
}
mCardShadowTransformer = new ShadowTransformer(mViewPager, mCardAdapter);
mViewPager.setAdapter(mCardAdapter);
mViewPager.setPageTransformer(false, mCardShadowTransformer);
mViewPager.setOffscreenPageLimit(3);
viewPager = (ViewPager)v.findViewById( R.id.viewpager );
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter( this.getContext() );
viewPager.setAdapter( viewPagerAdapter );
Timer timer = new Timer( );
timer.scheduleAtFixedRate( new Mytime(),2000,4000 );
FloatingActionButton floatingActionButton = (FloatingActionButton)v.findViewById( R.id.floatingActionButton );
floatingActionButton.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity( new Intent( getActivity(),Registration.class ) );
}
} );
return v;
}
public class Mytime extends TimerTask{
#Override
public void run() {
getActivity().runOnUiThread( new Runnable() {
#Override
public void run() {
if(viewPager.getCurrentItem() == 0) {
viewPager.setCurrentItem( 1 );
}
else if (viewPager.getCurrentItem()== 1){
viewPager.setCurrentItem( 2 );
}
else if (viewPager.getCurrentItem()== 2){
viewPager.setCurrentItem( 3 );
}
else if (viewPager.getCurrentItem()== 3){
viewPager.setCurrentItem( 4 );
}
else {
viewPager.setCurrentItem(0);
}
}
} );
}
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Drawable movieIcon = ResourcesCompat.getDrawable(getResources(), R.drawable.webdesign, getContext().getTheme());
String movieTitle = getArguments().getString(KEY_MOVIE_TITLE);
}
}
first of all onPageSelected listener is not really good idea in this case, because it is invoked every time when viewpager' current position changes (it's good for setting toolbar title, for example).
You can add another collection for Activities which can be invoked in CardPagerAdapterS, for example:
....
private List<CardItemString> mData;
private List<Class<? extends Activity> mActivities;
and use them to create click listener in order to open activities:
#Override
public Object instantiateItem(ViewGroup container, int position) {
View view = LayoutInflater.from(container.getContext())
.inflate(R.layout.adapter, container, false);
container.addView(view);
bind(mData.get(position), view);
CardView cardView = (CardView) view.findViewById(R.id.cardView);
if (mBaseElevation == 0) {
mBaseElevation = cardView.getCardElevation();
}
cardView.setMaxCardElevation(mBaseElevation * MAX_ELEVATION_FACTOR);
cardView.setOnCLickListener(v-> {
context.startActivity(new Intent(context, mActivities.get(position));
});
mViews.set(position, cardView);
return view;
}
I have fragment view pager in activity, that creates a number of pages of entered number before. In each fragment, i have recycler view that needs to update each time user moves to the relevant page. on resume() of each fragment I have getter of data from main activity.
What I am experiencing is while I'm going to next page first time it's not updated, but if after some page movements I would back to it, it is updated, with same resume() code.
I tried some delays after updating the data, it didn't help.
So if before updating data I would check every page it would work as I planned, but if the page was not created before (due to pager adapter) but I still use the same code for updating, it does not work.
I would be glad for some help, stacked on it for 2 days already.
Main Activity:
package com.slavafleer.tipcalculator02;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import com.slavafleer.tipcalculator02.recycler.PageHeaderAdapter;
import java.util.ArrayList;
public class ManualModeActivity extends AppCompatActivity implements
PageHeaderAdapter.Callbacks, DinerFragment.Callbacks {
private int mDinersAmount;
private ViewPager mViewPagerDiners;
private PageHeaderAdapter mHeaderAdapter;
private DinersPagerAdapter mDinersPagerAdapter;
private ArrayList<Order> mOrders;
public ArrayList<Order> getOrders() {
return mOrders;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manual_mode);
mOrders = new ArrayList<>();
// Get diners amount from previous activity
Intent intent = getIntent();
mDinersAmount = intent.getIntExtra(Constants.KEY_DINNERS_AMOUNT, 1);
// Initialise PageHeader Recycler
mHeaderAdapter = new PageHeaderAdapter(this, mDinersAmount, this);
final RecyclerView recyclerPageHeader = (RecyclerView) findViewById(R.id.recyclerViewPagerHeader);
final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
recyclerPageHeader.setLayoutManager(linearLayoutManager);
recyclerPageHeader.setAdapter(mHeaderAdapter);
// Initialise ViewPager
mViewPagerDiners = (ViewPager) findViewById(R.id.viewPagerDiners);
FragmentManager fragmentManager = getSupportFragmentManager();
mDinersPagerAdapter = new DinersPagerAdapter(fragmentManager, mDinersAmount);
mViewPagerDiners.setAdapter(mDinersPagerAdapter);
// ViewPager Listener - synchronise with headers recycler
mViewPagerDiners.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
#Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
// Gets position for selected page
#Override
public void onPageSelected(int position) {
mHeaderAdapter.selectItem(position);
linearLayoutManager.smoothScrollToPosition(recyclerPageHeader, null,position);
}
#Override
public void onPageScrollStateChanged(int state) {
}
});
}
// HeaderPage Adapter Callbacks
// Scroll ViewPager by clicked Header
#Override
public void onItemClick(int position) {
mViewPagerDiners.setCurrentItem(position, true);
}
// DinerFragment.OrderDialog.Callbacks
// Send data to PagerAdapter that would sent to each fragment
#Override
public void onDialogAddClick(Order order) {
Log.d("test", "onDialogAddClick");
mOrders.add(order);
mDinersPagerAdapter.updateOrders();
}
}
PagerAdapter
package com.slavafleer.tipcalculator02;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.ArrayList;
/**
* PagerAdapter for ManualModeActivity ViewPager
*/
public class DinersPagerAdapter extends FragmentPagerAdapter {
private int mDinersAmount;
private ArrayList<DinerFragment> mDinerFragments;
public DinersPagerAdapter(FragmentManager fm, int dinersAmount) {
super(fm);
mDinersAmount = dinersAmount;
mDinerFragments = new ArrayList<>();
}
#Override
public Fragment getItem(int position) {
// Insert diners amount to fragment
Bundle bundle = new Bundle();
bundle.putInt(Constants.KEY_DINNERS_AMOUNT, mDinersAmount);
bundle.putInt(Constants.KEY_CURRENT_PAGE, position);
DinerFragment dinerFragment = new DinerFragment();
dinerFragment.setArguments(bundle);
mDinerFragments.add(dinerFragment); // save fragments references
return dinerFragment;
}
// Diners amount + All
#Override
public int getCount() {
return mDinersAmount + 1;
}
// Update order list in each fragment of view pager
public void updateOrders() {
for(DinerFragment dinerFragment : mDinerFragments) {
dinerFragment.onResume();
}
}
}
Fragment
package com.slavafleer.tipcalculator02;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.slavafleer.tipcalculator02.recycler.OrdersAdapter;
import java.util.ArrayList;
/**
* Diner Fragment Class
*/
public class DinerFragment extends Fragment implements OrderDialog.Callbacks {
private ArrayList<Order> mOrders = new ArrayList<>();
private RecyclerView mRecyclerViewOrders;
private ImageView mImageViewAddOrderButton;
private int mDinersAmount;
private OrdersAdapter mOrdersAdapter;
private int mDinerId;
private Callbacks mCallbacks;
public DinerFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d("test", "onCreateView");
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_diner, container, false);
mCallbacks = (Callbacks) inflater.getContext();
// Get Diners Amount
final Bundle bundle = getArguments();
if(bundle != null) {
mDinersAmount = bundle.getInt(Constants.KEY_DINNERS_AMOUNT);
mDinerId = bundle.getInt(Constants.KEY_CURRENT_PAGE);
Log.d("test", "onCreateView " + mDinerId);
}
mRecyclerViewOrders = (RecyclerView) view.findViewById(R.id.recyclerViewOrders);
mOrdersAdapter = new OrdersAdapter(getActivity(), mOrders);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerViewOrders.setLayoutManager(linearLayoutManager);
mRecyclerViewOrders.setAdapter(mOrdersAdapter);
// Due to the bug, we could use just listener and not OnClick in Fragment
mImageViewAddOrderButton = (ImageView) view.findViewById(R.id.imageViewAddButton);
mImageViewAddOrderButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ArrayList<Integer> currentPage = new ArrayList<>();
currentPage.add(mDinerId);
OrderDialog orderDialog = new OrderDialog(getActivity(),
mDinersAmount, currentPage, DinerFragment.this);
orderDialog.show();
}
});
return view;
}
#Override
public void onResume() {
super.onResume();
Log.d("test", "onResume " + mDinerId);
ManualModeActivity activity = (ManualModeActivity) getActivity();
mOrders = activity.getOrders();
for(Order order : mOrders) {
Log.d("test", order.getPrice() + "");
}
int size = mOrders.size();
mOrdersAdapter.notifyDataSetChanged();
mRecyclerViewOrders.smoothScrollToPosition(size);
}
// Blank OrderDialog.Callbacks
// used due to Implements for creation OrderDialog
#Override
public void onDialogAddClick(Order order) {
mCallbacks.onDialogAddClick(order);
}
public interface Callbacks {
void onDialogAddClick(Order order);
}
}
Instead of using onResume use the onPageSelected method and used the passed fragment for context to call the updating method in the fragment.
Finally what I did is replacing mOrdersAdapter.notifyDataSetChanged() on recreating the adapter. I understand that is not a very smart solution but visually it does work as I needed.
I would not mark it as answer cause I still want to know why it acts like I wrote before.
Thanks again.
// mOrdersAdapter.notifyDataSetChanged();
mOrdersAdapter = new OrdersAdapter(getActivity(), mOrders);
mRecyclerViewOrders.setAdapter(mOrdersAdapter);
ViewPager adapter creates 2 fragments at the same time. for instance when you're on page 0, it also creates page 1(lifecycle for page 1: OnCreate->OnCreateView->OnResume->OnPause->OnResume).When you swipe to page 1 only method that is being called is SetMenuVisibility. So in order to update data for page 1 is to call setMenuVisibilty inside of Fragment:
#Override
public void setMenuVisibility(boolean menuVisible) {
super.setMenuVisibility(menuVisible);
if(menuVisible && isResumed()){
settingAdapter();
}
}
So here inside of settingAdapter i reloaded data.
so far,it's the best trick i made toward fragments with recyclerviews inside viewpager. But still there are few milliseconds delay for populating fragment with new data)))
I hope this will help you
I am developing Horizontal Scrolling pages and tabs
MY app is working well in all devices in foreground, but when it goes to background, after one hour, the logs saying that Process com.example.myapp has died. When i reopen the app , the gridview data is not appearing but when scrolling horizontally , getView() method displaying all data like images and text.
that means app has data but view is not formed when process has died. And if i press back button and re-open the app, It is working good
My MainActivity.java is here
package com.bbgusa.bbgdemo.ui.phone;
import java.util.List;
import java.util.Vector;
import org.json.JSONObject;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.TabHost;
import com.bbgusa.bbgdemo.R;
import com.bbgusa.bbgdemo.listener.phone.CustomViewPager;
import com.bbgusa.bbgdemo.ui.chat.phone.ChatFragmentTab;
import com.bbgusa.bbgdemo.ui.dialpad.phone.DialerFragment;
import com.bbgusa.bbgdemo.ui.home.phone.AlarmFragmentPhone;
import com.bbgusa.bbgdemo.ui.home.phone.HomeFragment;
import com.bbgusa.bbgdemo.ui.home.phone.HomeFragmentTab;
import com.bbgusa.bbgdemo.ui.home.phone.InfoFragPhone;
import com.bbgusa.bbgdemo.ui.home.phone.MapPhone;
import com.bbgusa.bbgdemo.ui.home.phone.WeatherFragmentPhone;
import com.bbgusa.bbgdemo.ui.messages.phone.MessagesFragment;
import com.bbgusa.bbgdemo.ui.settings.phone.AboutFragment;
import com.bbgusa.bbgdemo.ui.tablet.ConstantsManager;
import com.bbgusa.bbgdemo.ui.tablet.OnFragmentChangedListenerPhone;
import com.bbgusa.bbgdemo.utils.common.UConnectUtils;
public class MainActivity extends FragmentActivity implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener, OnFragmentChangedListenerPhone {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_phone);
this.initialiseTabHost(savedInstanceState);
initialiseViewPager();
}
/**
* Initialise ViewPager
*/
private void initialiseViewPager() {
List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this,HomeFragmentTab.class.getName()));
fragments.add(Fragment.instantiate(this, DialerFragment.class.getName()));
fragments.add(Fragment.instantiate(this,MessagesFragment.class.getName()));
fragments.add(Fragment.instantiate(this,ChatFragmentTab.class.getName()));
fragments.add(Fragment.instantiate(this, AboutFragment.class.getName()));
this.mPagerAdapter = new PagerAdapter(super.getSupportFragmentManager(), fragments);
this.mViewPager = (CustomViewPager) findViewById(R.id.tabviewpager);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
this.mViewPager.setOffscreenPageLimit(5);
this.mViewPager.setCurrentItem(0);
}
#Override
public void onFragmentChangePhone(JSONObject response, String whichView, String title, String mPhoneNo) {
Bundle b = new Bundle();
if(response != null)
b.putString("JSONObject", response.toString());
if(title != null)
b.putString("Title", title);
String propertyId = UConnectUtils.getPropertyId(mPref, getString(R.string.property_id));
b.putString(UConnectUtils.PROPERTY_ID_KEY, propertyId);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment fragment = null;
if (whichView.equals(ConstantsManager.GRIDVIEWPAGER)) {
// getSupportFragmentManager().popBackStack();
fragment = new HomeFragment();
} else if (whichView.equals(ConstantsManager.WEATHER)) {
fragment = new WeatherFragmentPhone();
}else if (whichView.equals(ConstantsManager.ALARM)) {
fragment = new AlarmFragmentPhone();
}else if (whichView.equals(ConstantsManager.MAPS)) {
fragment = new MapPhone();
}else if (whichView.equals(ConstantsManager.HELP)) {
fragment = new InfoFragPhone();
}
if (whichView.equals(ConstantsManager.MAPS)) { // to show plus-icon on map top right corner
HomeFragment.getInstance().onGridViewVisibilityChanged(true);
HomeFragmentTab.getInstance().onFragmentTabChange(View.VISIBLE , title, "", View.VISIBLE);
} else if (!whichView.equals(ConstantsManager.GRIDVIEWPAGER)) {
HomeFragment.getInstance().onGridViewVisibilityChanged(true);
HomeFragmentTab.getInstance().onFragmentTabChange(View.VISIBLE , title, mPhoneNo, View.GONE);
}
fragment.setArguments(b);
ft.add(R.id.main_home_frag, fragment);
if (whichView.equals(ConstantsManager.GRIDVIEWPAGER)) {
fragmentManager.popBackStack();
} else {
ft.addToBackStack(fragment.toString());
}
ft.commit();
}
#Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
#Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub
}
#Override
public void onTabChanged(String tabId) {
// TODO Auto-generated method stub
}
}
and my HomeFragmentTab.java is
package com.bbgusa.bbgdemo.ui.home.phone;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.bbgusa.bbgdemo.R;
import com.bbgusa.bbgdemo.ui.phone.MainActivity;
import com.bbgusa.bbgdemo.ui.tablet.ConstantsManager;
import com.bbgusa.bbgdemo.ui.tablet.OnFragmentTabChangedListener;
#SuppressLint("NewApi")
public class HomeFragmentTab extends Fragment implements OnFragmentTabChangedListener{
private static final String TAG = HomeFragmentTab.class.getSimpleName();
private static HomeFragmentTab tab;
private MainActivity activityPhone;
public static HomeFragmentTab getInstance() {
return tab;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
activityPhone = (MainActivity) activity;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v;
if (container == null) {
return null;
}
Log.i(TAG, "onCreateView");
v = inflater.inflate(R.layout.hometab_phone, container, false);
tab = this;
activityPhone.onFragmentChangePhone(null, ConstantsManager.GRIDVIEWPAGER, getResources().getString(R.string.app_name), "");
return v;
}
#Override
public void onFragmentTabChange(int i, String title, String mPhoneNo, int mapV) {
}
}
and HomeFragment.java is
package com.bbgusa.bbgdemo.ui.home.phone;
import java.util.Locale;
import org.json.JSONArray;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.bbgusa.bbgdemo.R;
import com.bbgusa.bbgdemo.ui.ImageCacheManager;
import com.bbgusa.bbgdemo.ui.cms.tablet.TestTopics;
import com.bbgusa.bbgdemo.ui.cms.tablet.TopicList;
import com.bbgusa.bbgdemo.ui.phone.MainActivity;
import com.bbgusa.bbgdemo.ui.tablet.onGridViewVisibilityChangedListener;
import com.bbgusa.bbgdemo.utils.common.UCConstants;
import com.bbgusa.bbgdemo.utils.common.UConnectUtils;
import com.viewpagerindicator.IconPageIndicator;
import com.viewpagerindicator.IconPagerAdapter;
import com.viewpagerindicator.PageIndicator;
public class HomeFragment extends Fragment implements onGridViewVisibilityChangedListener{
private static final String TAG = HomeFragment.class.getSimpleName();
private ViewPager mViewPager;
private MainActivity activity;
private PageIndicator mIndicator;
private Animation mRotateAnim;
private Dialog indiacatorDialog;
private LinearLayout homeFragmentLL;
private static HomeFragment homeFragment;
public static final HomeFragment getInstance() {
return homeFragment;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.activity = (MainActivity) activity;
}
#Override
public void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate");
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (container == null) {
return null;
}
View v = inflater.inflate(R.layout.home_phone, container, false);
homeFragment = this;
UConnectUtils.setLauncher(true);
mViewPager = (ViewPager) v.findViewById(R.id.viewpager);
mIndicator = (IconPageIndicator) v.findViewById(R.id.indicator);
homeFragmentLL = (LinearLayout) v.findViewById(R.id.homeFragment);
indiacatorDialog = new Dialog(getActivity());
indiacatorDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
indiacatorDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
indiacatorDialog.setContentView(R.layout.indicator_dialog);
indiacatorDialog.setCanceledOnTouchOutside(false);
Window window = indiacatorDialog.getWindow();
window.setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
mRotateAnim = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_and_scale);
UConnectUtils.addAnimationFrameCount(mRotateAnim);
indicatorAnim();
// for property id
// if (activity.isInterNetAvailable()) {
Log.i(TAG, "onCreateView========== isInterNetAvailable");
new CmsPropertyAsync(activity).execute(UCConstants.CMS_CONFIG_URL, UCConstants.CMS_CONFIG_KEY);
// }
return v;
}
protected void parseJson(JSONObject rootResponce) {
TestTopics.imageUrls.clear();
TestTopics.titles.clear();
TestTopics.mMainMenuID.clear();
TestTopics.mViewType.clear();
TestTopics.mPhoneNo.clear();
try {
//get the Version
String version = rootResponce.optString("VERSION");
SharedPreferences mPref;
SharedPreferences.Editor edit;
mPref = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
edit = mPref.edit();
edit.putString(getResources().getString(R.string.pref_cms_version_key), version).commit();
JSONArray jsonArray = rootResponce.getJSONArray("MAINMENU");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject childMenuObject = jsonArray.getJSONObject(i);
int mainMenuID = childMenuObject.optInt("mainMenuId");
String title = childMenuObject.optString("title");
String viewType = childMenuObject.optString("viewType");
String imageUrl = childMenuObject.optString("imageUrl");
String phoneNo = childMenuObject.optString("phoneNo");
TestTopics.mMainMenuID.add(mainMenuID);
TestTopics.imageUrls.add(imageUrl);
TestTopics.titles.add(title);
TestTopics.mViewType.add(viewType);
TestTopics.mPhoneNo.add(phoneNo);
}
// Create a TopicList for this demo. Save it as the shared instance
// in
// TopicList
String sampleText = getResources().getString(R.string.sample_topic_text);
TopicList tlist = new TopicList(sampleText);
TopicList.setInstance(tlist);
// Create an adapter object that creates the fragments that we need
// to display the images and titles of all the topics.
MyAdapter mAdapter = new MyAdapter(getActivity().getSupportFragmentManager(), tlist, getResources());
// mViewPager.removeAllViews();
mViewPager.setAdapter(mAdapter);
// mViewPager.setPageTransformer(true, new DepthPageTransformer());
mIndicator.setViewPager(mViewPager);
mIndicator.setCurrentItem(0);
mIndicator.notifyDataSetChanged();
ViewTreeObserver observer = mViewPager.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#SuppressLint("NewApi")
#SuppressWarnings("deprecation")
#Override
public void onGlobalLayout() {
mViewPager.bringChildToFront(mViewPager.getChildAt(0));
if(Build.VERSION.SDK_INT >= UCConstants.ICE_CREAM_SANDWICH_MR1){
mViewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}else{
mViewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
});
/*Fragment f = new GridViewFragment();
FragmentTransaction t = getFragmentManager().beginTransaction();
t.replace(R.id.main_home_frag, f);
t.commit();*/
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Adapter class
*
* This adapter class sets up GridFragment objects to be displayed by a
* ViewPager.
*/
public static class MyAdapter extends FragmentStatePagerAdapter implements IconPagerAdapter {
private TopicList mTopicList;
private int mNumItems = 0;
private int mNumFragments = 0;
/**
* Return a new adapter.
*/
public MyAdapter(FragmentManager fm, TopicList db, Resources res) {
super(fm);
setup(db, res);
}
/**
* Get the number of fragments to be displayed in the ViewPager.
*/
#Override
public int getCount() {
Log.i(TAG, "getCount : mNumFragments = "+mNumFragments);
return mNumFragments;
}
/**
* Return a new GridFragment that is used to display n items at the
* position given.
*
* #param position
* int - the position of the fragement; 0..numFragments-1
*/
#Override
public Fragment getItem(int position) {
// Create a new Fragment and supply the fragment number, image
// position, and image count as arguments.
// (This was how arguments were handled in the original pager
// example.)
Bundle args = new Bundle();
args.putInt("num", position + 1);
args.putInt("firstImage", position * mNumItems);
// The last page might not have the full number of items.
int imageCount = mNumItems;
if (position == (mNumFragments - 1)) {
int numTopics = mTopicList.getNumTopics();
int rem = numTopics % mNumItems;
if (rem > 0)
imageCount = rem;
}
args.putInt("imageCount", imageCount);
args.putSerializable("topicList", TopicList.getInstance());
// Return a new GridFragment object.
Log.i(TAG, "created fragmenat number:==== "+position+" "+1);
GridViewFragmentPhone f = new GridViewFragmentPhone();
f.setArguments(args);
Log.i(TAG, "getItem : imageCount = "+imageCount);
return f;
}
/**
* Set up the adapter using information from a TopicList and resources
* object. When this method completes, all the instance variables of the
* adapter are valid;
*
* #param tlist
* TopicList
* #param res
* Resources
* #return void
*/
void setup(TopicList tlist, Resources res) {
mTopicList = tlist;
if ((tlist == null) || (res == null)) {
mNumItems = 2;//DEFAULT_NUM_ITEMS;
mNumFragments = 2;//DEFAULT_NUM_FRAGMENTS;
} else {
int numTopics = tlist.getNumTopics();
int numRowsGV = res.getInteger(R.integer.num_of_rows_gridview);
int numColsGV = res.getInteger(R.integer.num_of_cols_gridview);
int numTopicsPerPage = numRowsGV * numColsGV;
int numFragments = numTopics / numTopicsPerPage;
if (numTopics % numTopicsPerPage != 0)
numFragments++; // Add one if there is a partial page
mNumFragments = numFragments;
mNumItems = numTopicsPerPage;
}
} // end setup
#Override
public int getIconResId(int index) {
int[] ICON = new int[mNumFragments];
for (int i = 0; i < mNumFragments; i++) {
ICON[i] = R.drawable.slidericon;
}
return ICON[index % ICON.length];
}
} // end class MyAdapter
#Override
public void onGridViewVisibilityChanged(boolean hide) {
if(hide){
homeFragmentLL.setVisibility(View.GONE);
}else {
homeFragmentLL.setVisibility(View.VISIBLE);
}
}
#Override
public void onDetach() {
super.onDetach();
activity = null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
private class CmsPropertyAsync extends AsyncTask<String, Void, String> {
MainActivity context;
CmsPropertyAsync(MainActivity activityTab) {
context = activityTab;
}
#Override
protected String doInBackground(String... params) {
String propertyId = UConnectUtils.getPropertyId(PreferenceManager.getDefaultSharedPreferences(context),getResources().getString(R.string.property_id));
if(propertyId != null && propertyId.length() > 0){
return propertyId;
}
return UConnectUtils.requestPropertyId(params[0], params[1]);
}
#Override
protected void onPostExecute(String propertyId) {
if(propertyId == null){
indiacatorDialog.dismiss();
showPropertyIdTimeoutAlert(getActivity());
return;
}
SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
editor.putString(getString(R.string.property_id),propertyId).commit();
String url = null;
String locale = Locale.getDefault().getLanguage();
url = UCConstants.CMS_BASE_URL+"mainMenu?propertyId="+propertyId+"&lang="+locale;
JsonObjectRequest jsObjRequest = new JsonObjectRequest(
Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
parseJson(response);
indiacatorDialog.dismiss();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (activity != null) {
// activity.getConnection(error);
}
indiacatorDialog.dismiss();
}
});
ImageCacheManager.getInstance().getQueueForMainmenu().add(jsObjRequest);
}
}
private void indicatorAnim() {
if (indiacatorDialog != null) {
ImageView alertIndicator = (ImageView) indiacatorDialog.findViewById(R.id.alert_indicator);
alertIndicator.startAnimation(mRotateAnim);
if (!getActivity().isFinishing()) {
indiacatorDialog.show();
}
}
}
// Show alert for Time out
private void showPropertyIdTimeoutAlert(final Activity context) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(context);
alertDialog.setIcon(R.drawable.alert_dialog_icon);
alertDialog.setTitle(context.getString(R.string.timeout_msg));
alertDialog.setMessage(context.getString(R.string.timeout_msg2));
alertDialog.setPositiveButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
indicatorAnim();
// for property id
new CmsPropertyAsync(activity).execute(UCConstants.CMS_CONFIG_URL, UCConstants.CMS_CONFIG_KEY);
}
});
alertDialog.setNegativeButton("Cancel", new OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
getActivity().finish();
}
});
AlertDialog alert = alertDialog.create();
alert.setCancelable(false);
alert.setCanceledOnTouchOutside(false);
if (context != null && !context.isFinishing()) {
alert.show();
}
}
}
Actually, some data is being saved with onSavedInstaceState(). The data is not being deleted when process has been killed on LowMemory.
I fixed this with
#Override
protected void onSaveInstanceState(Bundle outState) {
//super.onSaveInstanceState(outState);
}
Just do not call super class. Just comment like above