Monthly Archives: October 2015

Android Stdio卡在Configure Project的解决方法

Android Stdio编译需要联网,在网络不好的地方编译效果非常不好。

 

因此,解决方法是,在build.gradle文件中,把这两个都加上(默认只有一个)

       mavenCentral()
        jcenter()

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0'
        classpath 'com.github.triplet.gradle:play-publisher:1.1.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        maven { url "http://dl.bintray.com/populov/maven" }
        maven { url "https://repo.eclipse.org/content/groups/releases" }
        mavenCentral()
        jcenter()
    }
}

利用Privoxy将Shadowsocks改装成HTTP代理

因为用Android Studio需要穿墙,而现有的Shadowsocks只支持Socks5代理,最新版本的AS使用Socks5代理的时候总是出错,所以现在想把Shadowsocks改装成一个HTTP代理。

具体方法,需要利用到http://www.privoxy.org/

下载安装之后,启动,Options->Edit Main Configuration。

找到下面的这一段话,因为Shadowsocks的本地监听端口是1080,所以对应的把#注释取消,并且修改成:

 

# To chain Privoxy and Tor, both running on the same system, you
# would use something like:
#
forward-socks5t / 127.0.0.1:1080 .

 

然后,这个是Privoxy的监听地址:

 

# listen-address [::1]:8118
#
listen-address 127.0.0.1:8118

然后在浏览器中设置HTTP代理。

OK了

Android Sync Adapters学习(三)

创建Sync Adapter。
好了好了前面的准备工作做的差不多了,接下来做正经事。
前面我们说到,Sync Adapter就是一个封装数据传输代码的胶囊包,然后可以运行在Sync Adapter的这个framework之上。
add the following pieces:创建一个Sync Adapter Class,一个Bound Service,一个XML的metadata file,在Manifest里面注册。
1)Step1,创建sync adapter 类,然后记得要继承AbstractThreadedSyncAdapter!!!(好神奇的名字)
这个里面记得有两种类型的构造函数需要设置。在构造函数中,可以获得Content Provider的一个解析器。
/**
* Handle the transfer of data between a server and an
* app, using the Android sync adapter framework.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {

ContentResolver mContentResolver ;

/**
* Perform a sync for this account. SyncAdapter-specific parameters may
* be specified in extras, which is guaranteed to not be null. Invocations
* of this method are guaranteed to be serialized.
*
*
@param
account    the account that should be synced
*
@param
extras     SyncAdapter-specific parameters
*
@param
authority  the authority of this sync request
*
@param
provider   a ContentProviderClient that points to the ContentProvider for this
*                   authority
*
@param
syncResult SyncAdapter-specific parameters
*/
@Override
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider , SyncResult syncResult) {

}

/**
* Creates an {
@link AbstractThreadedSyncAdapter}.
*
*
@param
context        the {@link Context} that this is running within.
*
@param
autoInitialize if true then sync requests that have
*                       {
@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by
*                       {
@link AbstractThreadedSyncAdapter} by calling
*                       {
@link ContentResolver#setIsSyncable(Account, String,
int)} with 1 if it
*/
public SyncAdapter(Context context , boolean autoInitialize) {
super (context, autoInitialize) ;
/*
* If your app uses a content resolver, get an instance of it
* from the incoming Context
*/
mContentResolver = context.getContentResolver() ;
}

/**
* Creates an {
@link AbstractThreadedSyncAdapter}.
*
*
@param
context            the {@link Context} that this is running within.
*
@param
autoInitialize     if true then sync requests that have
*                           {
@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by
*                           {
@link AbstractThreadedSyncAdapter} by calling
*                           {
@link ContentResolver#setIsSyncable(Account, String,
int)} with 1 if it
*                           is currently set to <0.
*
@param
allowParallelSyncs if true then allow syncs for different accounts to run
*                           at the same time, each in their own thread. This must be consistent with the setting
*/
public SyncAdapter(Context context , boolean autoInitialize , boolean allowParallelSyncs) {
super (context, autoInitialize , allowParallelSyncs) ;
/*
* If your app uses a content resolver, get an instance of it
* from the incoming Context
*/
mContentResolver = context.getContentResolver() ;
}

}
2)Step 2,将传输代码放到onPerformSync中去,实际上这个回调函数就是这个抽象类中唯一必须实现的方法。具体的方法。以及参数的含义,在上面的代码中已经给出了。
一般来说,在这个OnPerformSync()里面,具体要怎么操作是由你自己的App自己定义的。
通常会有一些通用的implementation task:1)连接Server;2)上传下载数据;3)处理数据冲突,就是处理脏数据了;4)清空脏数据。
以下摘自官方文档,所以,这个东西其实还是有很多东西需要你自己去搞定的!!!!!!
Connecting to a server

