Статьи

Создание клиента Twitter для Android: твиты, ретвиты и ответы

В этой серии мы создаем клиент Twitter для платформы Android с использованием библиотеки Twitter4J. Этот учебник будет посвящен реализации твитов, ретвитов и ответов на твиты. Мы создадим новую активность для твитов и ответов с кнопками ретвитов и ответов, реализованными для каждого твита на домашней временной шкале пользователя.


  1. Создание клиента Twitter для Android: настройка и обзор
  2. Создание клиента Twitter для Android: создание интерфейса
  3. Создание клиента Twitter для Android: создание базы данных временной шкалы
  4. Создание клиента Twitter для Android: получение обновлений с помощью службы
  5. Создание клиента Twitter для Android: твиты, ретвиты и ответы

В первых четырех уроках мы:

  • Зарегистрировано приложение в твиттере.
  • Импортирована библиотека Twitter4J.
  • Обработана аутентификация пользователя.
  • Встроенный пользовательский интерфейс с использованием ресурсов XML.
  • Создана база данных SQLite для хранения твитов для домашней временной шкалы пользователя.
  • Сопоставил данные с видимыми представлениями с помощью адаптера.
  • Периодически выбирал новые обновления, используя Сервис и Трансляцию.

Наше приложение будет иметь второе действие в дополнение к основному экрану временной шкалы. Эта новая активность предназначена для отправки твитов. Внутри пользователь может ввести текст, чтобы отправить твит со своей учетной записи в Twitter. Пользователь может войти в Tweet Activity двумя способами – нажав кнопку Tweet на главном экране приложения или нажав кнопку ответа на временной шкале.


Если пользователь нажимает кнопку «Твитнуть», ему будет предложено пустое текстовое поле для ввода своего твита, а также кнопка «Отправить», чтобы продолжить и отправить его.


Если пользователь нажимает кнопку ответа в твите временной шкалы, он также будет представлен с текстовым полем, но имя пользователя для ответа уже будет заполнено в этом поле. Ответ также должен быть отправлен с использованием идентификатора твита, на который мы отвечаем, что мы также осуществим.

Создайте новый класс в своем проекте Android, назвав его «NiceTweet» в соответствии с именем, которое вы включили в свой файл манифеста в первом уроке. Измените объявление класса следующим образом:

1
public class NiceTweet extends Activity implements OnClickListener {

Вам понадобится следующий импорт Android:

1
2
3
4
5
6
7
8
9
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;

Плюс эти Twitter4J импортирует:

1
2
3
4
5
6
import twitter4j.StatusUpdate;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;

Включите следующие переменные экземпляра в ваше объявление класса:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
    /**shared preferences for user twitter details*/
private SharedPreferences tweetPrefs;
    /**twitter object**/
private Twitter tweetTwitter;
  
    /**twitter key*/
public final static String TWIT_KEY = “your key”;
    /**twitter secret*/
public final static String TWIT_SECRET = “your secret”;
  
    /**the update ID for this tweet if it is a reply*/
private long tweetID = 0;
    /**the username for the tweet if it is a reply*/
private String tweetName = “”;

Мы будем использовать настройки, Twitter, ключевые и секретные переменные для доступа к методам Twitter4J для твиттера из учетной записи пользователя. Измените ключ и секрет, чтобы удовлетворить свои собственные. Последние две переменные предназначены для ответов. Когда пользователь нажимает кнопку ответа в твите, мы собираемся передать идентификатор твита, на который мы отвечаем, вместе с отображаемым в Twitter именем учетной записи, на которую мы отвечаем. Мы будем хранить их в двух переменных экземпляра.

Давайте реализуем метод создания деятельности:

1
2
3
4
5
6
7
8
9
/*
 * onCreate called when activity is created
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        //set tweet layout
    setContentView(R.layout.tweet);
}

Все, что мы здесь делаем, это устанавливаем макет твита, который мы определили в XML ранее. Затем реализуйте метод возобновления, который вызывается всякий раз, когда действие становится видимым для пользователя:

1
2
3
4
5
6
7
8
9
/*
 * Call setup method when this activity starts
 */
@Override
public void onResume() {
    super.onResume();
        //call helper method
    setupTweet();
}

Мы собираемся предоставить указанный вспомогательный метод для настройки Activity для взаимодействия с пользователем.


Добавьте метод «setupTweet» в ваш класс следующим образом:

01
02
03
04
05
06
07
08
09
10
/**
 * Method called whenever this Activity starts
 * – get ready to tweet
 * Sets up twitter and onClick listeners
 * – also sets up for replies
 */
private void setupTweet() {
    //prepare to tweet
  
}

Внутри этого метода нам нужно подготовить класс для отправки обычных твитов и ответов. Сначала давайте используем Shared Preferences для создания экземпляра нашего объекта Twitter:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
    //get preferences for user twitter details
tweetPrefs = getSharedPreferences(“TwitNicePrefs”, 0);
          
