In previous article we have leant integration of Twitter with our Android App. Today we are going to move further in Twitter Integration by showing different kind of Timelines. Twitter API provides Timelines for adding scrollable timelines anywhere in your app.
NOTE : Please go through the previous tutorial about Android Twitter Integration to check how to get Twitter API Key and Secret Key and how to implement login in Android.
2. Fragments
4. RecyclerView
In this article we are going to cover following things:
Twitter provides following Timelines:
1. UserTimeline which shows the @sonusurender0 (my twitter account) user’s timeline of Tweets or any logged in user timeline Tweets.
1 2 3 4 5 6 |
UserTimeline userTimeline = new UserTimeline.Builder() .screenName("sonusurender0")//any screen name .includeReplies(true)//Whether to include replies. Defaults to false. .includeRetweets(true)//Whether to include re-tweets. Defaults to true. .maxItemsPerRequest(50)//Max number of items to return per request .build(); |
2. SearchTimeline which shows Tweets matching the query “#android” or any searched query.
1 2 3 4 5 |
SearchTimeline searchTimeline = new SearchTimeline.Builder() .query("#android")//the search query for Tweets .languageCode(Locale.ENGLISH.getLanguage())//set the language code .maxItemsPerRequest(50)//Max number of items to return per request .build(); |
3. CollectionTimeline for the National Parks Tweets example collection of Tweets.
1 2 3 4 |
CollectionTimeline timeline = new CollectionTimeline.Builder() .id(539487832448843776L)//collection id of created collection .maxItemsPerRequest(50)//Max number of items to return per request .build(); |
4. TwitterListTimeline for the @twitterdev national-parks list can be created with the owner screen name (or user id) and list name.
1 2 3 4 |
TwitterListTimeline timeline = new TwitterListTimeline.Builder() .slugWithOwnerScreenName("national-parks", "twitterdev")//give list name with owner screen name .maxItemsPerRequest(50)//Max number of items to return per request .build(); |
5. FixedTweetTimeline which shows a fixed set of Tweets.
1 2 3 |
FixedTweetTimeline timeline = new FixedTweetTimeline.Builder() .setTweets(listOfTweets)//list of tweets .build(); |
With the help of above code snippets you can easily create any kind of Timeline according to your requirement.
Now after creating Timeline next step is to show the created TimeLine into your RecyclerView or ListView.
1. With RecyclerView : Make sure you use LinearLayoutManager with VERTICAL orientation.
1 2 3 4 5 6 |
TweetTimelineRecyclerViewAdapter adapter = new TweetTimelineRecyclerViewAdapter.Builder(this) .setTimeline(create_timeline) .setViewStyle(R.style.tw__TweetLightWithActionsStyle) .build(); recyclerView.setAdapter(adapter); |
2. With ListView
1 2 3 4 5 |
TweetTimelineListAdapter adapter = new TweetTimelineListAdapter.Builder(this) .setTimeline(created_timeline) .setViewStyle(R.style.tw__TweetLightWithActionsStyle) .build(); listView.setAdapter(adapter); |
You can listen Tweet action callback too by adding setOnActionCallback with Adapter. To do this you should have taken Access of “Read, Write and Access direct messages” for Twitter App shown below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
adapter = new TweetTimelineRecyclerViewAdapter.Builder(context) .setTimeline(created_timeline)//set the created timeline //action callback to listen when user like/unlike the tweet .setOnActionCallback(new Callback<Tweet>() { @Override public void success(Result<Tweet> result) { //do something on success response } @Override public void failure(TwitterException exception) { //do something on failure response } }) //set tweet view style .setViewStyle(R.style.tw__TweetLightWithActionsStyle) .build(); |
Twitter provide functionality to filter Tweets displayed in our app. You can use this functionality to prevent showing Tweets with profane words, hide Tweets that link to blacklisted URLs, or block particular user’s Tweets from appearing in your app. The rules can be managed in a standard JSON configuration file or creating List for different filters.
Following are the different Filter Values:
Method 1 : By creating List of different Filters.
1 2 3 4 5 6 |
final List<String> keywords = Arrays.asList("any_keyword1", "any_keyword1", "any_keyword2", "so_on"); final List<String> hashTags = Arrays.asList("hashTag1", "hashTag2", "hashTag3", "so_on"); final List<String> handles = Arrays.asList("userName1", "userName2", "userName3", "so_on"); final List<String> urls = Arrays.asList("url1", "url2", "url3", "so_on"); final FilterValues filterValues = new FilterValues(keywords, hashTags, handles, urls); |
You can pass null in FilterValues. Suppose you want to remove blacklist URLs tweets then pass other Filters as null like below:
1 |
final FilterValues filterValues = new FilterValues(null, null, null, urls); |
Method 2 : Using JSON
Create a .json file under res=>raw directory and add your Filter values.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
{ "keywords": [ "keyword1", "keyword2", "keyword3", "so_on" ], "hashtags": [ "hashtags1", "hashtags2", "hashtags3", "so_on" ], "handles": [ "userName1", "userName2", "userName3", "so_on" ], "urls": [ "url1", "url2", "url3", "so_on" ] } |
After creating JSON file use the below code to read data from it and pass to Filter Values.
1 2 3 |
InputStream inputStream = context.getResources().openRawResource(R.raw.timeline_filter_values); JsonReader reader = new JsonReader(new InputStreamReader(inputStream)); FilterValues filterValues = new Gson().fromJson(reader, FilterValues.class); |
You can download json file from server and use it also depend upon your requirement.
Now after creating FilterValue create TimelineFilter using BasicTimelineFilter provided by Twitter.
1 |
TimelineFilter timelineFilter = new BasicTimelineFilter(filterValues, Locale.ENGLISH); |
After creating TimelineFilter too set it to your adapter to see effect.
1 2 3 4 |
TweetTimelineListAdapter adapter = new TweetTimelineListAdapter.Builder(this) .setTimeline(created_timeline) .setTimelineFilter(timelineFilter) .build(); |
Both TweetTimelineRecyclerViewAdapter and TweetTimelineListAdapter support swipe down to refresh tweets. For that you have to put your xml layout into SwipeRefreshLayout then use the below code to attach it with adapter.
If you don’t know about SwipeRefreshLayout then check this link.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { swipeLayout.setRefreshing(true); adapter.refresh(new Callback<TimelineResult<Tweet>>() { @Override public void success(Result<TimelineResult<Tweet>> result) { swipeLayout.setRefreshing(false); } @Override public void failure(TwitterException exception) { // Toast or some other action } }); } }); |
Twitter API supports 4 different kind of styles that you can use while creating adapter :
Following are the attributes of the twitter styles
To create custom style use the below code snippet and use the style name while creating adapter.
1 2 3 4 |
<style name="CustomLightTweetStyle" parent="tw__TweetDarkStyle"> <item name="tw__primary_text_color">@color/primary_text_color</item> <item name="tw__action_color">@color/action_color</item> </style> |
If any one of the custom style attributes is not set, the value defaults to the tw__TweetLightStyle‘s value.
1. Create an App on Twitter and get API Key and Secret. To know how to get these things check my previous tutorial.
2. Add the below given strings into your strings.xml which we will using in our app:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<resources> <string name="app_name">Twitter Show Timeline Demo</string> <string name="search_twitter">Search Twitter</string> <string name="no_tweets">No Tweets</string> <string name="login">Login</string> <!-- string array for Tab items --> <string-array name="tab_items"> <item>User Timeline</item> <item>Search Timeline</item> <item>Collection Timeline</item> </string-array> </resources> |
3. After getting API Key and Secret open build.gradle and add the following dependencies to it and sync the gradle.
1 2 |
compile 'com.twitter.sdk.android:twitter-core:3.1.1' compile 'com.twitter.sdk.android:tweet-ui:3.1.1' |
4. On syncing completion create an Application java class naming MyApplication.java where we will initialise Twitter.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package com.android_twitter_show_timelines_demo; import android.app.Application; import android.util.Log; import com.twitter.sdk.android.core.DefaultLogger; import com.twitter.sdk.android.core.Twitter; import com.twitter.sdk.android.core.TwitterAuthConfig; import com.twitter.sdk.android.core.TwitterConfig; /** * Created by sonu on 17/01/18. */ public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); //initiate Twitter config TwitterConfig config = new TwitterConfig.Builder(this) .logger(new DefaultLogger(Log.DEBUG)) .twitterAuthConfig(new TwitterAuthConfig("h835hmmGNYsKqFxEts6keGvfC", "kefJbnzbspZksOxMgHFUBChHssSS3205SLGW2R2nWMKndJzLzW"))//pass Twitter API Key and Secret .debug(true) .build(); Twitter.initialize(config); } } |
5. Now declare create Application in AndroidManifest.xml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name="com.android_twitter_show_timelines_demo.activity.MainActivity" android:label="@string/login"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> |
6. Lets create an xml layout naming login_activity.xml and place TwitterLoginButton inside it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" android:padding="16dp"> <!-- twitter login button to do login --> <com.twitter.sdk.android.core.identity.TwitterLoginButton android:id="@+id/login_button" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout> |
7. Now create LoginActivity.java and add the Twitter Login logic here. In this class we are checking if user is already logged-in then we are redirecting app to MainActivity else we are asking user to do login. To check user validation we are using SharedPreferences and saving user information to use later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
package com.android_twitter_show_timelines_demo.activity; import android.content.Intent; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.widget.Toast; import com.android_twitter_show_timelines_demo.helper.MyPreferenceManager; import com.android_twitter_show_timelines_demo.R; import com.twitter.sdk.android.core.Callback; import com.twitter.sdk.android.core.Result; import com.twitter.sdk.android.core.TwitterException; import com.twitter.sdk.android.core.TwitterSession; import com.twitter.sdk.android.core.identity.TwitterLoginButton; /** * Created by sonu on 17/01/18. */ public class LoginActivity extends AppCompatActivity { private MyPreferenceManager myPreferenceManager; private TwitterLoginButton loginButton; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); myPreferenceManager = new MyPreferenceManager(this); //check if user is already login or not if (myPreferenceManager.getUserId() != 0) { //if already login then start main activity startMainActivity(); return; } setContentView(R.layout.login_activity); loginButton = findViewById(R.id.login_button); //set the callback to Twitter login button loginButton.setCallback(new Callback<TwitterSession>() { @Override public void success(Result<TwitterSession> result) { // Do something with result, which provides a TwitterSession for making API calls TwitterSession twitterSession = result.data; //if twitter session is not null then save user data to shared preference if (twitterSession != null) { myPreferenceManager.saveUserId(twitterSession.getUserId());//save user id myPreferenceManager.saveScreenName(twitterSession.getUserName());//save user screen name //after saving start main activity startMainActivity(); //show toast Toast.makeText(LoginActivity.this, "Login Successful.", Toast.LENGTH_SHORT).show(); } else { //if twitter session is null due to some reason then show error toast Toast.makeText(LoginActivity.this, "Failed to do Login. Please try again.", Toast.LENGTH_SHORT).show(); } } @Override public void failure(TwitterException exception) { // Do something on failure Toast.makeText(LoginActivity.this, "Failed to do Login. Please try again.", Toast.LENGTH_SHORT).show(); } }); } /** * method to start Main Activity */ private void startMainActivity() { startActivity(new Intent(this, MainActivity.class)); finish(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // Pass the activity result to the login button. loginButton.onActivityResult(requestCode, resultCode, data); } } |
LoginActivity will be our launching activity so don’t forget to add it into AndroidManifest.xml file and make it a launcher activity.
NOTE : If you don’t want the user to Authenticate via Twitter then directly open MainActivity and Twitter will automatically treat it as Guest User.
8. For SharedPreferences create a class naming MyPreferenceManager,java which will handle all SharedPreference methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
package com.android_twitter_show_timelines_demo.helper; import android.content.Context; import android.content.SharedPreferences; /** * Created by sonu on 17/01/18. */ public class MyPreferenceManager { /** * preference constant keys */ private static final String PREF_KEY = "login_prefs"; private static final String USER_ID = "user_id"; private static final String SCREEN_NAME = "screen_name"; //preference manager instance private SharedPreferences sharedPreferences; public MyPreferenceManager(Context context) { //initialize preference sharedPreferences = context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE); } /** * method to save user id * * @param userId to save */ public void saveUserId(Long userId) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putLong(USER_ID, userId); editor.apply(); } /** * @return saved user id if exist else return 0 */ public Long getUserId() { return sharedPreferences.getLong(USER_ID, 0); } /** * method to save user screen name * * @param screenName of the user */ public void saveScreenName(String screenName) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.putString(SCREEN_NAME, screenName); editor.apply(); } /** * @return saved user screen name */ public String getScreenName() { return sharedPreferences.getString(SCREEN_NAME, ""); } } |
9. For MainActivity.java contains setup of ViewPager and TabLayout which you can refer to this article.
10. Now creating Fragment Tabs to show different Timeline.
user_timeline_fragment.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/user_swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- recycler view to show User timeline --> <android.support.v7.widget.RecyclerView android:id="@+id/user_timeline_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- empty label to show when no tweets available --> <TextView android:id="@id/android:empty" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal|center_vertical" android:text="@string/no_tweets" /> </LinearLayout> </android.support.v4.widget.SwipeRefreshLayout> |
UserTimelineFragment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
package com.android_twitter_show_timelines_demo.tabs; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; 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.Toast; import com.android_twitter_show_timelines_demo.helper.MyPreferenceManager; import com.android_twitter_show_timelines_demo.R; import com.twitter.sdk.android.core.Callback; import com.twitter.sdk.android.core.Result; import com.twitter.sdk.android.core.TwitterException; import com.twitter.sdk.android.core.models.Tweet; import com.twitter.sdk.android.tweetui.TimelineResult; import com.twitter.sdk.android.tweetui.TweetTimelineRecyclerViewAdapter; import com.twitter.sdk.android.tweetui.UserTimeline; /** * Created by sonu on 17/01/18. */ public class UserTimelineFragment extends Fragment { private Context context; private RecyclerView userTimelineRecyclerView; private SwipeRefreshLayout swipeRefreshLayout; private TweetTimelineRecyclerViewAdapter adapter; @Override public void onAttach(Context context) { super.onAttach(context); this.context = context; } public UserTimelineFragment() { } public static UserTimelineFragment newInstance() { Bundle args = new Bundle(); UserTimelineFragment fragment = new UserTimelineFragment(); fragment.setArguments(args); return fragment; } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.user_timeline_fragment, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setUpSwipeRefreshLayout(view); setUpRecyclerView(view); loadUserTimeline(); } /** * method to set up recycler view * * @param view of the fragment */ private void setUpRecyclerView(@NonNull View view) { userTimelineRecyclerView = view.findViewById(R.id.user_timeline_recycler_view); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);//it should be Vertical only userTimelineRecyclerView.setLayoutManager(linearLayoutManager); } /** * method to load user timeline over recycler view */ private void loadUserTimeline() { MyPreferenceManager myPreferenceManager = new MyPreferenceManager(context); //build UserTimeline UserTimeline userTimeline = new UserTimeline.Builder() .userId(myPreferenceManager.getUserId())//User ID of the user to show tweets for .screenName(myPreferenceManager.getScreenName())//screen name of the user to show tweets for .includeReplies(true)//Whether to include replies. Defaults to false. .includeRetweets(true)//Whether to include re-tweets. Defaults to true. .maxItemsPerRequest(50)//Max number of items to return per request .build(); /* ============= If you don't want to login the user and still you want to see the User Timeline then you can pass any SCREEN NAME and see the timeline. Enable the below code to do this. =============== */ /* UserTimeline userTimeline = new UserTimeline.Builder() .screenName("sonusurender0")//any screen name .includeReplies(true)//Whether to include replies. Defaults to false. .includeRetweets(true)//Whether to include re-tweets. Defaults to true. .maxItemsPerRequest(50)//Max number of items to return per request .build();*/ //now build adapter for recycler view adapter = new TweetTimelineRecyclerViewAdapter.Builder(context) .setTimeline(userTimeline)//set the created timeline //action callback to listen when user like/unlike the tweet .setOnActionCallback(new Callback<Tweet>() { @Override public void success(Result<Tweet> result) { //do something on success response } @Override public void failure(TwitterException exception) { //do something on failure response } }) //set tweet view style .setViewStyle(R.style.tw__TweetLightWithActionsStyle) .build(); //finally set the created adapter to recycler view userTimelineRecyclerView.setAdapter(adapter); } /** * set up swipe refresh layout * * @param view of the fragment */ private void setUpSwipeRefreshLayout(View view) { //find the id of swipe refresh layout swipeRefreshLayout = view.findViewById(R.id.user_swipe_refresh_layout); //implement refresh listener swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //return if adapter is null if (adapter == null) return; //make set refreshing true swipeRefreshLayout.setRefreshing(true); adapter.refresh(new Callback<TimelineResult<Tweet>>() { @Override public void success(Result<TimelineResult<Tweet>> result) { //on success response make refreshing false swipeRefreshLayout.setRefreshing(false); Toast.makeText(context, "Tweets refreshed.", Toast.LENGTH_SHORT).show(); } @Override public void failure(TwitterException exception) { // Toast or some other action Toast.makeText(context, "Failed to refresh tweets.", Toast.LENGTH_SHORT).show(); } }); } }); } } |
search_timeline_fragment.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/search_swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/background_color" android:orientation="vertical"> <!-- edit text to search the query --> <EditText android:id="@+id/enter_search_query" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:background="@drawable/edit_text_bg" android:drawableLeft="@drawable/ic_action_search" android:drawablePadding="10dp" android:drawableStart="@drawable/ic_action_search" android:hint="@string/search_twitter" android:imeOptions="actionSearch" android:inputType="text" android:maxLines="1" android:padding="10dp" android:textColor="@android:color/black" android:textColorHint="@android:color/darker_gray" android:textSize="14sp" /> <!-- recycler view to show search query timeline --> <android.support.v7.widget.RecyclerView android:id="@+id/search_timeline_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> <!-- empty label to show when no tweets available --> <TextView android:id="@id/android:empty" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal|center_vertical" android:text="@string/no_tweets" /> </LinearLayout> </android.support.v4.widget.SwipeRefreshLayout> |
SearchTimelineFragment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
package com.android_twitter_show_timelines_demo.tabs; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import com.android_twitter_show_timelines_demo.R; import com.twitter.sdk.android.core.Callback; import com.twitter.sdk.android.core.Result; import com.twitter.sdk.android.core.TwitterException; import com.twitter.sdk.android.core.models.Tweet; import com.twitter.sdk.android.tweetui.SearchTimeline; import com.twitter.sdk.android.tweetui.TimelineResult; import com.twitter.sdk.android.tweetui.TweetTimelineRecyclerViewAdapter; import java.util.Locale; /** * Created by sonu on 17/01/18. */ public class SearchTimelineFragment extends Fragment { private Context context; private RecyclerView searchTimelineRecyclerView; private EditText searchQuery; private SwipeRefreshLayout swipeRefreshLayout; private TweetTimelineRecyclerViewAdapter adapter; @Override public void onAttach(Context context) { super.onAttach(context); this.context = context; } public SearchTimelineFragment() { } public static SearchTimelineFragment newInstance() { Bundle args = new Bundle(); SearchTimelineFragment fragment = new SearchTimelineFragment(); fragment.setArguments(args); return fragment; } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.search_timeline_fragment, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setUpSwipeRefreshLayout(view); setUpRecyclerView(view); setUpSearchQuery(view); } /** * set up recycler view * * @param view of the fragment */ private void setUpRecyclerView(View view) { searchTimelineRecyclerView = view.findViewById(R.id.search_timeline_recycler_view); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context); searchTimelineRecyclerView.setLayoutManager(linearLayoutManager); } /** * set up search query * * @param view */ private void setUpSearchQuery(View view) { searchQuery = view.findViewById(R.id.enter_search_query); //implement editor action listener to trigger query when user click on search icon from Keyboard searchQuery.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { //check if user clicked on Search icon or not if (i == EditorInfo.IME_ACTION_SEARCH) { //get the text from edit text String searchQuery = textView.getText().toString().trim(); //check if query should not empty if (!TextUtils.isEmpty(searchQuery)) { //hide keyboard hideKeyboard(textView); //search entered query doTwitterSearch(searchQuery); } else { //if query is empty show toast Toast.makeText(context, "Please enter something to search.", Toast.LENGTH_SHORT).show(); } return true; } return false; } }); } /** * method to trigger Tweet search on query base * * @param query */ private void doTwitterSearch(String query) { //NOTE : Filter settings using array list //Removes Tweets containing specified keywords in Tweet text. Uses localized case-insensitive matching /* final List<String> keywords = Arrays.asList("any_keyword1", "any_keyword1", "any_keyword2", "so_on"); //Removes Tweets containing specified hashtags. Uses localized case-insensitive matching final List<String> hashTags = Arrays.asList("hashTag1", "hashTag2", "hashTag3", "so_on"); //Removes Tweets from specified user or replies to specified user. Uses case-insensitive matching final List<String> handles = Arrays.asList("userName1", "userName2", "userName3", "so_on"); //Removes Tweet containing URLs from specified domain. Supports internationalized domain names final List<String> urls = Arrays.asList("url1", "url2", "url3", "so_on"); final FilterValues filterValues = new FilterValues(keywords, hashTags, handles, urls);*/ /* ================ OR ================ */ //NOTE : You can easily load your filter settings using a JSON configuration file and GSON /*InputStream inputStream = context.getResources().openRawResource(R.raw.timeline_filter_values); JsonReader reader = new JsonReader(new InputStreamReader(inputStream)); FilterValues filterValues = new Gson().fromJson(reader, FilterValues.class);*/ //final TimelineFilter timelineFilter = new BasicTimelineFilter(filterValues, Locale.ENGLISH); //build the Search TimeLine SearchTimeline searchTimeline = new SearchTimeline.Builder() .query(query)//the search query for Tweets .languageCode(Locale.ENGLISH.getLanguage())//set the language code .maxItemsPerRequest(50)//Max number of items to return per request .build(); //create adapter for RecyclerView adapter = new TweetTimelineRecyclerViewAdapter.Builder(context) .setTimeline(searchTimeline)//set created timeline //.setTimelineFilter(timelineFilter) //set timeline filter if any required //action callback to listen when user like/unlike the tweet .setOnActionCallback(new Callback<Tweet>() { @Override public void success(Result<Tweet> result) { //do something on success response } @Override public void failure(TwitterException exception) { //do something on failure response } }) //set tweet view style .setViewStyle(R.style.tw__TweetLightWithActionsStyle) .build(); //finally set created adapter to recycler view searchTimelineRecyclerView.setAdapter(adapter); } /** * set up swipe refresh layout * * @param view of the fragment */ private void setUpSwipeRefreshLayout(View view) { //find the id of swipe refresh layout swipeRefreshLayout = view.findViewById(R.id.search_swipe_refresh_layout); //implement refresh listener swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //return if adapter is null if (adapter == null) return; //make set refreshing true swipeRefreshLayout.setRefreshing(true); adapter.refresh(new Callback<TimelineResult<Tweet>>() { @Override public void success(Result<TimelineResult<Tweet>> result) { //on success response make refreshing false swipeRefreshLayout.setRefreshing(false); Toast.makeText(context, "Tweets refreshed.", Toast.LENGTH_SHORT).show(); } @Override public void failure(TwitterException exception) { // Toast or some other action Toast.makeText(context, "Failed to refresh tweets.", Toast.LENGTH_SHORT).show(); } }); } }); } /** * method to hide keyboard manually * * @param view of the current context */ private void hideKeyboard(View view) { InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); if (inputMethodManager != null) { inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); } } } |
collection_timeline_fragment.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/collection_swipe_refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <!-- recycler view to show Collection Timeline --> <android.support.v7.widget.RecyclerView android:id="@+id/collection_timeline_recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- empty label to show when no tweets available --> <TextView android:id="@id/android:empty" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal|center_vertical" android:text="@string/no_tweets" /> </LinearLayout> </android.support.v4.widget.SwipeRefreshLayout> |
CollectionTimelineFragment.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
package com.android_twitter_show_timelines_demo.tabs; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; 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.Toast; import com.android_twitter_show_timelines_demo.R; import com.twitter.sdk.android.core.Callback; import com.twitter.sdk.android.core.Result; import com.twitter.sdk.android.core.TwitterException; import com.twitter.sdk.android.core.models.Tweet; import com.twitter.sdk.android.tweetui.CollectionTimeline; import com.twitter.sdk.android.tweetui.FixedTweetTimeline; import com.twitter.sdk.android.tweetui.TimelineResult; import com.twitter.sdk.android.tweetui.TweetTimelineRecyclerViewAdapter; /** * Created by sonu on 17/01/18. */ public class CollectionTimelineFragment extends Fragment { private Context context; private RecyclerView userTimelineRecyclerView; private SwipeRefreshLayout swipeRefreshLayout; private TweetTimelineRecyclerViewAdapter adapter; @Override public void onAttach(Context context) { super.onAttach(context); this.context = context; } public CollectionTimelineFragment() { } public static CollectionTimelineFragment newInstance() { Bundle args = new Bundle(); CollectionTimelineFragment fragment = new CollectionTimelineFragment(); fragment.setArguments(args); return fragment; } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.collection_timeline_fragment, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); setUpSwipeRefreshLayout(view); setUpRecyclerView(view); loadCollectionTimeLine(); } /** * @param view of the fragment */ private void setUpRecyclerView(@NonNull View view) { userTimelineRecyclerView = view.findViewById(R.id.collection_timeline_recycler_view); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context); userTimelineRecyclerView.setLayoutManager(linearLayoutManager); } /** * method to load collection timeline */ private void loadCollectionTimeLine() { // Collection "National Parks Tweets" //NOTE : link to create collection, publish it and get collection id : https://developer.twitter.com/en/docs/tweets/curate-a-collection/overview/overview //build CollectionTimeLine CollectionTimeline timeline = new CollectionTimeline.Builder() .id(539487832448843776L)//collection id of created collection .maxItemsPerRequest(50)//Max number of items to return per request .build(); //now build adapter for recycler view adapter = new TweetTimelineRecyclerViewAdapter.Builder(context) .setTimeline(timeline)//set the created time line //action callback to listen when user like/unlike the tweet .setOnActionCallback(new Callback<Tweet>() { @Override public void success(Result<Tweet> result) { //do something on success response } @Override public void failure(TwitterException exception) { //do something on failure response } }) //set tweet view style .setViewStyle(R.style.tw__TweetLightWithActionsStyle) .build(); //finally set created adapter to recycler view userTimelineRecyclerView.setAdapter(adapter); } /** * set up swipe refresh layout * * @param view of the fragment */ private void setUpSwipeRefreshLayout(View view) { //find the id of swipe refresh layout swipeRefreshLayout = view.findViewById(R.id.collection_swipe_refresh_layout); //implement refresh listener swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { //return if adapter is null if (adapter == null) return; //make set refreshing true swipeRefreshLayout.setRefreshing(true); adapter.refresh(new Callback<TimelineResult<Tweet>>() { @Override public void success(Result<TimelineResult<Tweet>> result) { //on success response make refreshing false swipeRefreshLayout.setRefreshing(false); Toast.makeText(context, "Tweets refreshed.", Toast.LENGTH_SHORT).show(); } @Override public void failure(TwitterException exception) { // Toast or some other action Toast.makeText(context, "Failed to refresh tweets.", Toast.LENGTH_SHORT).show(); } }); } }); } } |
11. For EditText in search_timeline_fragment.xml use the below drawable naming edit_text_bg.xml:
1 2 3 4 5 6 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/white" /> <corners android:radius="5dp" /> </shape> |
12. Don’t forget to add INTERNET permission in AndroidManifest.xml.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android_twitter_show_timelines_demo"> <!-- permission required for Twitter login and fetch timeline --> <uses-permission android:name="android.permission.INTERNET" /> <application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name="com.android_twitter_show_timelines_demo.activity.LoginActivity" android:label="@string/login"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name="com.android_twitter_show_timelines_demo.activity.MainActivity" /> </application> </manifest>A |
13. Finally all done , now you can create an app which will show Tweets Timelines
Thanks.
NOTE : After downloading don’t forget to place your API Key and Secret inside MyApplication.java.
Subscribe to us and get the latest news.