Although you can assume that the network is available when your data transfer starts, the sync adapter framework doesn’t automatically connect to a server.
Downloading and uploading data

A sync adapter doesn’t automate any data transfer tasks. If you want to download data from a server and store it in a content provider, you have to provide the code that requests the data, downloads it, and inserts it in the provider. Similarly, if you want to send data to a server, you have to read it from a file, database, or provider, and send the necessary upload request. You also have to handle network errors that occur while your data transfer is running.
Handling data conflicts or determining how current the data is

A sync adapter doesn’t automatically handle conflicts between data on the server and data on the device. Also, it doesn’t automatically detect if the data on the server is newer than the data on the device, or vice versa. Instead, you have to provide your own algorithms for handling this situation.
Clean up.

Always close connections to a server and clean up temp files and caches at the end of your data transfer.
也就是说,只是这个OnPerformSync是在后台执行的。建议将所有的网络相关,以及sync相关的代码放在这个函数里面。
3)Step 3,将Sync Adapter绑定在Sync Framework上。
又要创建一个所谓的Bound Service了
在这个Bound Service里面,初始化的时候要去实例化一个SyncAdapter的实例,然后在连接到Service的时候,需要返回一个SyncAdapter的Binder。
于是就有了下面的这个类
/**
* Define a Service that returns an IBinder for the
* sync adapter class, allowing the sync adapter framework to call
* onPerformSync().
*/
public class SyncService extends Service {
// Storage for an instance of the sync adapter
private static SyncAdapter sSyncAdapter = null;
// Object to use as a thread-safe lock
private static final Object sSyncAdapterLock = new Object();
/*
* Instantiate the sync adapter object.
*/
@Override
public void onCreate() {
/*
* Create the sync adapter as a singleton.
* Set the sync adapter as syncable
* Disallow parallel syncs
*/
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new SyncAdapter(getApplicationContext() , true);
}
}
}
/**
* Return an object that allows the system to invoke
* the sync adapter.
*
*/
@Override
public IBinder onBind(Intent intent) {
/*
* Get the object that allows external processes
* to call onPerformSync(). The object is created
* in the base class code when the SyncAdapter
* constructors call super()
*/
return sSyncAdapter.getSyncAdapterBinder();
    }
}
4)Step 4 添加Framework所需要的账户
Framework要求每一个Adapter都有一个账户类型。现在需要在Android System里面设置这个account type。设置方法为,添加一个account, 使用addAccountExplicitly方法设置account type
最好是在程序的最开始设置这个Account Type,一般就是在Activity里面了。
注意这里的添加账户的功能就直接写到主Activity的OnCreate方法里面了!!!
public class SyncActivity extends Activity {

//…
//  …
// Constants
// The authority for the sync adapter’s content provider
public static final String AUTHORITY = “com.example.android.datasync.provider” ;
// An account type, in the form of a domain name
public static final String ACCOUNT_TYPE = “example.com” ;
// The account name
public static final String ACCOUNT = “dummyaccount”;
// Instance fields
Account mAccount;
// …
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState) ;
//  …
// Create the dummy account
mAccount = CreateSyncAccount(this) ;
//  …
}
// …
/**
* Create a new dummy account for the sync adapter
*
*
@param
context The application context
*/
public static Account CreateSyncAccount(Context context) {
// Create the account type and default account
Account newAccount = new Account(
ACCOUNT, ACCOUNT_TYPE);
// Get an instance of the Android account manager
AccountManager accountManager =
(AccountManager) context.getSystemService(
ACCOUNT_SERVICE);
/*
* Add the account and account type, no password or user data
* If successful, return the Account object, otherwise report an error.
*/
if (accountManager.addAccountExplicitly(newAccount , null, null)) {
/*
* If you don’t set android:syncable=”true” in
* in your <provider> element in the manifest,
* then call context.setIsSyncable(account, AUTHORITY, 1)
* here.
*/
} else {
/*
* The account exists or some other error occurred. Log this, report it,
* or handle it internally.
*/
}
return newAccount;
}

}
5)Step 5,添加sync adapter的元数据文件
这个就有点像那个authenticator了,也是需要一个配置文件,作为元数据去说明Sync Adapter相关的一些东西。
元数据文件就是用来说明Adapter的一些参数,配置,flag。同样的,这些文件被放在/res/xml里面。
<? xml version=“1.0” encoding= “utf-8”?>
<sync-adapter
xmlns:android= “http://schemas.android.com/apk/res/android”
android:contentAuthority=“com.test.lzq.androidstudiotest”
android :accountType=“example.com”
android :userVisible=“false”
android :supportsUploading=“false”
android :allowParallelSyncs=“false”
    android :isAlwaysSyncable=“true”/>