        //get user token and secret for authentication
String userToken = tweetPrefs.getString(“user_token”, null);
String userSecret = tweetPrefs.getString(“user_secret”, null);
  
    //create a new twitter configuration usign user details
Configuration twitConf = new ConfigurationBuilder()
    .setOAuthConsumerKey(TWIT_KEY)
    .setOAuthConsumerSecret(TWIT_SECRET)
    .setOAuthAccessToken(userToken)
    .setOAuthAccessTokenSecret(userSecret)
    .build();
  
    //create a twitter instance
tweetTwitter = new TwitterFactory(twitConf).getInstance();

Здесь мы создаем объект Twitter, используя информацию для аутентификации пользователя вместе с ключом разработчика и секретом для приложения. Когда мы возьмем пользователей в этот класс Activity, мы передадим идентификатор и имя пользователя, если на твит отвечают. Мы получаем это из намерения:

1
2
    //get any data passed to this intent for a reply
Bundle extras = getIntent().getExtras();

Если твит – это обычное обновление, а не ответ, дополнений не будет. Если есть дополнения, мы знаем, что твит – это ответ:

01
02
03
04
05
06
07
08
09
10
if(extras !=null)
{
        //get the ID of the tweet we are replying to
    tweetID = extras.getLong(“tweetID”);
        //get the user screen name for the tweet we are replying to
    tweetName = extras.getString(“tweetUser”);
  
        //use the passed information
  
}

Здесь мы получаем идентификатор и экранное имя для ответа на твит. Далее мы используем эту информацию для добавления имени пользователя в текстовое поле, все еще внутри оператора «if»:

1
2
3
4
5
6
    //get a reference to the text field for tweeting
EditText theReply = (EditText)findViewById(R.id.tweettext);
    //start the tweet text for the reply @username
theReply.setText(“@”+tweetName+” “);
    //set the cursor to the end of the text for entry
theReply.setSelection(theReply.getText().length());

Мы устанавливаем имя пользователя в качестве первой части текста твита, помещая курсор в конец, чтобы пользователь мог сразу набрать текст ответа.


Далее давайте позаботимся о случаях, когда твит не является ответом:

1
2
3
4
5
else
{
        EditText theReply = (EditText)findViewById(R.id.tweettext);
        theReply.setText(“”);
}

Здесь мы просто устанавливаем текст в пустую строку, снова используя идентификатор, который мы дали текстовое поле в макете XML. Теперь мы можем завершить метод «setupTweet», добавив прослушиватели для кнопки «Отправить» и «Домой» для возврата к главному экрану временной шкалы:

1
2
3
4
5
6
7
    //set up listener for choosing home button to go to timeline
LinearLayout tweetClicker = (LinearLayout)findViewById(R.id.homebtn);
tweetClicker.setOnClickListener(this);
          
