I am using Johan Nilsson Android Pull to Refresh library in my android application. The problem I am having is that the onRefresh method seems to not being called (since none of my logs are displayed) what is causing this and how do I fix it.
public class MyFragment extends RoboFragment implements ResponseListener<List<TimelineItem>>{
#InjectView (R.id.TwitterList) private PullToRefreshListView listView;
private List<TimelineItem> results;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState)
{
return inflater.inflate(R.layout.fragment_timeline, container,false);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState)
{
super.onViewCreated(view, savedInstanceState);
listView.setOnRefreshListener(new OnRefreshListener() {
public void onRefresh() {
Log.v("onRefresh", "done");
new FetchNewData().execute("");
}
});
TimelineTask request = new TimelineTask(getActivity());
request.onResponseListener(this);
request.execute(new String());
}
/**
* Callback handler that is called
* after data is fetched from server.
* #author mario
*/
public void onComplete(List<TimelineItem> result)
{
if (result != null && !result.isEmpty())
{
this.results = result;
Collections.sort(results,Collections.reverseOrder());
TimelineAdapter adapter = new TimelineAdapter(getActivity(),R.layout.fragment_timeline_item, results);
listView.setAdapter(adapter);
}
else
Toast.makeText(getActivity(), "No Account! Available Please an Account", Toast.LENGTH_LONG).show();
}//end onComplete method
private class FetchNewData extends AsyncTask<String, Void,List<TimelineItem> >
{
#Override
protected void onPostExecute(List<TimelineItem> result)
{
results.addAll(result);
listView.onRefreshComplete();
Log.v("onPostExecuted", "done");
}
#Override
protected List<TimelineItem> doInBackground(String... params)
{
Log.v("doInBackground", "done");
Collections.sort(results);
return results;
}
}
Related
I have to create a RecyclerView which is updated every time a new item is created by my AsyncTask. So the RecyclerView is building itself up gradually.
Every Item is generated and then the Thread sleeps for a time to see the progress slower.
I tried to get the Adapter and update it with notifyDataSetChanged(), but it wont work like this. The Error I get is:
Only the original thread that created a view hierarchy can touch its
views.
Another idea was to update the adapter in my MainActivity with the use of a interface. But I dont exactly know how to do that. First I have to know if its the right way to use an interface or if there is a better way or maybe a really easy solution for my problem.
public class MainActivity extends AppCompatActivity implements ListAdapter.Listener{
static RecyclerView recyclerView;
static ListAdapter adapter;
#Override
public void click(String name) {
if(getResources().getConfiguration().orientation== Configuration.ORIENTATION_LANDSCAPE){
DetailsFragment detailsFragment = (DetailsFragment)getSupportFragmentManager().findFragmentById(R.id.fragment_details);
detailsFragment.setData(name);
}
else{
Toast.makeText(this, "clicked", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(this, DetailsActivity.class);
intent.putExtra("sorte_name", name);
startActivity(intent);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initRecyclerView();
new DataContainer().execute();
}
private void initRecyclerView(){
recyclerView = findViewById(R.id.meinRecyclerView);
adapter = new ListAdapter(this, DataContainer.meineSortenListe, this);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
}
public class DataContainer extends AsyncTask<Void, Void, Void> {
public static ArrayList<String> meineSortenListe = new ArrayList<String>();
ListAdapter myAdapter;
#Override
protected void onPreExecute() {
myAdapter =(ListAdapter)MainActivity.recyclerView.getAdapter();
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... voids) {
for(int i= 0; i<50; i++){
meineSortenListe.add("Sorte "+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
onProgressUpdate();
}
Log.i("info", "array befüllt");
return null;
}
#Override
protected void onProgressUpdate(Void... values) {
myAdapter.notifyDataSetChanged();
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
}
}
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder>{
private ArrayList<String> mSorten;
private Context mContext;
private Listener listener;
public interface Listener{
void click(String name);
}
//Constructor
public ListAdapter(Context mContext, ArrayList<String> sortenListe, Listener listener) {
this.mContext = mContext;
this.mSorten = sortenListe;
this.listener=listener;
}
///////////////////////
public class ViewHolder extends RecyclerView.ViewHolder {
TextView sortenName;
LinearLayout sorteLayout;
public ViewHolder(View itemView) {
super(itemView);
sortenName = itemView.findViewById(R.id.nameSorte);
sorteLayout = itemView.findViewById(R.id.sorteLayout);
}
}
////////////////////////////////
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, final int position) {
holder.sortenName.setText(mSorten.get(position));
holder.sorteLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
listener.click(mSorten.get(position));
}
});
}
#Override
public int getItemCount() {
return mSorten.size();
}
}
In Android, only the UI thread can update views. (It is possible to trigger UI updates in onPostExecute, since onPostExecute is switching to the UI thread.)
Since you are still in the doInBackground() function, you need a Handler to send a Runnable with your code to the UI thread's MessageQueue.
So in your DataContainer, change onProgressUpdate to
protected void onProgressUpdate(Void... values) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable(){
public void run() {
myAdapter.notifyDataSetChanged();
}
});
super.onProgressUpdate(values);
}
I am not experienced on android and I implemented code for Tablayout, where I have six tab and each tab has there ListView where data will come from server. I am using VolleyResponse to fetch the data but all the tab's data come at open time. I need data should be come on swipe and when user will go previous swipe data should not load again. So please guide me what should I do?
Below is my code for fragment.
private void setupViewPager(ViewPager viewPager) {
int numberOfPages=7;
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
adapter.addFragment(new Matches_Tab(), "Matches");
adapter.addFragment(new NewMatches_Tab(), "New matches");
adapter.addFragment(new Similar_Matchs_Tab(), "Similar Matches");
adapter.addFragment(new ShortlistTab(), "ShortListed");
adapter.addFragment(new Viewed_My_Profile(), "View My Profile");
adapter.addFragment(new ShortListedMeTab(), "ShortListed Me");
adapter.addFragment(new Photo_Request_Received(), "Photo Request Received");
viewPager.setOffscreenPageLimit(numberOfPages);
viewPager.setAdapter(adapter);
}
Fragment class
public class Matches_Tab extends Fragment{
// Session Manager Class
SessionManager session;
String email;
public String JSON_URL;
private ListView listView;
public Matches_Tab() {}
private static Matches_Tab instance;
public static synchronized Matches_Tab getInstance(Bundle data){
if (instance == null) {
instance = new Matches_Tab();
instance.setArguments(data);
}
return instance;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TypefaceUtil.overrideFont(getContext(), "SERIF", "Peddana-Regular.ttf");
// Session class instance
session = new SessionManager(getActivity());
// get user data from session
HashMap<String, String> user = session.getUserDetails();
email = user.get(SessionManager.KEY_EMAIL);
JSON_URL = "https://www.maangal.com/maangal_mobile/matches.php?matri_id="+email;
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.matches_tab, container, false);
// ProgressBar progressbar = (ProgressBar) view.findViewById(R.id.progressBar);
listView = (ListView) view.findViewById(R.id.listView);
sendRequest();
//getArguments();
return view;
}
private void sendRequest(){
final ProgressDialog loading = ProgressDialog.show(getActivity(),"Loading Data", "Please wait...",false,false);
StringRequest stringRequest = new StringRequest(Request.Method.POST,JSON_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
loading.dismiss();
showJSON(response);
Log.e("Broder Matches s----->",response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getContext(),error.getMessage(), Toast.LENGTH_LONG).show();
}
});
int MY_SOCKET_TIMEOUT_MS = 30000;
stringRequest.setRetryPolicy(new DefaultRetryPolicy(
MY_SOCKET_TIMEOUT_MS, DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
RequestQueue requestQueue = Volley.newRequestQueue(getContext());
requestQueue.add(stringRequest);
}
protected void showJSON(String json){
ParseJSON pj = new ParseJSON(json);
pj.parseJSON();
Profile_Match_custom_List cl = new Profile_Match_custom_List(getActivity(), ParseJSON.ids,ParseJSON.ages, ParseJSON.heights, ParseJSON.communities,ParseJSON.castes,ParseJSON.educations,ParseJSON.occupations,ParseJSON.incomes,ParseJSON.pics,ParseJSON.locations,ParseJSON.shortlist,ParseJSON.expressinterest);
listView.setAdapter(cl);
}
}
You can extend BaseFragment
public abstract class BaseFragment extends Fragment {
protected Activity mActivity;
/**
* isFragmentVisible
*/
private boolean isFragmentVisible;
/**
* View in onCreateView is ok
*/
private boolean isPrepared;
/**
* isFirstLoad
*/
private boolean isFirstLoad = true;
/**
* isForceLoad
*/
private boolean isForceLoad = false;
/**
* onAttach Activity
*
* #param context
*/
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (Activity) context;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container
, Bundle savedInstanceState) {
isFirstLoad = true;
View view = LayoutInflater.from(mActivity)
.inflate(getLayoutId(), container, false);
initView(view, savedInstanceState);
isPrepared = true;
lazyLoad();
return view;
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
#Override
public void onDestroy() {
super.onDestroy();
}
/**
* want to load data ,need set in onCreateView
* isPrepared = true;
*/
protected void lazyLoad() {
if (isPrepared() && isFragmentVisible()) {
if (isForceLoad || isFirstLoad()) {
isForceLoad = false;
isFirstLoad = false;
initData();
}
}
}
public boolean isPrepared() {
return isPrepared;
}
public boolean isFirstLoad() {
return isFirstLoad;
}
public boolean isFragmentVisible() {
return isFragmentVisible;
}
/**
* use with viewpager
*
* #param isVisibleToUser is visible for user
*/
#Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (getUserVisibleHint()) {
onVisible();
} else {
onInvisible();
}
}
/**
* if you use show hide to set fragment ,do this
*
* #param hidden hidden True if the fragment is now hidden, false if it is not
* visible.
*/
#Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (!hidden) {
onVisible();
} else {
onInvisible();
}
}
protected void onVisible() {
isFragmentVisible = true;
lazyLoad();
}
protected void onInvisible() {
isFragmentVisible = false;
}
/**
* set force load
*/
public void setForceLoad(boolean forceLoad) {
this.isForceLoad = forceLoad;
}
/**
* getLayoutId ,like : R.layout.fragment
*
* #return
*/
protected abstract int getLayoutId();
/**
* initView
*
* #param view
* #param savedInstanceState
*/
protected abstract void initView(View view, Bundle savedInstanceState);
/**
* load data here
*/
protected abstract void initData();
}
Then load data in initData method .
#Override
protected void initData() {
// request here
}
Note
the main method is setUserVisibleHint and onHiddenChanged
add some boolean flag to determine whether the data has been loaded, view creates etc.
You can use ViewPager.OnPageChangeListener to get callbacks for when a page becomes visible.
Check below code.
viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
#Override
public void onPageSelected(int position) {
// Add your logic
}
});
Aternate solution
tabLayout.setupWithViewPager(mViewPager);
tabLayout.setOnTabSelectedListener(
new TabLayout.ViewPagerOnTabSelectedListener(mViewPager) {
#Override
public void onTabSelected(TabLayout.Tab tab) {
super.onTabSelected(tab);
//put your Logic here
}
});
If you are using ViewPager and you are getting data for all the tabs in one API call then I suggest you set the offset of the viewpager equal to the number of tabs.
ViewPager vp = ...;
vp.setOffscreenPageLimit(numberOfTabsHERE);
NOTE: Only use this if there is not much data to show else you may get a MemoryOutOfException.
If you do have a lot of tabs and a lot of data. Using Singleton pattern for fragments is a good option.
public class MyFragment extends Fragment {
private static MyFragment instance;
public static synchronized MyFragment getInstance(Bundle data // if any){
if (instance == null) {
instance = new MyFragment();
instance.setArguments(data);
}
return instance;
}
}
...
onCreateView{.... getArguments()}
Got two empty Activites(A and B), which just hold two fragments inside ViewPager of Activity A.
I do not have code errors, everything seems fine.
When I lunch my app and click on button, nothing happens.I was trying just to log something, but still nothing is happening.
I am using ButterKnife, and so far everything was perfect.I got almost same Fragment and it is performing fine, but OnClick inside Fragment B is not working.I tried to add some more OnClick methods, but none of them worked for me.XML looks good,looks almost same as fragment A.
Fragment B is not complex, it just three TextViews and Button.
Here is code for my fragment B:
public class ForgotPasswordFragmentComplete extends BaseFragment
implements BaseView {
private Realm realm;
private Email model;
#Bind(R.id.btn_resend)
AppCompatButton resendEmail;
#Inject
ForgotPasswordPresenter presenter;
#OnClick(R.id.btn_resend)
public void resendButton() {
Log.d("ResendOnclick", "Checking OnClickMethod ");
Realm realm2 = getRealm();
RealmQuery<Email> queryUserResend = realm2.where(Email.class);
Email resultResend = queryUserResend.findFirst();
ForgotPasswordPayload forgotPayload = new ForgotPasswordPayload(resultResend.getUsername());
this.presenter.subscribe(forgotPayload);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerForgotPasswordCompletedComponent.builder()
.applicationComponent(
((AndroidApplication) getActivity().getApplication()).getApplicationComponent())
.forgotPasswordCompletedModule(new ForgotPasswordCompletedModule())
.build()
.inject(this);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
protected void onCreateViewWidgetInitialization(View view) {
super.onCreateViewWidgetInitialization(view);
}
#Override
public void onStart() {
super.onStart();
getEmail();
}
public void getEmail(){
Realm realm = getRealm();
RealmQuery<Email> queryUser = realm.where(Email.class);
Email result1 = queryUser.findFirst();
resendEmailTxt = (AutoResizeTextView) getView().findViewById(R.id.resend_user_email);
if (resendEmailTxt != null) {
this.resendEmailTxt.setText(result1.getUsername());
}
}
#Override
public void onDestroy() {
super.onDestroy();
realm.close();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_forgot_password_fragment_complete, container, false);
}
#Override
protected int getFragmentLayoutId() {
return R.layout.fragment_forgot_password_fragment_complete;
}
You need to bind the fragment's view object before you can use it. Try putting the following code inside onCreateView() :
View rootView = inflater.inflate(R.layout.fragment_forgot_password_fragment_complete, container, false);
ButterKnife.bind(this, rootView);
return rootView;
In onAttach function eclipse shows error stating
The method onAttach(Activity) in the type Fragment is not applicable
for the arguments (Context)
although it is clearly Context type variable passed
import android.content.Context;
public class MyListFragment extends Fragment{
private OnItemSelectedListener listener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rsslist_overview,
container, false);
Button button = (Button) view.findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
updateDetail("fake");
}
});
return view;
}
public interface OnItemSelectedListener {
public void onRssItemSelected(String link);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnItemSelectedListener) {
listener = (OnItemSelectedListener) context;
} else {
throw new ClassCastException(context.toString()
+ " must implemenet MyListFragment.OnItemSelectedListener");
}
}
#Override
public void onDetach() {
super.onDetach();
listener = null;
}
// may also be triggered from the Activity
public void updateDetail(String uri) {
// create a string just for testing
String newTime = String.valueOf(System.currentTimeMillis());
// inform the Activity about the change based
// interface defintion
listener.onRssItemSelected(newTime);
}
}
If you are using API < 23 then
public void onAttach(Context context) {
should be
public void onAttach(Activity context) {
See official docs
Note:
onAttach(Context context) was added in api 23. See this
I had same problem can you try to pass Activity in your onAtach method like this:
#Override
public void onAttach(Activity activity) {
super.onAttach(context);
if (context instanceof OnItemSelectedListener) {
listener = (OnItemSelectedListener) activity;
} else {
throw new ClassCastException(context.toString()
+ " must implemenet MyListFragment.OnItemSelectedListener");
}
}
and tell me if it works or not.
Hope to help!
This question already has answers here:
How can I fix 'android.os.NetworkOnMainThreadException'?
(66 answers)
Closed 7 years ago.
I am getting NetworkOnMainThreadException while running my code. I have a Fragment where i am showing some ID from the webservices that gets called when i click on a button. Following is my code. I have used Asynctask as mentioned for this purpose but still i keep getting this error.
public class AboutMeFragView extends Fragment implements ObsrvIntModel {
private Button getConfButton;
private UsrDataCtrl m_UsrDataCtrl;
private UsrDataModel m_UsrDataModel;
private boolean m_bResUpdate;
private String retc;
public static AboutMeFragView newInstance() {
AboutMeFragView aboutMeFragment = new AboutMeFragView();
return aboutMeFragment;
}
public AboutMeFragView() {}
//inflate the data on this view from the relevant xml file fragment_about_me.xml
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_about_me, container, false);
getConfButton = (Button) rootView.findViewById(R.id.get_config_button);
getConfButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Toast.makeText(getActivity(), "Implement methods to get the configuration", Toast.LENGTH_LONG).show();
//call your model to get the data from the server and show it on the UI
enableStrictMode();
new GetCredsTask().execute();
}
});
return rootView;
}
//whenever fragment is associated with our main activity
//following method would get called
//also we make sure here that whatever navigation activity is selected
//our action bar shows up the same activity name
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
((CpActivity)activity).onSectionAttached(1);
}
#Override
public void update(boolean result) {
m_bResUpdate = result;
}
public void enableStrictMode()
{
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
private class GetCredsTask extends AsyncTask<Void, Void, String> {
public GetCredsTask() {
super();
}
#Override
protected String doInBackground(Void... params) {
m_UsrDataModel = new UsrDataModel(AboutMeFragView.this);
m_UsrDataCtrl = new UsrDataCtrl(m_UsrDataModel);
m_UsrDataCtrl.execConfig();
retc = m_UsrDataModel.getM_authid();
if(m_bResUpdate != true) {
retc = "404";
}
Log.d("doInBackground", retc);
return retc;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
Log.d("onPostExecute", retc);
if (m_bResUpdate == true)
Toast.makeText(getActivity(), s, Toast.LENGTH_LONG).show();
else
Toast.makeText(getActivity(), retc, Toast.LENGTH_LONG).show();
super.onPostExecute(s);
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
protected void execute() {
doInBackground();
}
}
}
Thanks
You are overriding execute(), which is causing the task to be posted on the main thread instead of executed in the background. The normal implementation posts the execution of the task to a background thread, i.e.
Edit:
public final AsyncTask<Params, Progress, Result> More ...execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);
}