во-первых, @ Грэм Борланд прав.Вы можете использовать старый API, это полностью решает проблему.Тем не менее, ваше программное обеспечение не будет развиваться и следовать усовершенствованиям API и в конечном итоге будет соответствовать версии Android, которая больше не поддерживается.
Шаблон проектирования, который я собираюсь предложить, основан на самоанализе, но обеспечивает лучшее программирование.интерфейс, чем решение, предложенное @Blundell.Я думаю, что он достаточно силен, чтобы вдохновить стандартный подход к этой общей проблеме.Он основан на многих сообщениях из Stack Over Flow и других форумов.
Сначала вам нужно определить интерфейс для службы, которую вы хотите реализовать.Вы сможете реализовать разные версии этого сервиса, используя разные версии интересующего вас API.
Действительно, поскольку мы собираемся поделиться некоторым кодом здесь для загрузки наших различных реализаций, мы решили использоватьабстрактный класс.Он будет определять сигнатуры открытых методов как интерфейс, но также будет предлагать статический метод для загрузки ваших различных реализаций.
/**
* Interface used to interact with the actual instance of MessageManager.
* This inteface allows will be the type of the reference that will point
* to the actual MessageMessenger, which will be loaded dynamically.
* @author steff
*
*/
public abstract class MessageManager {
/** Request code used to identify mail messages.*/
public final static int FOR_MAIL = 0x3689;
/** Request code used to identify SMS messages.*/
public final static int FOR_SMS = 0x3698;
/**
* Start an activity inside the given context. It will allow to pickup a contact
* and will be given an intent code to get contact pick up.
* *@param the request code. Has to be a constant : FOR_MAIL or FOR_SMS
*/
public abstract void pickupContact(int code);//met
/**
* Start an activity inside the given context. It will allow to pickup a contact
* and will be given an intent code to get contact pick up.
* *@param the request code. Has to be a constant : FOR_MAIL or FOR_SMS
*/
public abstract void sendMessage(int code, Intent data, final String body);//met
/**
* Static methode used as in factory design pattern to create an instance
* of messageManager. Here it is combined with the singleton pattern to
* get an instance of an inherited class that is supported by current android SDK.
* This singleton will be created bu reflexion.
* @param activity the activity that needs messaging capabilities.
* @return an instance of an inherited class that is supported by current android SDK or null, if not found.
*/
public static MessageManager getInstance( Activity activity )
{
MessageManager instance = null;
try {
Class<? extends MessageManager> messageManagerClass = (Class<? extends MessageManager>) activity.getClassLoader().loadClass( "ca.qc.webalterpraxis.cinedroid.message.MessageManagerSDK7" );
Method singletonMethod = messageManagerClass.getMethod("getInstance", Activity.class );
instance = (MessageManager) singletonMethod.invoke( null , activity);
} catch (Throwable e) {
Log.e( "CinemadroidMain", "Impossible to get an instance of class MessageManagerSDK7",e );
}//met
return instance;
}//met
}//interface
Затем вы можете предоставить различные реализации этого абстрактного класса, используя разные версии Android SDK.
Что несколько необычно в этом методе, так это то, что это шаблон фабричного дизайна в сочетании с шаблоном одноэлементного дизайна.Все подклассы должны быть одноэлементными и предоставлять статический метод getInstanceMethod.Метод фабрики этого абстрактного класса попытается загрузить класс, реализующий этот интерфейс.Если это не удается, вы можете понизить ваши требования до классов, реализующих службу и основанных на более ранней версии APIS.
Вот пример класса для отправки почты и смс с использованием этого интерфейса.Он предназначен для Android SDK 7.
public class MessageManagerSDK7 extends MessageManager {
/** Used for logcat. */
private static final String LOG_TAG = "MessageManagerSDK7";
/** Singleton instance. */
private static MessageManagerSDK7 instance = null;
/** Activity that will call messaging actions. */
private Activity context;
/** Private constructor for singleton. */
private MessageManagerSDK7( Activity context )
{
if( instance != null )
throw new RuntimeException( "Should not be called twice. Singleton class.");
this.context = context;
}//cons
/**
* Static method that will be called by reflexion;
* @param context the activity that will enclose the call for messaging.
* @return an instance of this class (if class loader allows it).
*/
public static MessageManagerSDK7 getInstance( Activity context )
{
if( instance == null )
instance = new MessageManagerSDK7( context );
instance.context = context;
return instance;
}//met
/* (non-Javadoc)
* @see ca.qc.webalterpraxis.cinedroid.model.MessageManager#pickupContact(int)
*/
@Override
public void pickupContact( int code )
{
if( code != FOR_MAIL && code != FOR_SMS )
throw new RuntimeException( "Wrong request code, has to be either FOR_MAIL or FOR_SMS.");
Intent intentContact = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
context.startActivityForResult(intentContact, code );
}//met
/* (non-Javadoc)
* @see ca.qc.webalterpraxis.cinedroid.model.MessageManager#sendMessage(int, android.content.Intent, java.lang.String)
*/
@Override
public void sendMessage( int code, Intent data, final String body )
{
//System.out.println( "SendMessage");
if( code != FOR_MAIL && code != FOR_SMS )
throw new RuntimeException( "Wrong request code, has to be either FOR_MAIL or FOR_SMS.");
int icon = 0;
int noItemMessage = 0;
int title = 0;
//set the right icon and message for the dialog
if( code == FOR_MAIL )
{
icon=R.drawable.mail;
noItemMessage = R.string.no_email_found;
title = R.string.mail_error;
}//if
else if( code == FOR_SMS )
{
icon=R.drawable.sms;
noItemMessage = R.string.no_number_found;
title = R.string.sms_error;
}//if
//compose email or sms
//pick contact email address
final String[] emailsOrPhoneNumbers = (code == FOR_MAIL ) ? getContactsEmails( data ) : getContactPhoneNumber( data );
if( emailsOrPhoneNumbers == null )
{
new AlertDialog.Builder( context ).setIcon( icon ).setTitle(title).setMessage( noItemMessage ).show();
return;
}//if
//in case there are several addresses, we handle this using a dialog.
//modal dialog would be usefull but it's bad UI practice
//so we use an alert dialog, async ..
//all this is poorly coded but not very interesting, not worth having a dedicated inner class
if( emailsOrPhoneNumbers.length > 1 )
{
selectMultipleAndSend( emailsOrPhoneNumbers, body, code);
return;
}//if
if( code == FOR_MAIL )
sendMail( emailsOrPhoneNumbers, body );
else
sendSMS( emailsOrPhoneNumbers, body );
}//met
private void sendMail( String[] emails, String body )
{
if( body == null )
{
new AlertDialog.Builder( context ).setIcon( R.drawable.mail ).setTitle(R.string.mail_error).setMessage( R.string.impossible_compose_message ).show();
return;
}//if
//prepare email data
try {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("message/rfc822") ;
i.putExtra(Intent.EXTRA_EMAIL, emails );
//i.putExtra(Intent.EXTRA_EMAIL, emails);
i.putExtra(Intent.EXTRA_SUBJECT, context.getString( R.string.showtimes ) );
i.putExtra(Intent.EXTRA_TEXT,body);
context.startActivity(Intent.createChooser(i, context.getString( R.string.select_application ) ) );
} catch (Throwable e) {
new AlertDialog.Builder( context ).setIcon( R.drawable.mail ).setTitle(R.string.mail_error).setMessage( R.string.no_application_mail ).show();
Log.e( LOG_TAG, "No application found", e);
}//catch
}//met
private void sendSMS( String[] phoneNumbers, String body )
{
try {
Intent sendIntent= new Intent(Intent.ACTION_VIEW);
if( body == null )
{
new AlertDialog.Builder( context ).setIcon( R.drawable.sms ).setTitle(R.string.sms_error).setMessage( R.string.impossible_compose_message ).show();
return;
}//if
sendIntent.putExtra("sms_body", body);
String phones = "";
for( String phoneNumber : phoneNumbers )
phones += ((phones.length() == 0) ? "" : ";") + phoneNumber;
sendIntent.putExtra("address", phones );
sendIntent.setType("vnd.android-dir/mms-sms");
context.startActivity(sendIntent);
} catch (Throwable e) {
new AlertDialog.Builder( context ).setIcon( R.drawable.sms ).setTitle(R.string.sms_error).setMessage( R.string.no_application_sms ).show();
Log.e( LOG_TAG, "No application found", e);
}//catch
}//met
/**
* @param intent the intent returned by the pick contact activity
* @return the emails of selected people, separated by a comma or null if no emails has been found;
*/
protected String[] getContactsEmails(Intent intent)
{
List<String> resultList = new ArrayList<String>();
///717023/kak-pozvonit-v-spisok-kontaktov-android
Cursor cursor = context.managedQuery(intent.getData(), null, null, null, null);
while (cursor.moveToNext())
{
String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
// Find Email Addresses
Cursor emails = context.getContentResolver().query(ContactsContract.CommonDataKinds.Email.CONTENT_URI,null,ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = " + contactId,null, null);
while (emails.moveToNext())
{
resultList.add( emails.getString(emails.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)) );
}//while
emails.close();
} //while (cursor.moveToNext())
cursor.close();
if( resultList.size() == 0 )
return null;
else
return resultList.toArray( new String[ resultList.size() ] );
}//met
/**
* @param intent the intent returned by the pick contact activity
* @return the phoneNumber of selected people, separated by a comma or null if no phoneNumber has been found;
*/
protected String[] getContactPhoneNumber(Intent intent)
{
List<String> resultList = new ArrayList<String>();
///717023/kak-pozvonit-v-spisok-kontaktov-android
Cursor cursor = context.managedQuery(intent.getData(), null, null, null, null);
while (cursor.moveToNext())
{
String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String name = cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
String hasPhone = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
if ( hasPhone.equalsIgnoreCase("1"))
hasPhone = "true";
else
hasPhone = "false" ;
if (Boolean.parseBoolean(hasPhone))
{
Cursor phones = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId,null, null);
while (phones.moveToNext())
{
resultList.add( phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)) );
}
phones.close();
}
} //while (cursor.moveToNext())
cursor.close();
if( resultList.size() == 0 )
return null;
else
return resultList.toArray( new String[ resultList.size() ] );
}//met
private void selectMultipleAndSend( final String[] emailsOrPhoneNumbers, final String body, final int code )
{
int icon = 0;
int selectMessage = 0;
//set the right icon and message for the dialog
if( code == FOR_MAIL )
{
icon=R.drawable.mail;
selectMessage = R.string.select_email;
}//if
else if( code == FOR_SMS )
{
icon=R.drawable.sms;
selectMessage = R.string.select_phone;
}//if
final boolean[] selected = new boolean[ emailsOrPhoneNumbers.length ];
Arrays.fill( selected, true );
new AlertDialog.Builder( context ).setIcon( icon ).setTitle( selectMessage ).setMultiChoiceItems(emailsOrPhoneNumbers, selected, new OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean isChecked) {
selected[ which ] = isChecked;
}
}).setPositiveButton( R.string.OK, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
int count = 0;
for( int s=0; s< selected.length; s ++ )
if( selected[s] )
count ++;
String[] selectedEmailsOrPhoneNumbers = new String[ count ];
int index = 0;
for( int s=0; s< selected.length; s ++ )
if( selected[s] )
selectedEmailsOrPhoneNumbers[ index ++ ] = emailsOrPhoneNumbers[ s ];
if( code == FOR_MAIL )
sendMail( selectedEmailsOrPhoneNumbers, body );
else if( code == FOR_SMS )
sendSMS( selectedEmailsOrPhoneNumbers, body );
}
}).setNegativeButton( R.string.cancel , null ).show();
}//met
}//class
И вы могли бы также предоставить другие альтернативы.Попытка загрузить их одну за другой, по убыванию номеров версий Android.
Чтобы использовать вашу службу мессенджеров, довольно просто:
MessageManager messageManager = MessageManager.getInstance( this );
, если она нулевая, то ни одна служба не подходитЕсли оно не равно NULL, используйте интерфейс, определенный MessageManager.
Этот метод можно расширить и даже сделать более понятным, включив номер версии, на котором основана реализация, и создав небольшую шину для загрузки классов 1.за другим в правильном порядке.
Все отзывы приветствуются.
С уважением, Стефан