注意,这里有两个值需要注意,第一个是contentAuthority要跟Manifest里面的Provider的URI一样,另一个是accountType要跟前面设置的账户类型一致。
6)在Manifest文件中声明Sync Adapter
需要开启一系列的权限,以及需要为之前的那个Bound Service进行声明。
然后就添加了一堆权限:
<uses-permission android:name=“android.permission.INTERNET” />
<uses-permission
android:name=“android.permission.READ_SYNC_SETTINGS” />
<uses-permission android:name=“android.permission.WRITE_SYNC_SETTINGS” />
<uses-permission android:name=“android.permission.AUTHENTICATE_ACCOUNTS” />
注册Service的时候要记得增加以下内容:
<service
android :name=“.SyncService”
android :enabled=“true”
android :exported=“true”
android :process=“:sync”>
<intent-filter>
<action
android:name=“android.content.SyncAdapter” />
</intent-filter>
<meta-data
android :name=“android.content.SyncAdapter”
android :resource=“@xml/syncadapter” />
</service>
这里有一个process参数,会使得这个Service以独立全局进程的方式运行在一个叫做sync的进程中。如果有很多歌sync adapter的话,这样做可以节约开销。
好了!至此为止已经拥有了所有的使用sync adapter需要的组件。已经OK了。
接下来要做的就是让Sync Adapter Framework使用你自己创建的Sync Adapter。

Android Sync Adapters学习(二)

创建一个Stub Content Provider
sync adapter framework是和content provider framework 结合在一起使用的。因此,sync adapter 希望上面的App都能够为他自己的local data定义好一个content provider。
如果sync adapter想要运行你设计的sync adapter,但是app又没有设计content provider的话,sync adapter就会崩溃掉。
所以,如果没有Content Provider的话,就要创建一个Stub(感觉就是空的,存根那种类型)的Content Provider。如果已经有了,就可以跳过进入下一个阶段了。
1)Step1,创建一个Content Provider类。所谓Stub就是把所有方法的返回设置为null或者0就可以了
/*
* Define an implementation of ContentProvider that stubs out
* all methods
*/
public class StubProvider extends ContentProvider {
/*
* Always return true, indicating that the
* provider loaded correctly.
*/
@Override
public boolean onCreate() {
return true;
}
/*
* Return no type for MIME type
*/
@Override
public String getType(Uri uri) {
return null;
}
/*
* query() always returns no results
*
*/
@Override
public Cursor query(
Uri uri
,
String[] projection ,
String selection ,
String[] selectionArgs ,
String sortOrder) {
return null;
}
/*
* insert() always returns null (no URI)
*/
@Override
public Uri insert(Uri uri , ContentValues values) {
return null;
}
/*
* delete() always returns “no rows affected” (0)
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/*
* update() always returns “no rows affected” (0)
*/
public int update(
Uri uri
,
ContentValues values ,
String selection ,
String[] selectionArgs) {
return 0;
}
}
2)Step 2:在Manifest文件中声明这个Provider
注意,在Manifest里面声明的时候,记得要添加一些额外的元素
android:name="com.example.android.datasync.provider.StubProvider"

Specifies the fully-qualified name of the class that implements the stub content provider.
就是这个provider的具体名字/位置。
android:authorities="com.example.android.datasync.provider"

A URI authority that identifies the stub content provider. Make this value your app’s package name with the string “.provider” appended to it. Even though you’re declaring your stub provider to the system, nothing tries to access the provider itself.
URI好像一般都是用provider所在的包的名字?
android:exported="false"

