Frozen snapshot of list rendered with SwipeRefreshLayout in ViewPager - android

Consider an Android activity that is subclass ofandroid.support.v4.app.FragmentActivity. It contains several apges managed by FragmentStatePagerAdapter. Each page contains a ListView wrapped by android.support.v4.widget.SwipeRefreshLayout. The following screenshot shows the initial state of this activity.
Now, I swipe down to refresh the list on page 0. The refresh animation appears. Now, let's swipe to the right on page 2 and then back to page 0.
The refresh animation is still visible. This seems strange to me as page 0 was destroyed and created again. Moreover, if I swipe up (trying to scroll to the end of the list on page 0) some strange layer is rendered over the page which seems to contain the old state of the page from the time it was destroyed.
I have no idea why this happens and how to fix it. Thanks for any help.
Here is the source code of a minimal application that consists of 3 layout files, an activity class, a fragment class, a manifest file and a build script.
swipeandroid/src/main/res/layout/service_schedule_activity.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/servicePager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.PagerTabStrip
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"/>
</android.support.v4.view.ViewPager>
swipeandroid/src/main/res/layout/service_schedule_tab_fragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.SwipeRefreshLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/serviceRefreshLayout"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="#+id/timeSlots"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.v4.widget.SwipeRefreshLayout>
swipeandroid/src/main/res/layout/service_schedule_row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"/>
</RelativeLayout>
swipeandroid/src/main/java/com/swipetest/ServiceScheduleActivity.java
package com.swipetest;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
public class ServiceScheduleActivity extends FragmentActivity {
#Override
protected void onCreate(final Bundle inState) {
// call super class
super.onCreate(inState);
// set content
setContentView(R.layout.service_schedule_activity);
// set up service pager
((ViewPager) findViewById(R.id.servicePager)).setAdapter(new ServiceFragmentPagerAdapter());
}
private class ServiceFragmentPagerAdapter extends FragmentStatePagerAdapter {
public ServiceFragmentPagerAdapter() {
super(getSupportFragmentManager());
}
#Override
public int getCount() {
return 5;
}
#Override
public Fragment getItem(final int position) {
return ServiceScheduleTabFragment.newInstance(position);
}
#Override
public CharSequence getPageTitle(final int position) {
return String.format("page %d", position);
}
}
}
swipeandroid/src/main/java/com/swipetest/ServiceScheduleTabFragment.java
package com.swipetest;
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.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class ServiceScheduleTabFragment extends Fragment {
private static final String TAB_POSITION_ARGUMENT = "tabPosition";
public static ServiceScheduleTabFragment newInstance(final int tabPosition) {
// prepare arguments
final Bundle arguments = new Bundle();
arguments.putInt(TAB_POSITION_ARGUMENT, tabPosition);
// create fragment
final ServiceScheduleTabFragment fragment = new ServiceScheduleTabFragment();
fragment.setArguments(arguments);
return fragment;
}
#Override
public View onCreateView(final LayoutInflater layoutInflater, final ViewGroup parent, final Bundle inState) {
// create fragment root view
final View rootView = layoutInflater.inflate(R.layout.service_schedule_tab_fragment, parent, false);
// initialize time slot list view
final ListView timeSlotListView = (ListView) rootView.findViewById(R.id.timeSlots);
timeSlotListView.setAdapter(new TimeSlotListAdapter());
// return fragment root view
return rootView;
}
private int getTabPosition() {
return getArguments().getInt(TAB_POSITION_ARGUMENT);
}
private static class TimeSlotRowViewHolder {
private final TextView timeView;
public TimeSlotRowViewHolder(final View rowView) {
timeView = (TextView) rowView.findViewById(R.id.time);
}
public TextView getTimeView() {
return timeView;
}
}
private class TimeSlotListAdapter extends BaseAdapter {
#Override
public int getCount() {
return 80;
}
#Override
public Object getItem(final int position) {
return position;
}
#Override
public long getItemId(final int position) {
return position;
}
#Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
// reuse or create row view
final View rowView;
if (convertView != null) {
rowView = convertView;
} else {
rowView = LayoutInflater.from(getContext()).inflate(R.layout.service_schedule_row, parent, false);
rowView.setTag(new TimeSlotRowViewHolder(rowView));
}
// fill data
final TimeSlotRowViewHolder rowViewHolder = (TimeSlotRowViewHolder) rowView.getTag();
rowViewHolder.getTimeView().setText(String.format("tab %d, row %d", getTabPosition(), position));
return rowView;
}
}
}
swipeandroid/src/main/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.swipetest"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23"/>
<application
android:name="android.app.Application"
android:label="Swipe Test"
android:allowBackup="false">
<activity
android:name="com.swipetest.ServiceScheduleActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
swipeandroid/build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
}
}
apply plugin: 'com.android.application'
repositories {
mavenCentral()
}
dependencies {
compile "com.android.support:support-v4:23.1.1"
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
buildTypes {
debug {
debuggable true
minifyEnabled false
}
}
}

