Reputation: 3190
I found the ViewPager in the android SDK and was messing around with it. Basically my final task is to create a youtube, facebook, and twitter feed all in one app, using the ViewPager and Fragments to scroll between the 3 categories. I'm having a bit of a hard time understanding house these work, more specifically, how to I add an element (Button) to a specific Fragment? Here's my code so far:
package com.ito.mindtrekkers;
import java.util.ArrayList;
import twitter4j.Query;
import twitter4j.QueryResult;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import android.annotation.SuppressLint;
import android.os.AsyncTask;
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.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
@SuppressLint("ShowToast")
//Brady Mahar
public class Main extends FragmentActivity {
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
* will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
ArrayList<String> tweetList = new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(
getSupportFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setCurrentItem(1); //sets initial page to "Facebook"
new DownloadFilesTask().execute("weather" , null, null);
}
@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;
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a DummySectionFragment (defined as a static inner class
// below) with the page number as its lone argument.
Fragment fragment = new DummySectionFragment();
Bundle args = new Bundle();
args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
fragment.setArguments(args);
return fragment;
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getString(R.string.title_youtube);
case 1:
return getString(R.string.title_facebook);
case 2:
return getString(R.string.title_twitter);
}
return null;
}
}
/**
* 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() {
}
@SuppressLint("ShowToast")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Create a new TextView and set its text to the fragment's section
// number argument value.
TextView textView = new TextView(getActivity());
textView.setGravity(Gravity.CENTER);
textView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
return textView;
}
}
/**
* Class for handling NetworkOnMainThread
* Sends the command Asynchronously
* @author austinn
*
*/
private class DownloadFilesTask extends AsyncTask<String, Void, String> {
protected String doInBackground(String... command) {
Twitter twitter = new TwitterFactory().getInstance();
Query query = new Query("from:MindTrekkers");
query.setRpp(100);
try {
QueryResult result = twitter.search(query);
for(twitter4j.Tweet tweet : result.getTweets()) {
//Toast.makeText(getApplicationContext(), tweet.getText(), Toast.LENGTH_SHORT);
Log.v("Tweet", tweet.getText());
tweetList.add(tweet.getText());
}
} catch (TwitterException e) {
//Toast.makeText(getApplicationContext(), e + "", Toast.LENGTH_SHORT);
Log.v("Error", e+"");
}
return null;
}
protected void onProgressUpdate(Void... progress) {}
protected void onPostExecute(String result) {}
}
}
Upvotes: 0
Views: 3070
Reputation: 6838
Implement your 3 Fragment categories (youtube, facebook, and twitter) in separate Fragment classes with a Singleton instance getter. Here's an Facebook Fragment example (note the onCreateView() inflates a fragment_facebook layout):
public class FaceBookFragment extends Fragment {
private static FaceBookFragment instance = null;
public static FaceBookFragment newInstance() {
if(instance == null) {
instance = new FaceBookFragment();
Bundle args = new Bundle();
instance.setArguments(args);
return instance;
}
return instance;
}
public FaceBookFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_facebook, container,
false);
...
return rootView;
}
}
Then in your FragmentPagerAdapter (located in the MainActivity of your code above), have the getItem() return the Fragment instance:
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment frag = null;
switch (position) {
case 0:
frag = FaceBookFragment.newInstance();
break;
case 1:
frag = TwitterFragment.newInstance();
break;
case 2:
frag = YouTubeFragment.newInstance();
break;
}
return frag;
}
}
BONUS: Also, I know your code was experimental, but your tweetlist won't be accessible from any of your Fragments.
A Fragment is a new class object and can't access anything in the MainActivity directly unless you pass a reference to an object (the tweetlist) during construction (limiting), or get a 'final' on an object/variable if the Fragment code is under MainActivity (the list will never change from the Fragment's perspective). Maybe I didn't articulate this statement as well as other might, but tweetlist will not be accessible from your Fragment as it is.
There's a couple of solutions:
Move tweetlist to the Twitter Fragment and have it call the downloader. Then your TwitterFragment can construct and hold the list and update the UI as necessary. HOWEVER, consider the Fragment lifecycle (http://developer.android.com/guide/components/fragments.html), see the lifecycle section and diagram) The onDestroyView() method will be called when you swipe/flip over a couple of Fragments and back again. e.g. Android will not keep an indefinite number of Fragment alive and will destroy/re-create the view as needed. Don't try to update the Fragment's UI/layout objects from an AsyncTask. It's possible the Fragment might call onDestoryView() before your task completes. (you'll probably get NullPointerExceptions then) Instead have your AsyncTask only update Fragment scope variables (tweetlist) and have your onCreateView() use that same variable. (maybe synchronize the variable too)
Keep your major variable/objects/AsyncTask invoking code, all in the MainActivity, and add methods to access them from a Fragment, and have the Fragment getActivity() and cast it to MainActivity and call the method when needed:
public class MainActivity extends ActionBarActivity implements ActionBar.TabListener {
ArrayList<String> tweetList = new ArrayList<String>();
...
public ArrayList<String> getTweetlist() {
return tweetlist;
}
...
}
public class TwitterFragment extends Fragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_twitter, container, false);
...
ArrayList<String> tweetList = ((MainActivity)getActivity()).getTweetlist();
...
return rootView;
}
...
}
Upvotes: 1
Reputation: 7530
Let me try to explain, first use this FragmentPagerAdapter:
public class TestFragmentAdapter extends FragmentPagerAdapter implements IconPagerAdapter {
protected static final String[] CONTENT = new String[] { "CATEGORIAS", "PRINCIPAL", "AS MELHORES", };
protected static final int[] ICONS = new int[] {
R.drawable.perm_group_calendar,
R.drawable.perm_group_camera,
R.drawable.perm_group_device_alarms,
};
private int mCount = CONTENT.length;
public TestFragmentAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {Fragment f = null;
switch(position){
case 0:
{
f = new ArrayListFragment();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 1:
{
f = new HomeFragment();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
case 2:
{
f = new EndlessCustomView();//YourFragment
// set arguments here, if required
Bundle args = new Bundle();
f.setArguments(args);
break;
}
default:
throw new IllegalArgumentException("not this many fragments: " + position);
}
return f;
}
@Override
public int getCount() {
return mCount;
}
@Override
public CharSequence getPageTitle(int position) {
return TestFragmentAdapter.CONTENT[position % CONTENT.length];
}
@Override
public int getIconResId(int index) {
return ICONS[index % ICONS.length];
}
public void setCount(int count) {
if (count > 0 && count <= 10) {
mCount = count;
notifyDataSetChanged();
}
}
}
As you can see, ArrayListFragment, HomeFragment and EndlessCustomView is a class that extends Fragment, so for each of these classes inside onCreate() , You can setContentView(R.layout.your_layout);
Then you can add a button or whatever you want in this layout.
Upvotes: 0