    //set up listener for send tweet button
Button tweetButton = (Button)findViewById(R.id.dotweet);
tweetButton.setOnClickListener(this);

Мы снова используем значения идентификаторов, которые мы указали в наших файлах макета.


Помните, что Tweet Activity будет содержать кнопку для возврата пользователей на домашнюю временную шкалу, а также кнопку для отправки твита. Давайте теперь добавим метод «onClick» для обработки пользователей, нажимающих эти кнопки:

1
2
3
4
5
6
7
8
/**
 * Listener method for button clicks
 * – for home button and send tweet button
 */
public void onClick(View v) {
    //handle home and send button clicks
  
}

Сначала получите ссылку на текстовое поле:

1
EditText tweetTxt = (EditText)findViewById(R.id.tweettext);

Теперь нам нужно выяснить, какая кнопка была нажата, используя операторы switch и case:

01
02
03
04
05
06
07
08
09
10
11
12
13
    //find out which view has been clicked
switch(v.getId()) {
case R.id.dotweet:
    //send tweet
      
    break;
case R.id.homebtn:
    //go to the home timeline
  
    break;
default:
    break;
}

Внутри оператора case “dotweet”, перед оператором break, реализуйте отправку твита следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
String toTweet = tweetTxt.getText().toString();
try {
        //handle replies
    if(tweetName.length()>0)
        tweetTwitter.updateStatus(new StatusUpdate(toTweet).inReplyToStatusId(tweetID));
          
        //handle normal tweets
    else
        tweetTwitter.updateStatus(toTweet);
              
        //reset the edit text
    tweetTxt.setText(“”);
}
catch(TwitterException te) { Log.e(“NiceTweet”, te.getMessage());

Здесь мы проверяем, является ли твит ответом или нет. Оператор «if» выполняется, если твит является ответом, включая текст из текстового поля и идентификатор обновления статуса, на которое мы отвечаем. Оператор “else” заботится об отправке обычных твитов, в которых в качестве параметра передается только текст. Блоки try и catch необходимы, когда мы пытаемся подключиться к Twitter через сеть. После отправки твита, будь то ответ или нет, мы возвращаем текстовое поле пустым при подготовке к следующему обновлению твита.

Для оператора case “homebtn” просто установите для текстового поля пустую строку:

1
tweetTxt.setText(“”);

Наконец, после оператора switch, но все еще внутри метода “onClick”, завершите Activity, чтобы он вернулся к домашней временной шкале:

1
finish();

Независимо от того, является ли твит ответом или обычным обновлением, мы немедленно возвращаем пользователя к главному экрану при его отправке, что мы также делаем, когда они нажимают кнопку «Домой» – оператор завершения будет выполняться во всех трех случаях.


Чтобы реализовать ретвит и ответ, нам нужно сохранить идентификатор твита и имя пользователя в пределах кнопок ретвита и ответа для каждого твита на временной шкале. Сохраняя эти данные в кнопке Views для ретвита и ответа, мы сможем определить, какой твит ретвитится или на который отвечает, когда пользователь нажимает кнопку.

Поскольку информация, которую мы должны хранить, состоит из числа и некоторого текста, мы создадим класс для ее моделирования. Создайте новый класс в своем проекте и назовите его «StatusData». Ваш новый класс должен начинаться следующим образом:

1
public class StatusData {

Внутри класса добавьте переменные экземпляра для идентификатора твита и имени пользователя:

1
2
3
4
5
/**tweet ID*/
private long tweetID;
  
/**user screen name of tweeter*/
private String tweetUser;

Идентификатор моделируется как длинный, с отображаемым именем текстовая строка. Добавьте метод конструктора к классу:

01
02
03
04
05
06
07
08
09
10
/**
 * Constructor receives ID and user name
 * @param ID
 * @param screenName
 */
public StatusData(long ID, String screenName) {
        //instantiate variables
    tweetID=ID;
    tweetUser=screenName;
}

Метод просто создает две переменные. Затем добавьте публичный метод, чтобы мы могли получить идентификатор твита в другом месте:

1
2
3
4
5
/**
 * Get the ID of the tweet
 * @return tweetID as a long
 */
public long getID() {return tweetID;}

Затем добавьте метод для возврата имени экрана:

1
2
3
4
5
/**
 * Get the user screen name for the tweet
 * @return tweetUser as a String
 */
public String getUser() {return tweetUser;}

Эти методы позволят нам получать эту информацию, когда пользователи нажимают кнопку ретвита или ответа для определенного твита.


Теперь нам нужно расширить код в созданном нами классе адаптера («UpdateAdapter»). В методе «bindView» мы адаптировали отображение данных к пользовательскому интерфейсу Views. Теперь мы добавим дополнительную обработку, чтобы включить данные твитов в каждый ретвит и кнопку ответа. Перед завершением вашего метода “bindView” начните следующим образом:

1
2
3
4
    //get the status ID
long statusID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));
    //get the user name
String statusName = cursor.getString(cursor.getColumnIndex(“user_screen”));

Помните, что методу «bindView» передается объект Cursor для прохождения данных. Здесь мы используем курсор для получения длинного значения идентификатора и имени пользователя String для текущего твита. Вам понадобится следующий дополнительный импорт:

1
import android.provider.BaseColumns;

Теперь мы создадим объект нашего нового класса StatusData, передав данные твита методу конструктора:

1
2
    //create a StatusData object to store these
StatusData tweetData = new StatusData(statusID, statusName);

Объект StatusData содержит все необходимое для отправки ретвита или ответа на данный твит. Теперь мы добавим ссылку на этот объект в кнопки ретвита и ответа для твита, чтобы мы могли получить доступ к информации после нажатия пользователем. Мы используем метод “setTag”:

1
2
3
    //set the status data object as tag for both retweet and reply buttons in this view
row.findViewById(R.id.retweet).setTag(tweetData);
row.findViewById(R.id.reply).setTag(tweetData);

Метод «bindView» также получает параметр, представляющий представление строки, в котором будет отображаться твит. Если вы посмотрите на обновленный файл макета XML, то увидите, что эти два значения идентификатора включены для кнопок. Мы устанавливаем тег в каждой кнопке для отображения объекта StatusData, содержащего идентификатор и имя пользователя для отображаемого твита. Теперь нам нужно настроить нажатие кнопок для них:

1
2
3
    //setup onclick listeners for the retweet and reply buttons
row.findViewById(R.id.retweet).setOnClickListener(tweetListener);
row.findViewById(R.id.reply).setOnClickListener(tweetListener);

Здесь мы указываем прослушиватель кликов для обработки нажатий кнопок. Внутри метода слушателя мы сможем получить объекты StatusData любого ретвита и нажатых кнопок ответа. Мы также собираемся позволить пользователям нажимать на имя пользователя для твита, чтобы открыть профиль пользователя в веб-браузере. Добавьте слушателя щелчка к этому Представлению также здесь:

1
2
    //setup onclick for the user screen name within the tweet
row.findViewById(R.id.userScreen).setOnClickListener(tweetListener);

Это позволит нам подключаться к веб-интерфейсу Twitter, чтобы пользователи могли получать доступ к функциям, которые мы не предоставили в самом приложении.


В вашем классе UpdateAdapter создайте «onClickListener» для обработки кликов, используя имя «tweetListener», чтобы соответствовать тому, что мы указали в методе «bindView»:

01
02
03
04
05
06
07
08
09
10
/**
 * tweetListener handles clicks of reply and retweet buttons
 * – also handles clicking the user name within a tweet
 */
private OnClickListener tweetListener = new OnClickListener() {
    //onClick method
    public void onClick(View v) {
  
    }
};

Добавьте следующие дополнительные импорты в класс Adapter:

01
02
03
04
05
06
07
08
09
10
import android.view.View.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.widget.Toast;
import android.net.Uri;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;

Внутри метода «onClick» мы реализуем щелчки обеих кнопок плюс имя пользователя. Чтобы определить, какой из них был нажат, добавьте оператор switch:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
//which view was clicked
switch(v.getId()) {
        //reply button pressed
    case R.id.reply:
        //implement reply
  
        break;
        //retweet button pressed
    case R.id.retweet:
        //implement retweet
  
        break;
        //user has pressed tweet user name
    case R.id.userScreen:
        //implement visiting user profile
  
        break;
    default:
        break;
}

Внутри оператора case ответа мы запускаем класс Tweet Activity, передавая данные ответа, чтобы при отправке твита могли быть указаны идентификатор ответа и имя пользователя:

01
02
03
04
05
06
07
08
09
10
    //create an intent for sending a new tweet
Intent replyIntent = new Intent(v.getContext(), NiceTweet.class);
    //get the data from the tag within the button view
StatusData theData = (StatusData)v.getTag();
    //pass the status ID
replyIntent.putExtra(“tweetID”, theData.getID());
    //pass the user name
replyIntent.putExtra(“tweetUser”, theData.getUser());
    //go to the tweet screen
v.getContext().startActivity(replyIntent);

Обратите внимание, что мы извлекаем тег для нажатого просмотра, преобразуя его в объект StatusData. Затем мы вызываем открытые методы, которые мы предоставили в классе StatusData, чтобы вернуть идентификатор твита и имя пользователя. Мы передаем их в Твиттере как дополнения, затем запускаем Активность. В этот момент пользователь будет перенаправлен на экран Tweet, где данные ответа будут использоваться для реализации ответа на правильный твит.


В ретвите case case мы будем ретвитать соответствующий твит напрямую, используя методы Twitter4J. Сначала создайте экземпляр объекта Twitter с помощью общих настроек, а также вашего ключа разработчика и секрета для приложения:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
    //get context
Context appCont = v.getContext();
    //get preferences for user access
SharedPreferences tweetPrefs = appCont.getSharedPreferences(“TwitNicePrefs”, 0);
String userToken = tweetPrefs.getString(“user_token”, null);
String userSecret = tweetPrefs.getString(“user_secret”, null);
  