Try to clear the list and then load the new data on swipe refresh.
As mentioned in the comment.

Finally, I have discovered a workaround that is very simple to implement and fixes the issue.
Just wrap the SwipeRefreshLayout e.g. by FrameLayout. It seems that the ViewPager does not like SwipeRefreshLayout being the root of the view hierarchy of a page fragment.
Anyway, this issue looks like a bug in Android Support Library. See
https://code.google.com/p/android/issues/detail?id=194957
I have also tried other workarounds that do not work:
Replacing FragmentStatePagerAdapter by `FragmentPagerAdapter will not help.
Calling mySwipeRefreshLayout.setRefreshing(false) in onPause will not help.
Modifying the FragmentStatePagerAdapter so that it does not remeber states of destroyed pages will not help.
The following workarounds can help somehow but I prefer the suggested wrapping of SwipeRefreshLayout anyway:
Clearing the data (so that the ListView contains no rows) in SwipeRefreshLayout.OnRefreshListener#onRefresh() helps only if the ListView has transparent background. The unwanted snapshot is probably still rendered over the first page but it is fully transparent.
You can disallow paging for the time of refresh animation. However, this takes some effort as you must subclass both ViewPager and PagerTabStrip and prevent appropriate UI events in your subclasses.
Of course, you can avoid using SwipeRefreshLayout in ViewPager completely but this does not seem to be necessary.

Related

Android Viewpager Fragment Network Call handling

Inside a viewpager fragment is having a network call to load the data. Due to this network call it creates a lag for users. How can i handle network call inside a fragment which reside inside a viewpager. I just dont want my users to see the lag as it takes 4-7 seconds to load a fragment. what is efficent way to load a fragment via network call for Viewpager
below is code for Activity:
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import com.test.androidtest20202.R;
import com.test.androidtest20202.adapter.ViewPagerAdapter;
import java.util.ArrayList;
import java.util.List;
public class ViewPagerActivity extends AppCompatActivity {
ViewPagerAdapter adapter;
ViewPager viewPager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_pager);
viewPager = findViewById(R.id.viewpager);
ArrayList<Integer> task_ids = new ArrayList<>();
for(int i=0;i<5;i++){
task_ids.add(i);
}
adapter = new ViewPagerAdapter(this, getSupportFragmentManager(),task_ids);
viewPager.setAdapter(adapter);
}
}
Below activity xml layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activity.ViewPagerActivity">
<androidx.viewpager.widget.ViewPager
android:id="#+id/viewpager"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="#color/white"
android:largeHeap="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Below is my Viewpager Adapter :
import android.content.Context;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import com.test.androidtest20202.fragments.ViewPagerFragment;
import java.util.ArrayList;
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
private ArrayList<Integer> taskid;
private SparseArray<Fragment> registeredFragments = new SparseArray<>();
public ViewPagerAdapter(Context context, #NonNull FragmentManager fm, ArrayList<Integer> taskid) {
super(fm);
this.taskid = taskid;
}
#NonNull
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
Bundle bundle = new Bundle();
bundle.putInt("COMPLETED_TASKID", taskid.get(position));
fragment = new ViewPagerFragment();
registeredFragments.put(position, fragment);
fragment.setArguments(bundle);
return fragment;
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
#Override
public int getCount() {
return taskid.size();
}
}
Below is my Viewpager Fragment code:
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.test.androidtest20202.R;
import com.test.androidtest20202.pojo.SaleskenResponse;
import com.test.androidtest20202.util.RestApiClient;
import com.test.androidtest20202.util.RestUrlInterface;
import butterknife.BindView;
import butterknife.ButterKnife;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ViewPagerFragment extends Fragment {
private static final String TAG = "ViewPagerFragment";
private ViewGroup container;
private LayoutInflater inflater;
#BindView(R.id.textView2)
TextView textView;
private AsyncTask mAsyncTask;
public RestUrlInterface restUrlInterface;
Integer taskid = -1;
public View onCreateView(LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
this.container = container;
this.inflater = inflater;
return initializeView();
}
private View initializeView() {
final View view;
view = inflater.inflate(
R.layout.fragment_laout, container, false);
ButterKnife.bind(this, view);
restUrlInterface = RestApiClient.getClient(getContext()).create(RestUrlInterface.class);
if (getArguments() != null) {
taskid = getArguments().getInt("COMPLETED_TASKID");
}
return view;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Call<SaleskenResponse> task_details = restUrlInterface.getTaskDetail(getString(R.string.token), taskid );
task_details.enqueue(new Callback<SaleskenResponse>() {
#Override
public void onResponse(Call<SaleskenResponse> call, Response<SaleskenResponse> response) {
switch (response.code()) {
case 200:
textView.setText( response.body().toString());
}
}
#Override
public void onFailure(Call<SaleskenResponse> call, Throwable t) {
}
});
}
}
Below is Fragment layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
So as the data only need to be loaded once I would do this in the activity onCreate just after you have created your task_ids ArrayList.
You seem to be using a custom RestAPI package, but most package do Network request asynchronously, so when you get a response for each request you would then store them in a shared viewmodel using the unique task_id's as an index.
The shared viewmodel can then be observed from the fragment and when the data is available the fragment will be notified to use it.
So basically start the Network load as soon as the Activity starts, to give it a head start before the viewpager is setup and the first Fragment is loaded, and storing your data independently of the Activity and Fragments.
Note this won't guarantee that the first fragment in the viewpager will have it's data available by the time it is shown but at least it should be part way to having it available and by the time the user swaps to the second page in the viewpager that data should already be available.
How to share data between Fragments with a shared viewmodel example is at https://blog.mindorks.com/shared-viewmodel-in-android-shared-between-fragments (this example is between 2 fragments but the same concept can be used for comms between the background RestAPI calls in the Activity and each Fragment in the viewpager.
There might be a trade off on first page load time between requesting the data for all task_id's in parallel vs doing them sequentially start with the first page and then once that has loaded request the next one, etc.
Sorry no code example (other than in the link on how to use shared viewmodel) but is more of an architectural answer as you seem to be using a custom RestAPI package I'm not familiar with.
This is basically caching the data for each fragment as soon as the activity starts and the Fragments just display the cached data.
If you can cache between each time the Activity is started you could instead of the shared viewmodel use a Database like Android Rooms, then when it Activity is started it has the data from last time the Activity was started and really it could in the background just check the freshness of the data stored in the database with a RestAPI request.

Android viewbinding problem when including layout with the <include> tag with direct child in it

I am trying to include a layout that contains the only recyclerView in it.
home_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/home_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToPadding="false"
android:paddingStart="#dimen/_8sdp"
android:paddingEnd="#dimen/_8sdp" />
And include this in the main layout like below.
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include
android:id="#+id/slider_recyclerView"
layout="#layout/home_recycler_view" />
<include
android:id="#+id/boards_recyclerview"
layout="#layout/home_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_12sdp" />
<include
android:id="#+id/news_recyclerview"
layout="#layout/home_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_12sdp" />
<include
android:id="#+id/video_recyclerview"
layout="#layout/home_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/_12sdp"
android:layout_marginBottom="#dimen/_2sdp" />
</LinearLayout>
In this case, it gives me an error like,
java.lang.NullPointerException: Missing required view with ID: homeRecyclerView
Generated Class Of home_recycler_view.xml
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewbinding.ViewBinding;
import com.backendme.arduinolearn.R;
import java.lang.NullPointerException;
import java.lang.Override;
import java.lang.String;
public final class HomeRecyclerViewBinding implements ViewBinding {
#NonNull
private final RecyclerView rootView;
#NonNull
public final RecyclerView homeRecyclerView;
private HomeRecyclerViewBinding(#NonNull RecyclerView rootView,
#NonNull RecyclerView homeRecyclerView) {
this.rootView = rootView;
this.homeRecyclerView = homeRecyclerView;
}
#Override
#NonNull
public RecyclerView getRoot() {
return rootView;
}
#NonNull
public static HomeRecyclerViewBinding inflate(#NonNull LayoutInflater inflater) {
return inflate(inflater, null, false);
}
#NonNull
public static HomeRecyclerViewBinding inflate(#NonNull LayoutInflater inflater,
#Nullable ViewGroup parent, boolean attachToParent) {
View root = inflater.inflate(R.layout.home_recycler_view, parent, false);
if (attachToParent) {
parent.addView(root);
}
return bind(root);
}
#NonNull
public static HomeRecyclerViewBinding bind(#NonNull View rootView) {
// The body of this method is generated in a way you would not otherwise write.
// This is done to optimize the compiled bytecode for size and performance.
String missingId;
missingId: {
RecyclerView homeRecyclerView = rootView.findViewById(R.id.home_recycler_view);
if (homeRecyclerView == null) {
missingId = "homeRecyclerView";
break missingId;
}
return new HomeRecyclerViewBinding((RecyclerView) rootView, homeRecyclerView);
}
throw new NullPointerException("Missing required view with ID: ".concat(missingId));
}
}
if I wrap the recyclerView with any parent layout like frame layout than it works fine but I don't want to wrap my recyclerView in any other view.
please provide me a solution for this how can I include layout with a direct child in this case (RecyclerView) without any root or parent viewGroup in Viewbinding?
When you give ID to <include> means you are setting the id to root view of the layout you're including. In this case, you're setting the id to your recycler view and that's why It can not find the recycler view with its original ID. What you need to do is
use <merge> within the shared layout.
Wrap your RecyclerView in <merge>.
Don't give <include> any ID.
Call the bind() method of the generated class of merge layout and pass the root view of the layout you included your layout in.
Access your view from the object of merge binding
For example, you have home_recycler_view.xml so you'll have HomeRecyclerView.class generated and this is how you will access the view from this layout.
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityTestBinding.inflate(layoutInflater)
val homeRecyclerBinding= HomeRecyclerView.bind(binding.root)
setContentView(binding.root)
homeRecyclerBinding.homeRecyclerView.adapter= SomeAdapter()
}
}

Potential Glide bug - RecyclerView item lose focus when fast scrolled with Dpad on Android TV

I am attempting to make a basic photo album app for Android TV.
Using recyclerview with glide.
Issue:
When scrolling one by one slowly by pressing dpad down button, recyclerview items gain focus accurately just as expected. But when dpad down button is kept pressed, during fast scroll, recyclerview item easily lose focus and the focus is moved to any focusable view (in this case an edit text) outside the recyclerview and no scrolling is possible until manually focus is moved inside recyclerview again.
Remedies attempted:
1. If I disable image loading by Glide completely (inside onBindViewHolder()), focus is never lost and no matter how fast the scrolling is it always works as expected. This remedy is not useful as images needs to be viewed.
2. If fast scrolling is limited by overriding Activity.onKeyDown method to ignore all key inputs unless 300ms has passed since last keydown it works. Again, this feels very hacky and completely disables fast scroll with is an absolute requirement.
Please note that I have already read the related QA on stackoverflow. Which suggested it's a bug in Android support library LayoutManager code which is not the case here since without glide it works fine.
How to reproduce: Create a fragment like ListFragment (code below) and try fast scrolling by keeping Down Dpad button pressed and you will see that editText constantly getting focused.
Code:
ListFragment.java
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import java.util.Random;
public class ListFragment extends Fragment {
RequestManager glide;
public ListFragment() {
// Required empty public constructor
}
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_list, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = getActivity().findViewById(R.id.my_recycler_view);
glide = Glide.with(this);
layoutManager = new GridLayoutManager(getActivity(),8);
mAdapter = new MyAdapter();
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(mAdapter);
}
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private final String[] imageUrls = {"https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa1821c67c1430401c65/1546365481213/20181208_0034pp2+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa218a922d1c5eb370c5/1546365483758/20181208_0115pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba92340ec9ab2ea3f0f73/1546365229886/20181215_0135pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8880e2e72e38d92a482/1546365075745/20180914_0189+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba885f950b760dd6800a7/1546365086762/20180914_0168pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba9b1032be425c6948ca2/1546365375849/20180818_0014pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa184ae2379d323c4187/1546365481929/20181208_0065pp+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256b9e4fcb574ae612941/1470258368357/20160801_0045.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255d1e4fcb574ae61196f/1470256635728/20160717_0391.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25695e4fcb574ae61273c/1470258368265/20160801_0040.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256dbe4fcb574ae612b71/1470258369606/20160801_0108+pp+810+bw.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257088419c29f345a7500/1470258369115/20160801_0108+pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4f950b760dd6804fe/1546365168544/20181101_0067pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba83270a6adae0b3b6395/1546364992480/20181205_0164pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4575d1f0c318f3727/1546365171139/20181101_0050pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2543dd1758e06589e07f1/1470256544677/20160402_0075+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a253fad1758e06589e040f/1470256190368/20160402_0039+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255fae4fcb574ae611e08/1470258367476/20160717_0444b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2573be4fcb574ae613197/1470258370169/20160801_0123+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257708419c29f345a7ba7/1470258369404/20160801_0272+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25db19f74561d105005de/1470258684806/20160402_0046+810+nik2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/55076c74e4b07b36ea118be0/1470413754677/20141222_0049.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256688419c29f345a6b17/1470258368620/20160721_0097+pp2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255c9d1758e06589e1f5e/1470258367695/20160721_0012+ppb.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c21ac72b8dde5db5879498/1546363401197/20151107_0094+pp+57c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c20eb662cd945cd5b485f5/1546363401197/20151024_1026+pp+810c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/53558987e4b007661e339aa7/1470413754809/20140419_0430_pp1+5x7b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db7f3893fc0e1cdfe1bbb/1482536961660/20160507_0069b+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8019de4bb91b69d5e37/1482537012182/20160904_0012+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8346a496340ce2b8f6e/1482537056393/20160904_0043+pp+810l.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db846d482e9c87e69aa3c/1482537056630/20160904_0071+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db860d2b857ddbd63c824/1482537071373/20160904_0119+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8602e69cf4bac703ff9/1482537081308/20160904_0124+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8828419c2d595b13ee0/1482537109350/20161008_0086+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8923e00be46604ad66c/1482537119283/20161105_0068pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db895b3db2b35c2346e97/1482537128208/20161128_0181+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db89fc534a5283f35edd0/1482537156287/20161203_0126+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8a703596eeb52691ac2/1482537145676/20161206_0101.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa1821c67c1430401c65/1546365481213/20181208_0034pp2+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa218a922d1c5eb370c5/1546365483758/20181208_0115pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba92340ec9ab2ea3f0f73/1546365229886/20181215_0135pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8880e2e72e38d92a482/1546365075745/20180914_0189+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba885f950b760dd6800a7/1546365086762/20180914_0168pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba9b1032be425c6948ca2/1546365375849/20180818_0014pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2baa184ae2379d323c4187/1546365481929/20181208_0065pp+810b2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256b9e4fcb574ae612941/1470258368357/20160801_0045.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255d1e4fcb574ae61196f/1470256635728/20160717_0391.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25695e4fcb574ae61273c/1470258368265/20160801_0040.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256dbe4fcb574ae612b71/1470258369606/20160801_0108+pp+810+bw.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257088419c29f345a7500/1470258369115/20160801_0108+pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4f950b760dd6804fe/1546365168544/20181101_0067pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba83270a6adae0b3b6395/1546364992480/20181205_0164pp+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/5c2ba8e4575d1f0c318f3727/1546365171139/20181101_0050pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2543dd1758e06589e07f1/1470256544677/20160402_0075+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a253fad1758e06589e040f/1470256190368/20160402_0039+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255fae4fcb574ae611e08/1470258367476/20160717_0444b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a2573be4fcb574ae613197/1470258370169/20160801_0123+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a257708419c29f345a7ba7/1470258369404/20160801_0272+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a25db19f74561d105005de/1470258684806/20160402_0046+810+nik2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/55076c74e4b07b36ea118be0/1470413754677/20141222_0049.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a256688419c29f345a6b17/1470258368620/20160721_0097+pp2.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/57a255c9d1758e06589e1f5e/1470258367695/20160721_0012+ppb.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c21ac72b8dde5db5879498/1546363401197/20151107_0094+pp+57c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/56c20eb662cd945cd5b485f5/1546363401197/20151024_1026+pp+810c.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/53558987e4b007661e339aa7/1470413754809/20140419_0430_pp1+5x7b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db7f3893fc0e1cdfe1bbb/1482536961660/20160507_0069b+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8019de4bb91b69d5e37/1482537012182/20160904_0012+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8346a496340ce2b8f6e/1482537056393/20160904_0043+pp+810l.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db846d482e9c87e69aa3c/1482537056630/20160904_0071+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db860d2b857ddbd63c824/1482537071373/20160904_0119+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8602e69cf4bac703ff9/1482537081308/20160904_0124+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8828419c2d595b13ee0/1482537109350/20161008_0086+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8923e00be46604ad66c/1482537119283/20161105_0068pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db895b3db2b35c2346e97/1482537128208/20161128_0181+810.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db89fc534a5283f35edd0/1482537156287/20161203_0126+pp+810b.jpg","https://static1.squarespace.com/static/51d6d61de4b03f5ac28c861a/55076abee4b038dc7dbd4f2a/585db8a703596eeb52691ac2/1482537145676/20161206_0101.jpg"};
private final RequestOptions options = new RequestOptions().centerCrop();
private final Random random = new Random();
private final Handler handler = new Handler();
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView icon;
public View layout;
ViewHolder(View v) {
super(v);
layout = v;
icon = v.findViewById(R.id.icon);
}
}
#Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
LayoutInflater inflater = LayoutInflater.from(
parent.getContext());
View v =
inflater.inflate(R.layout.item_recycler_view, parent, false);
MyAdapter.ViewHolder vh = new MyAdapter.ViewHolder(v);
return vh;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder holder, final int position) {
final String name = imageUrls[random.nextInt(imageUrls.length - 1)];
//Commenting this out resolves focus loss
glide.load(name).into(holder.icon);
}
#Override
public void onViewRecycled(#NonNull ViewHolder holder) {
super.onViewRecycled(holder);
glide.clear(holder.icon);
}
// Return the size of your dataset (invoked by the layout manager)
#Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
}
}
Layouts:
item_recycler_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:foreground="#drawable/fg_selectable"
android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="false"
android:descendantFocusability="blocksDescendants"
android:layout_margin="2dp"
>
<ImageView
android:id="#+id/icon"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="27:41"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="#color/colorPrimaryDark"
tools:src="#tools:sample/avatars"
/>
</android.support.constraint.ConstraintLayout>
fragment_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ListFragment"
android:orientation="horizontal"
>
<EditText
android:id="#+id/editText"
android:text="test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:nextFocusDown="#id/editText"
/>
<android.support.v7.widget.RecyclerView
android:id="#+id/my_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
Why do you need glide.clear() in onViewRecycled? My guess is that it has to do with frequent glide loading and clearing during fast scrolls. Glide may be getting somewhat confused. Also, why not Leanback Library and GridFragment? From my experience it works just fine with Glide and fast scrolling.

How can I set a header over a RecyclerView?

My Android app lists the audio files inside an specific folder by using a RecyclerView. However, I want to display at the top of that RecyclerView a header that indicates the current folder with a TextView, but I do not know how to do it.
Is there an easy way to achieve that?
This is my adapter code:
package vmc.songbook;
import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.io.File;
import java.util.Date;
public class RecordingsAdapter extends RecyclerView.Adapter<RecordingsAdapter.ViewHolder> {
// Attributes
protected File[] files; // Files to include in the RecyclerView
protected LayoutInflater inflater; // This class creates the layout based on the XML file
/** Constructor */
public RecordingsAdapter(Context context, File[] files) {
this.files = files;
inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
/** ViewHolder is needed to store the variables of each file */
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView file_name, file_duration, file_date;
public ViewHolder(View itemView) {
super(itemView);
file_name = (TextView) itemView.findViewById(R.id.file_name);
file_duration = (TextView) itemView.findViewById(R.id.file_duration);
file_date = (TextView) itemView.findViewById(R.id.file_date);
}
}
/** Inflating the ViewHolder based on the XML file*/
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = inflater.inflate(R.layout.file_element, null);
return new ViewHolder(v);
}
/** Maximum number of items */
#Override public int getItemCount() {
return files.length;
}
/** Customizing the ViewHolder */
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Setting the date
Date lastModDate = new Date(files[position].lastModified());
holder.file_date.setText(lastModDate.toString());
// Setting the audio duration
String duration = getDuration(files[position]);
holder.file_duration.setText(duration);
// Setting the audio name
holder.file_name.setText(files[position].getName());
}
}
Since I am usic a Basic Activity as Main Activity, my content_main.xml is the following:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
/>
This is my current display:
And this is the view that what I want to achieve:
EDITED: If I create a simple TextView over the RecyclerView within a LinearLayout, the layout colocates itself over the action bar...
The simplest thing you can do is just add a text view above the recycler view :)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<TextView
android:id="#+id/title_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="title" />
<android.support.v7.widget.RecyclerView
android:id="#+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
In your activity class set that text view to the current folder path text.
title_text_view.setText("path/to/folder");
Using this code snippet works like a charm, with scroll of course:
https://github.com/cundong/HeaderAndFooterRecyclerView

Add an XML files content inside another XML document dynamically in Android using Eclipse

I'm very new to Android Development and I'd like to add a page to another dynamically. I'm a C# web developer and would like to do the same as using a Master Page and inserting other pages in this page.
The code I have at the moment is as follow: (Keep in mind that I've never done this, and any and all advise would be appreciated.)
I Have 3 main documents I'm working on at the moment:
Pharma Manifest.xml
MainActivity.java
fragment_main_dummy.xml(I'm using the dummy since it's already doing what I want.)
Here is the content on MainActivity.xml
package com.pharma.pharma;
import org.w3c.dom.Text;
import android.annotation.TargetApi;
import android.app.ActionBar;
import android.location.Address;
import android.os.Bundle;
import android.content.Context;
import android.os.Build;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.NavUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class MainActivity extends FragmentActivity implements
ActionBar.OnNavigationListener {
/**
* The serialization (saved instance state) Bundle key representing the
* current dropdown position.
*/
private static final String STATE_SELECTED_NAVIGATION_ITEM = "selected_navigation_item";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Set up the action bar to show a dropdown list.
final ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
// Set up the dropdown list navigation in the action bar.
actionBar.setListNavigationCallbacks(
// Specify a SpinnerAdapter to populate the dropdown list.
new ArrayAdapter<String>(getActionBarThemedContextCompat(),
android.R.layout.simple_list_item_1,
android.R.id.text1, new String[] {
getString(R.string.title_Dashboard),
getString(R.string.title_Customers),
getString(R.string.title_Products),
getString(R.string.title_Detailing),
getString(R.string.title_Appointments),
getString(R.string.title_Events), }), this);
}
/**
* Backward-compatible version of {#link ActionBar#getThemedContext()} that
* simply returns the {#link android.app.Activity} if
* <code>getThemedContext</code> is unavailable.
*/
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
private Context getActionBarThemedContextCompat() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return getActionBar().getThemedContext();
} else {
return this;
}
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Restore the previously serialized current dropdown position.
if (savedInstanceState.containsKey(STATE_SELECTED_NAVIGATION_ITEM)) {
getActionBar().setSelectedNavigationItem(
savedInstanceState.getInt(STATE_SELECTED_NAVIGATION_ITEM));
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
// Serialize the current dropdown position.
outState.putInt(STATE_SELECTED_NAVIGATION_ITEM, getActionBar()
.getSelectedNavigationIndex());
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onNavigationItemSelected(int position, long id) {
// When the given dropdown item is selected, show its contents in the
// container view.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.container, fragment).commit();
return true;
}
/**
* A dummy fragment representing a section of the app, but that simply
* displays dummy text.
*/
public static class DummySectionFragment extends Fragment {
/**
* The fragment argument representing the section number for this
* fragment.
*/
public static final String ARG_SECTION_NUMBER = "section_number";
public DummySectionFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main_dummy, container, false);
TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
switch(getArguments().getInt(ARG_SECTION_NUMBER)){
case 1:
dummyTextView.setText("blah Blah Dashboard");
break;
case 2:
dummyTextView.setText("blah Blah Customers");
break;
case 3:
dummyTextView.setText("blah Blah Products");
break;
case 4:
dummyTextView.setText("blah Blah Detailing");
break;
case 5:
dummyTextView.setText("blah Blah Appointments");
break;
case 6:
//Insert XML to fragment dummy here as a test
break;
default:
//throw error
}
return rootView;
}
}
}
Here is the code in the Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.pharma.pharma"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.pharma.pharma.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
And lastly the code for fragment_main_dummy.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".MainActivity$DummySectionFragment" >
<TextView
android:id="#+id/section_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true" />
<include
android:id="#+id/section_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
layout="#layout/dashboard" />
</RelativeLayout>
I've sat with this for days.
I'm still new at this and can't figure it out. I'm also pressured to get this whole project done in about a months time. Any help would be greatly appreciated.
Your title is conceptually wrong, you don't one XML to another. Those XML are heavily crunched and pre-compiled during the compile time and don't exist as you see them in the final app.
Further, those XML are just representations for the system to build Views and inside ViewGroups which is a class that extends View you can call .addView(view);
The include xml code you use, is a good way to re-use static generated XML, but for dynamic generated stuff you need to do it via code.
I've notice you're using fragments stuff. So probably you're better use the Fragment route of dynamically adding/removing stuff
The code you created inside onNavigationItemSelected is pretty much everything you need to do to dynamically change stuff around.
The fragment you're creating/instantiating will override onCreateView to inflate a new View and return it. That new view will be inserted on android.R.id.content (that is the View ID for your whole content) or for any ID that you specified in your XML.
hope it helps.
You could use LayoutInflater to do that.
eg.
RelativeLayout relativeLayout= (RelativeLayout) findViewById(R.id.relativeLayout);
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
relativeLayout.addView(childIndex, layoutInflater.inflate(R.layout.newLayoutToAdd, this, false) );

Categories

Resources