Determines whether other apps can access the content provider. For your stub content provider, set the value to false, since there’s no need to allow other apps to see the provider. This value doesn’t affect the interaction between the sync adapter framework and the content provider.
android:syncable="true"

Sets a flag that indicates that the provider is syncable. If you set this flag to true, you don’t have to callsetIsSyncable() in your code. The flag allows the sync adapter framework to make data transfers with the content provider, but transfers only occur if you do them explicitly.
在我这边的代码里面是这样设置的:
<provider
android:name=“com.test.lzq.androidstudiotest.StubProvider”
android :authorities=“com.test.lzq.androidstudiotest”
android :enabled=“true”
android :exported=“true”
    android :syncable =“true” >
</provider>
OK,那么到目前为止,已经做好了所有在用Sync Adapter之前的准备工作了。接下来可以用一种组件把所有传输相关的代码包裹起来了。这种组件就是Sync Adapter。
现在我们进入下一个章节。

Android Sync Adapters学习(一)

在Google的Android Development网站上有许多的Training教程
今天首先重点研究一下跟Sync相关的一套解决方案,学习现有的传输框架对我们的研究工作有非常好的借鉴作用
##################################################################################
首先,使用统一的传输框架的好处就不用多说了,这个可以大大降低开发者的开发负担,同时又有利于做出非常好的App
总体来讲,这个Android内置的sync framework可以:
 This framework helps manage and automate data transfers, and coordinates synchronization operations across different apps.
当然你也可以自己写自己的传输协议,但是这个Android自身的框架有一下几点更好的地方:
Plug-in architecture

Allows you to add data transfer code to the system in the form of callable components.
像插座一样嵌入到系统中去。就是可以很好的把你的代码跟System Transmission相结合了。
Automated execution

Allows you to automate data transfer based on a variety of criteria, including data changes, elapsed time, or time of day. In addition, the system adds transfers that are unable to run to a queue, and runs them when possible.
可以根据不同的场景设置自动的传输数据!
Automated network checking

The system only runs your data transfer when the device has network connectivity.
自动检查网络!!这个就跟我们想做的很像啦。但是肯定还是不一样的!这个号称是,System仅仅在有网络连接的时候工作,谁知道啊。
Improved battery performance

Allows you to centralize all of your app’s data transfer tasks in one place, so that they all run at the same time. Your data transfer is also scheduled in conjunction with data transfers from other apps. These factors reduce the number of times the system has to switch on the network, which reduces battery usage.
可以降低能耗,我不信。这个节能的思想很简单啊!就是把所有应用的数据绑在一个时间传输!!!
Account management and authentication

If your app requires user credentials or server login, you can optionally integrate account management and authentication into your data transfer.
还有身份认证的功能。这个很基础,没什么。
反正就是很好了。但是我们的研究工作肯定是想在这个基础上做得更好一些了。下面开始进入代码过程。
#################################################################
Step 1,创建一个存根验证器(这么翻译好奇怪,其实就是Stub Authenticator,本质上就是一个验证的账号,类似于Dropbox那个API的用法)
就是一个APP ID。即便是不想使用Login的功能,也需要创建一个空的Authenticator。
1)要想添加一个验证器authenticator,首先创建一个类,然后继承AbstractAccountAuthenticator,并且存根出(stub out,其实就是实现抽象方法)所有需要的method
接下来写一下这个抽象的账号验证类的使用方法,要使用账号的验证功能,首先需要继承这个抽象类,还需要写一个service,在services的onBine函数中返回getIBinder()的结果。通过ACTION_AUTHENTICATOR_INTENT去调用Service。
同时,这个Service还必须设置filter去监听这个action,并且Service中还需要指定metadata的tags,在AndroidManifest.xml中。
在Android的文档中给出的例子是如下所示。
   <intent-filter>
<action android:name=”android.accounts.AccountAuthenticator” />
</intent-filter>
<meta-data android:name=”android.accounts.AccountAuthenticator”
android:resource=”@xml/authenticator” />
 <account-authenticator xmlns:android=”http://schemas.android.com/apk/res/android”