    //create new Twitter configuration
Configuration twitConf = new ConfigurationBuilder()
    .setOAuthConsumerKey(TWIT_KEY)
    .setOAuthConsumerSecret(TWIT_SECRET)
    .setOAuthAccessToken(userToken)
    .setOAuthAccessTokenSecret(userSecret)
    .build();
  
    //create Twitter instance for retweeting
Twitter retweetTwitter = new TwitterFactory(twitConf).getInstance();

Это та же самая техника, которую мы использовали для создания экземпляра класса Twitter раньше. Теперь мы можем использовать объект Twitter для отправки ретвита. Сначала нам нужно извлечь объект StatusData из кнопки, на которую вы нажали:

1
2
    //get tweet data from view tag
StatusData tweetData = (StatusData)v.getTag();

Теперь мы можем попытаться ретвитнуть обновление в блоке try:

1
2
3
4
5
6
7
try
{
        //retweet, passing the status ID from the tag
    retweetTwitter.retweetStatus(tweetData.getID());
  
}
catch(TwitterException te) {Log.e(LOG_TAG, te.getMessage());}

Все, что нужно объекту Twitter для отправки ретвита – это идентификатор исходного твита. Однако давайте дадим пользователю подтверждение, что его ретвит был отправлен, все еще внутри блока try:

1
2
3
4
5
    //confirm to use
CharSequence text = “Retweeted!”;
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(appCont, text, duration);
toast.show();

Вы можете, конечно, изменить сообщение, если хотите. Вот как это выглядит:


Теперь давайте дадим пользователю возможность посетить страницу профиля Twitter в веб-браузере, щелкнув экранное имя в текущем твите внутри оператора case «userScreen»:

1
2
3
4
5
6
7
    //get the user screen name
TextView tv = (TextView)v.findViewById(R.id.userScreen);
String userScreenName = tv.getText().toString();
    //open the user’s profile page in the browser
Intent browserIntent = new Intent(Intent.ACTION_VIEW,
    Uri.parse(“http://twitter.com/”+userScreenName));
v.getContext().startActivity(browserIntent);

Здесь мы получаем имя пользователя в виде текстовой строки из самого представления, которое в любом случае отображает имя экрана в виде строки. Мы встраиваем это в адрес страницы профиля Twitter, анализируем его как URI и даем команду браузеру открыть его.


Помните, что в нашем главном приложении Activity отображается кнопка для перехода пользователей прямо на экран Tweet. Давайте реализуем это сейчас. В свой основной класс Activity добавьте следующее внутри вашего метода “setupTimeline”, где бы вы ни были после установки основного представления контента:

1
2
3
    //setup onclick listener for tweet button
LinearLayout tweetClicker = (LinearLayout)findViewById(R.id.tweetbtn);
tweetClicker.setOnClickListener(this);

Идентификатор кнопки Tweet соответствует тому, что мы включили в основной XML-файл макета временной шкалы. Основной класс Activity будет обрабатывать нажатия кнопки Tweet. Если вы посмотрите на свой метод «onClick» в основной деятельности («TwitNiceActivity», если вы использовали имя в первом уроке), вы должны увидеть оператор switch с одним оператором case для кнопки «signin». Добавьте второй оператор case для кнопки Tweet следующим образом (перед оператором по умолчанию):

1
2
3
4
5
    //user has pressed tweet button
case R.id.tweetbtn:
        //launch tweet activity
    startActivity(new Intent(this, NiceTweet.class));
    break;

Здесь мы просто запускаем твит-активность. Нам не нужно передавать какую-либо информацию в Активность, так как в этом случае пользователь просто запускает ее, чтобы отправить обычный твит.


На этом наше приложение для Twitter завершено! Запустите приложение на эмуляторе или устройстве, чтобы увидеть его функционирование. При первом запуске вы, конечно, должны дать согласие на то, чтобы приложение могло использовать вашу учетную запись Twitter. При желании вы можете создать отдельную учетную запись Twitter для тестирования приложения, а не использовать обычную учетную запись. После авторизации вам должна быть представлена ​​домашняя временная шкала, представляющая самые последние твиты из аккаунтов, на которые вы подписаны. Проверьте твиты, ретвиты и ответы, а также убедитесь, что ваша временная шкала автоматически обновляется с выбранным интервалом.


В этом уроке мы создали базовый клиент Twitter для Android. Существует множество способов улучшить и улучшить приложение, например, возможность просматривать прямые сообщения или просматривать профили пользователей в приложении, а не использовать веб-браузер. Вы также можете сделать упоминание пользователей в твитах кликабельными (т. Е. Связать любую текстовую строку, перед которой стоит «@», со страницей профиля этого пользователя). Подобный процесс позволит вам поддерживать хэштеги. Более продвинутые клиенты Twitter также отображают диалоги при выборе отдельного твита, отображая ответы в хронологическом порядке.

С точки зрения реализации приложения, есть также улучшения, которые вы могли бы рассмотреть. Например, в случае, если у пользователя плохое соединение, вы можете реализовать загрузку изображений профиля в качестве фонового процесса. Вы также можете реализовать некоторую форму кэширования изображений, чтобы максимизировать эффективность. Вместо того, чтобы приложение автоматически обновляло ListView с помощью новых твитов, вы могли бы внедрить кнопку в верхней части временной шкалы, чтобы пользователи могли управлять отображением, с помощью кнопки, указывающей, сколько новых твитов доступно. Наконец, вы можете повысить эффективность, запустив Сервис в отдельном потоке.


Надеюсь, вам понравилась эта серия статей о создании клиента Twitter для платформы Android! Помимо изучения того, как подключить свои приложения к Twitter, у вас теперь есть опыт использования внешней библиотеки и различных ресурсов платформы Android, таких как базы данных, адаптеры, сервисы и трансляции. Все эти ключевые навыки будут полезны для ваших будущих проектов Android. Загружаемый исходный код содержит дополнительные примечания, которые могут оказаться полезными.