在本質上,你有正確的想法......但這不是「正確」的實施。
'正確'的方法是使用一些事情,看起來你不是。內容提供者(這是'包裝'你的數據庫,並創建一個'簡單'(明確定義的)接口來與你的數據庫進行交互(好'簡單'...使用,寫它,可以是一種痛苦......直到你學會如何使它們變得容易,並且我的提示使它變得容易的是在開始之前製作一個Schema文件,其中包含基礎數據庫的所有結構+我們以前在某些情況下使用的ContentProvider Here is a sample Schema我們的Coursera Android Concurrency/Mobile/Web專業課程。))
2)Android的內置帳戶管理支持。
使用ContentProvider和以下組件的要點是多用途的...您正在遵循最佳實踐......您有明確的「分離問題」......您是「好鄰居」應用程序當用戶不希望應用程序同步時,允許用戶禁用應用程序進行同步......(同時保存電池/帶寬/內存(從應用程序不運行服務24/7進行同步)否則,實際上不得不編寫'sycning'機制或定時器或類似的東西......(你必須爲你的同步過程編寫自定義'邏輯'......這超出了這個問題的範圍......)
當您只使用內置的SyncAdaptor/Account機制時...您可以輕鬆檢查用戶是否擁有「帳戶」當他們打開「主要活動」,然後指示他們在繼續之前創建新帳戶/登錄到現有帳戶。 (下面的代碼實際上並不使用OAuth/Google/Facebook/StackOverflow /等基於Web的賬戶,但如果你沒有一個帶有認證設置的Web服務器......這可能是一個很好的早期測試直到你這樣做,仍然允許你使用賬戶機制/等。一旦你這樣做,你顯然必須改變他們使用正確的信息。)
(有很多原因說明爲什麼這種方法更好,我有點琢磨它們,以節省時間/空間......但我認爲你會得到它的一般'要點'。 )
2.1),擴展服務
2.2),擴展AccountAuthenticatorActivity
這裏有兩個 '樣本' 的文件,應該幫助你寫你自己的版本的活性的AccountAuthenticatorService。這段代碼已經有幾年了,但仍然應該與你所需要的「接近」。我在這段代碼中使用了一些「技巧」(比如:ApplicationConstants),我不會分享它們,因爲它們不是最佳實踐。但是這些文件的大綱應該會讓你有70%〜80%的路程。
如果您在編寫ContentProvider時需要幫助,我個人建議您購買/借用/獲取Professional Android 2 Application Development 2nd Edition的副本,價格約爲5.50美元。這是本教程針對Android 2.0教程編寫的舊版本,但自那時起,您嘗試做的核心部分並沒有改變,並且它大幅降低了新版本的價格。本書是我個人用來學習這些材料的內容,我認爲它是教你如何從頭開始創建一個數據庫和ContentProvider的最佳工作之一。如果你不想購買這本書,你可以隨時下載the Downloadable Code from this book。它有很多(在Chapter_7.txt中)內容提供者不同部分的例子。然而,它並沒有解釋每個人做什麼......所以它不會像兩者一樣有用。
package edu.vuum.mocca.authentication;
import edu.vuum.mocca.main.ApplicationConstants;
import android.accounts.AbstractAccountAuthenticator;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
/**
* Skeleton example for how a functional SyncAdaptor's
* AccountAuthenticatorService would be implemented.
*
* @author Michael A. Walker
*
*/
public class AccountAuthenticatorService extends Service {
private static final String TAG = AccountAuthenticatorService.class
.getCanonicalName();
private static AccountAuthenticatorImpl sAccountAuthenticator = null;
private static String ACCOUNT_NAME;
private static String ACCOUNT_TYPE;
public AccountAuthenticatorService() {
super();
ACCOUNT_NAME = ApplicationConstants
.getValue(ApplicationConstants.ACCOUNT_NAME);
ACCOUNT_TYPE = ApplicationConstants
.getValue(ApplicationConstants.ACCOUNT_TYPE);
}
public static Account GetDefaultSyncAccount() {
final String accountName = ACCOUNT_NAME;
return new Account(accountName, ACCOUNT_TYPE);
}
/*
* (non-Javadoc)
*
* @see android.app.Service#onBind(android.content.Intent)
*/
@Override
public IBinder onBind(Intent intent) {
IBinder ret = null;
if (intent.getAction().equals(
android.accounts.AccountManager.ACTION_AUTHENTICATOR_INTENT))
ret = getAuthenticator().getIBinder();
return ret;
}
/**
* Creates Singleton AccountAuthenticator Implementation.
* @return
*/
private AccountAuthenticatorImpl getAuthenticator() {
if (sAccountAuthenticator == null)
sAccountAuthenticator = new AccountAuthenticatorImpl(this);
return sAccountAuthenticator;
}
private static class AccountAuthenticatorImpl extends
AbstractAccountAuthenticator {
private Context mContext;
public AccountAuthenticatorImpl(Context context) {
super(context);
mContext = context;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#addAccount(android.
* accounts.AccountAuthenticatorResponse, java.lang.String,
* java.lang.String, java.lang.String[], android.os.Bundle)
*/
@Override
public Bundle addAccount(AccountAuthenticatorResponse response,
String accountType, String authTokenType,
String[] requiredFeatures, Bundle options)
throws NetworkErrorException {
Bundle result = new Bundle();
Intent i = new Intent(mContext, AccountLoginActivity.class);
i.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE,
response);
result.putParcelable(AccountManager.KEY_INTENT, i);
return result;
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#confirmCredentials(
* android.accounts.AccountAuthenticatorResponse,
* android.accounts.Account, android.os.Bundle)
*/
@Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response,
Account account, Bundle options) {
// TODO Auto-generated method stub
Log.i(TAG, "confirmCredentials, not supported, exception thrown.");
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#editProperties(android
* .accounts.AccountAuthenticatorResponse, java.lang.String)
*/
@Override
public Bundle editProperties(AccountAuthenticatorResponse response,
String accountType) {
// TODO Auto-generated method stub
Log.i(TAG, "editProperties, not supported, exception thrown.");
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#getAuthToken(android
* .accounts.AccountAuthenticatorResponse, android.accounts.Account,
* java.lang.String, android.os.Bundle)
*/
@Override
public Bundle getAuthToken(AccountAuthenticatorResponse response,
Account account, String authTokenType, Bundle options)
throws NetworkErrorException {
// TODO Auto-generated method stub
Log.i(TAG, "getAuthToken");
Bundle bundle = new Bundle();
// TODO this works, but isn't really doing any valid auth.
bundle.putString(AccountManager.KEY_AUTHTOKEN, account.name);
return bundle;
}
/**
* Ask for a localized label for the given authTokenType.
* <p>
* may return null if not known.
*
* @see android.accounts.AbstractAccountAuthenticator#getAuthTokenLabel(java
* .lang.String)
*/
@Override
public String getAuthTokenLabel(String authTokenType) {
// TODO Auto-generated method stub
Log.i(TAG, "getAuthTokenLabel, not supported, exception thrown.");
throw new UnsupportedOperationException();
}
/*
* Checking features of the Account Not Supported currently.
*
* @see
* android.accounts.AbstractAccountAuthenticator#hasFeatures(android
* .accounts.AccountAuthenticatorResponse, android.accounts.Account,
* java.lang.String[])
*/
@Override
public Bundle hasFeatures(AccountAuthenticatorResponse response,
Account account, String[] features)
throws NetworkErrorException {
Log.i(TAG, "hasFeatures, not supported, exception thrown.");
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
*
* @see
* android.accounts.AbstractAccountAuthenticator#updateCredentials(android
* .accounts.AccountAuthenticatorResponse, android.accounts.Account,
* java.lang.String, android.os.Bundle)
*/
@Override
public Bundle updateCredentials(AccountAuthenticatorResponse response,
Account account, String authTokenType, Bundle options) {
// TODO Auto-generated method stub
Log.i(TAG, "updateCredentials, not supported, exception thrown.");
throw new UnsupportedOperationException();
}
}
}
這裏是延伸AccountAuthenticatorActivity
package edu.vuum.mocca.authentication;
import java.util.Locale;
import android.accounts.Account;
import android.accounts.AccountAuthenticatorActivity;
import android.accounts.AccountManager;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
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.Toast;
import edu.vanderbilt.mooc.mooc_cp.R;
import edu.vuum.mocca.main.ApplicationConstants;
/**
* Activity that gets Launched when Adding an Account to the SyncManager
* <p>
* An Activity to prompt for a Server Address, a UserName, and a Password. Uses
* these to verify user login credentials and to create a 'token' identifying
* the user account on the device.
*
* @author Michael A. Walker
* @Date 2012-11-23
*/
public class AccountLoginActivity extends AccountAuthenticatorActivity {
public final static String LOG_TAG = AccountLoginActivity.class.getCanonicalName();
/**************************************************************
* UI component variables
*************************************************************/
EditText mServerIP;
EditText mUsername;
EditText mPassword;
Button mLoginButton;
/**************************************************************
* Examples of constants for message passing on the AsyncTask
*************************************************************/
public final static String PARAM_AUTHTOKEN_TYPE = "";
public final static String PARAM_ACCOUNT_TYPE = "";
/*
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(LOG_TAG, "onCreate() called");
setContentView(R.layout.authenticator_layout);
mServerIP = (EditText) findViewById(R.id.server);
mUsername = (EditText) findViewById(R.id.username);
mPassword = (EditText) findViewById(R.id.password);
mLoginButton = (Button) findViewById(R.id.login);
// might be able to make this go away and be in the XML
// just easier to put here for now.
mLoginButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
loginButtonPressed(v);
}
});
}
// start the background threaded action to authenticate the user
public void loginButtonPressed(View v) {
Log.d(LOG_TAG, "onCreate() called");
String user = mUsername.getText().toString().trim()
.toLowerCase(Locale.ENGLISH);
String password = mPassword.getText().toString().trim()
.toLowerCase(Locale.ENGLISH);
String testValue = ApplicationConstants
.getValue(ApplicationConstants.ACCOUNT_TYPE);
if (testValue != null) {
Toast.makeText(getApplicationContext(), "testValue: " + testValue,
Toast.LENGTH_SHORT).show();
}
if (user.length() > 0 && password.length() > 0) {
LoginTask t = new LoginTask(AccountLoginActivity.this);
t.execute(user, password);
}
}
/**
* This is the background logic behind the user login credentials checking
*
* @author Michael A. Walker
*
*/
private class LoginTask extends AsyncTask<String, Void, Boolean> {
Context mContext;
ProgressDialog mDialog;
// constructor
LoginTask(Context c) {
Log.d(LOG_TAG, "LoginTask() constructed");
mContext = c;
mLoginButton.setEnabled(false);
// display a dialog with a spinner showing progress being worked on
mDialog = ProgressDialog.show(c, "",
getString(R.string.authenticating), true, false);
mDialog.setCancelable(true);
}
// Threaded background work (doesn't block UI)
@Override
public Boolean doInBackground(String... params) {
Log.d(LOG_TAG, "LoginTask.doInBackground() called");
String user = params[0];
String pass = params[1];
// TODO:Do something internetty HERE
try {
Thread.sleep(2000);
} catch (Exception e) {
e.printStackTrace();
}
Bundle result = null;
Account account = new Account(user,
mContext.getString(R.string.ACCOUNT_TYPE));
AccountManager am = AccountManager.get(mContext);
if (am.addAccountExplicitly(account, pass, null)) {
result = new Bundle();
result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
setAccountAuthenticatorResult(result);
return true;
} else {
return false;
}
}
// post processing of login verification
@Override
public void onPostExecute(Boolean result) {
Log.d(LOG_TAG, "LoginTask.onPostExecute() called");
mLoginButton.setEnabled(true);
mDialog.dismiss();
if (result)
finish();
}
}
}
它是簡單的樣品AccountLoginActivity。我覺得我好笨。我正在與第二個解決方案,因爲我有兩個活動。 –
哈哈沒問題,很高興幫忙。請接受此爲正確答案:D –
您可能還想查看我的答案,它更全面,因爲它可以指導您編寫更靈活/最佳實踐的應用程序等。儘管您當他們加載應用程序將他們引導到賬戶創建/登錄活動 – mawalker