android:accountType=”typeOfAuthenticator”
android:icon=”@drawable/icon”
android:smallIcon=”@drawable/miniIcon”
android:label=”@string/label”
android:accountPreferences=”@xml/account_preferences”
/>
2)创建好验证的class之后,就需要把这个验证器绑定到同步的framework中去。
要创建一个Bound Service,然后这个Service提供一个Android binder object,允许这个framework调用创建的authenticator,并且在framework和authenticator之间传递数据。
所以,可以在Service中实例化这个authenticator,即在onCreate()中调用。
创建Service(在Android Stdio中创建Service还挺方便的因为它自己会去修改Manifest的文件,添加Service的相关说明。)
public class AuthenticatorService extends Service {
// Instance field that stores the authenticator object
private Authenticator mAuthenticator; //create our authenticator
@Override
public void onCreate() {
// Create a new authenticator object
mAuthenticator = new Authenticator( this);
}
/*
* When the system binds to this Service to make the RPC call
* return the authenticator’s IBinder.
*/
@Override
public IBinder onBind(Intent intent) {
return mAuthenticator.getIBinder();
}
}
3) 为了能够在framework中插入这些控件,必须向framework提供一些元数据说明。metadata中需要说明,创建的账户类型(account type),还要设置一堆图片,如果你的账户类型要展示给用户看的话,会用到这些icon。如果你的Server需要验证身份(login)的话,这些账户类型的内容会被发送到Server上,如果不需要验证就不发送了。
这些元数据用一个XML文件描述,在项目的/res/xml文件夹中,名字可以随意取。
所以,我们就创建对应的文件夹,对应的xml文件,然后在res/xml下面创建对应的authenticator.xml文件。这个xml文件只含有唯一的元素,<account-authenticator>
这个元素包含有以下的属性: android:accountType, android:icon, android:smallIcon, android:label。
这里面第一个元素可以看做是一个sync adapter的唯一标识,后面的两个是在System的账号选项卡里面,选择的时候显示的小图标。最后一个就是一个标记。所以就创建了以下的xml文件。
注意这里的accountType是以域名的形势给出的。
<? xml version=“1.0” encoding= “utf-8”?>
<account-authenticator
xmlns:android= “http://schemas.android.com/apk/res/android”
android :accountType=“example.com”
android :icon=“@drawable/ic_launcher”
android :smallIcon=“@drawable/ic_launcher”
    android :label=“@string/app_name”/>
4)在Manifest文件中声明创建的Authenticator。
在前面的步骤中,我们创建了一个Bound Service,把创建的authenticator和sync adapter framework关联起来了。为了让系统能够识别我们的service,按照惯例需要在Manifest文件中声明这个Service。
<service
android :name=“.AuthenticatorService”
android :enabled=“true”
android :exported=“true” >
<intent-filter>
<action
android:name=“android.accounts.AccountAuthenticator” />
</intent-filter>
<meta-data
android:name=“android.accounts.AccountAuthenticator”
android :resource=“@xml/authenticator” />
</service>
注意!这里的过滤器,也就是触发这个Service的方法需要在<intent-filter>中设置一下。<meta-data>中需要声明一下authenticator的内容,还有对应的xml文件的内容!
除了一个authenticator之外,要想使用sync adapter还需要一个content provider,具体方法见下一节内容。

Android Stdio上使用代理服务器

从Eclipse转战到Android Stdio之后,遇到各种麻烦的事情

之前Eclipse编译项目的时候,是不需要联网的,纯本地执行就可以,但是现在的Stdio编译,或者下载一些Example进行学习的时候,是需要联网的,尤其是要用到一些墙外的网站。

要命了,太麻烦了。所以,目前的解决办法是,利用Shadowsocks建立代理,然后通过这个代理去进行相关的更新。

不知道哪天Shadowsocks就没了,跟以前的GoAgent一样。

先暂时这样用吧。

进入Android Stdio,File,Settings,选Appearance&Behavior,(或者直接搜索Proxy)

找到System Settings,选择HTTP Proxy

 

这里我的Shadowsocks的客户端是运行在路由器上的(路由器运行OpenWRT+Shadowsocks Client),Shadowsocks的Server运行在Amazon EC2上。

 

这里路由器的地址是192.168.2.1,运行端口是1081.

 

想要检查网络的话,可以用这里的Check connection功能。

 

如果不知道怎么用Shadowsocks的话,可以参考以下链接:

http://pan.baidu.com/s/1mgLAoWw