Skip to content

Commit de59913

Browse files
committedMar 19, 2016
(自认为)优雅的支持跨进程的单例实现机制(toolbox + sample)
1 parent a1a0f64 commit de59913

File tree

26 files changed

+903
-5
lines changed

26 files changed

+903
-5
lines changed
 

‎app/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ dependencies {
2727
compile 'com.android.support:recyclerview-v7:22.1.1'
2828
compile 'com.facebook.fresco:fresco:0.6.1'
2929
compile 'com.tencent.bugly:crashreport:1.2.3.8'
30+
/** ButterKnife */
31+
compile 'com.jakewharton:butterknife:7.0.1'
3032
}
3133

3234
/** Bugly Crash上报相关配置 */

‎app/src/main/AndroidManifest.xml

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@
2020
<activity
2121
android:name=".MainActivity"
2222
android:label="@string/app_name">
23-
<intent-filter>
24-
<action android:name="android.intent.action.MAIN" />
25-
26-
<category android:name="android.intent.category.LAUNCHER" />
27-
</intent-filter>
2823
</activity>
2924
<activity android:name=".sample.SampleActivity" />
3025
<activity android:name=".demos.DemosIndexActivity" />
@@ -65,6 +60,25 @@
6560
<action android:name="playground.android.me.sr1.androidplayground.demos.service.MAIN_PROCESS_SERVICE_WITH_INTENT_FILTER" />
6661
</intent-filter>
6762
</service>
63+
<service android:name=".sample.mutilprocess.processA.ServiceA" />
64+
<activity android:name=".sample.mutilprocess.processA.ActivityA" >
65+
<intent-filter>
66+
<action android:name="android.intent.action.MAIN" />
67+
68+
<category android:name="android.intent.category.LAUNCHER" />
69+
</intent-filter>
70+
</activity>
71+
<service android:name=".sample.mutilprocess.processA.ServiceA" />
72+
73+
<activity android:name=".sample.mutilprocess.processB.ActivityB"
74+
android:process=":B" />
75+
<service android:name=".sample.mutilprocess.processB.ServiceB"
76+
android:process=":B" />
77+
78+
<activity android:name=".sample.mutilprocess.processC.ActivityC"
79+
android:process=":C" />
80+
<service android:name=".sample.mutilprocess.processC.ServiceC"
81+
android:process=":C" />
6882
</application>
6983

7084
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processA;
2+
3+
interface SingletonA {
4+
void invokeA(String aString);
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processB;
2+
3+
interface SingletonB {
4+
void invokeB(String aString);
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processC;
2+
3+
interface SingletonC {
4+
void invokeC(String aString);
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton;
2+
3+
parcelable InstanceCarrier;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton;
2+
3+
import playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton.InstanceCarrier;
4+
5+
interface InstanceTransfer {
6+
InstanceCarrier transfer();
7+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processA;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.os.*;
6+
import android.support.v7.app.AppCompatActivity;
7+
import android.util.Log;
8+
import android.widget.Button;
9+
import android.widget.TextView;
10+
import android.widget.Toast;
11+
12+
import butterknife.Bind;
13+
import butterknife.ButterKnife;
14+
import butterknife.OnClick;
15+
import playground.android.me.sr1.androidplayground.App;
16+
import playground.android.me.sr1.androidplayground.R;
17+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processB.ActivityB;
18+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processB.ServiceB;
19+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processB.SingletonBImp;
20+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processC.ServiceC;
21+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processC.SingletonCImp;
22+
import playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton.InstanceReceiver;
23+
import playground.android.me.sr1.androidplayground.toolbox.utils.AppUtils;
24+
25+
/**
26+
* @author SR1s
27+
*/
28+
public class ActivityA extends AppCompatActivity {
29+
30+
private static String TAG = "ActivityA";
31+
32+
@Bind(R.id.textView1) TextView mTextView1;
33+
34+
@Bind(R.id.button0) Button mBtn0;
35+
36+
@Bind(R.id.button1) Button mBtn1;
37+
38+
@Bind(R.id.button2) Button mBtn2;
39+
40+
@Bind(R.id.button3) Button mBtn3;
41+
42+
@Override
43+
protected void onCreate(Bundle savedInstanceState) {
44+
super.onCreate(savedInstanceState);
45+
setContentView(R.layout.activity_abc);
46+
ButterKnife.bind(this);
47+
48+
mTextView1.setText("这里是主进程A");
49+
mBtn0.setText("启动进程B");
50+
mBtn1.setText("调用本主进程A的方法)");
51+
mBtn2.setText("调用其他进程B的方法");
52+
mBtn3.setText("调用其他进程C的方法");
53+
54+
/** 把其他进程的单例绑定过来 */
55+
bindService(ServiceB.class);
56+
bindService(ServiceC.class);
57+
}
58+
59+
void bindService(Class<?> clz) {
60+
Intent intent = new Intent(this, clz);
61+
bindService(intent, new InstanceReceiver(), Context.BIND_AUTO_CREATE);
62+
}
63+
64+
@OnClick(R.id.button0)
65+
void startActivty() {
66+
Intent intent = new Intent(this, ActivityB.class);
67+
startActivity(intent);
68+
}
69+
70+
@OnClick(R.id.button1)
71+
void invokeAInstance() {
72+
try {
73+
Log.i(TAG, String.format("[%s][invokeA][pid=%d][tid=%d]", AppUtils.currentProcessName(),
74+
android.os.Process.myPid(), android.os.Process.myTid()));
75+
SingletonAImp.getInstance().invokeA(AppUtils.currentProcessName());
76+
Toast.makeText(App.getContext(), "调用A单例方法", Toast.LENGTH_SHORT).show();
77+
} catch (Exception e) {
78+
Log.e(TAG, "[invokeA][fail]", e);
79+
}
80+
}
81+
82+
@OnClick(R.id.button2)
83+
void invokeBInstance() {
84+
try {
85+
Log.i(TAG, String.format("[%s][invokeB][pid=%d][tid=%d]", AppUtils.currentProcessName(),
86+
android.os.Process.myPid(), android.os.Process.myTid()));
87+
SingletonBImp.getInstance().invokeB(AppUtils.currentProcessName());
88+
Toast.makeText(App.getContext(), "调用B单例方法", Toast.LENGTH_SHORT).show();
89+
} catch (Exception e) {
90+
Log.e(TAG, "[invokeB][fail]", e);
91+
}
92+
}
93+
94+
@OnClick(R.id.button3)
95+
void invokeCInstance() {
96+
try {
97+
Log.i(TAG, String.format("[%s][invokeC][pid=%d][tid=%d]", AppUtils.currentProcessName(),
98+
android.os.Process.myPid(), android.os.Process.myTid()));
99+
SingletonCImp.getInstance().invokeC(AppUtils.currentProcessName());
100+
Toast.makeText(App.getContext(), "调用单例C方法", Toast.LENGTH_SHORT).show();
101+
} catch (Exception e) {
102+
Log.e(TAG, "[invoke][fail]", e);
103+
}
104+
}
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processA;
2+
3+
import playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton.BaseService;
4+
5+
/**
6+
* @author SR1s
7+
*/
8+
public class ServiceA extends BaseService {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processA;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.os.*;
6+
import android.os.Process;
7+
import android.util.Log;
8+
import android.widget.Toast;
9+
10+
import playground.android.me.sr1.androidplayground.App;
11+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.utils.MainThreadUtils;
12+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.utils.ProcessUtils;
13+
import playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton.InstanceReceiver;
14+
import playground.android.me.sr1.androidplayground.toolbox.utils.AppUtils;
15+
16+
/**
17+
* @author SR1s
18+
*/
19+
public class SingletonAImp extends SingletonA.Stub {
20+
21+
public static SingletonA INSTANCE;
22+
23+
public static synchronized SingletonA getInstance() {
24+
if (ProcessUtils.isProcessA()) {
25+
if (INSTANCE == null) {
26+
INSTANCE = new SingletonAImp();
27+
}
28+
return INSTANCE;
29+
} else {
30+
if (INSTANCE == null) {
31+
/** 自发重连 */
32+
Intent intent = new Intent(App.getContext(), ServiceA.class);
33+
App.getContext().bindService(intent, new InstanceReceiver(), Context.BIND_AUTO_CREATE);
34+
}
35+
return INSTANCE;
36+
}
37+
}
38+
39+
private SingletonAImp() {}
40+
41+
public static final String TAG = "SingletonAImp";
42+
43+
@Override
44+
public void invokeA(final String aString) throws RemoteException {
45+
MainThreadUtils.runOnMainThread(new Runnable() {
46+
@Override
47+
public void run() {
48+
Toast.makeText(App.getContext(),
49+
String.format("[SingletonA]\n[调用进程:%s]\n[执行进程:%s]\n", aString, AppUtils.currentProcessName()),
50+
Toast.LENGTH_SHORT).show();
51+
}
52+
});
53+
Log.i(TAG, String.format("[%s][invokeA][pid=%d][tid=%d]",
54+
aString, android.os.Process.myPid(), Process.myTid()));
55+
}
56+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processB;
2+
3+
import android.content.Context;
4+
import android.content.Intent;
5+
import android.os.*;
6+
import android.support.v7.app.AppCompatActivity;
7+
import android.util.Log;
8+
import android.widget.Button;
9+
import android.widget.TextView;
10+
import android.widget.Toast;
11+
12+
import butterknife.Bind;
13+
import butterknife.ButterKnife;
14+
import butterknife.OnClick;
15+
import playground.android.me.sr1.androidplayground.App;
16+
import playground.android.me.sr1.androidplayground.R;
17+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processA.ServiceA;
18+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processA.SingletonAImp;
19+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processC.ActivityC;
20+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processC.ServiceC;
21+
import playground.android.me.sr1.androidplayground.sample.mutilprocess.processC.SingletonCImp;
22+
import playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton.InstanceReceiver;
23+
import playground.android.me.sr1.androidplayground.toolbox.utils.AppUtils;
24+
25+
/**
26+
* @author SR1s
27+
*/
28+
public class ActivityB extends AppCompatActivity {
29+
30+
private static String TAG = "ActivityB";
31+
32+
@Bind(R.id.textView1) TextView mTextView1;
33+
34+
@Bind(R.id.button0) Button mBtn0;
35+
36+
@Bind(R.id.button1) Button mBtn1;
37+
38+
@Bind(R.id.button2) Button mBtn2;
39+
40+
@Bind(R.id.button3) Button mBtn3;
41+
42+
@Override
43+
protected void onCreate(Bundle savedInstanceState) {
44+
super.onCreate(savedInstanceState);
45+
setContentView(R.layout.activity_abc);
46+
ButterKnife.bind(this);
47+
48+
mTextView1.setText("这里是进程B");
49+
mBtn0.setText("启动进程C");
50+
mBtn1.setText("调用主进程A的方法)");
51+
mBtn2.setText("调用本进程B的方法");
52+
mBtn3.setText("调用其他进程C的方法");
53+
54+
/** 把其他进程的单例绑定过来 */
55+
bindService(ServiceA.class);
56+
bindService(ServiceC.class);
57+
}
58+
59+
void bindService(Class<?> clz) {
60+
Intent intent = new Intent(this, clz);
61+
bindService(intent, new InstanceReceiver(), Context.BIND_AUTO_CREATE);
62+
}
63+
64+
@OnClick(R.id.button0)
65+
void startActivty() {
66+
Intent intent = new Intent(this, ActivityC.class);
67+
startActivity(intent);
68+
}
69+
70+
@OnClick(R.id.button1)
71+
void invokeAInstance() {
72+
try {
73+
Log.i(TAG, String.format("[%s][invokeA][pid=%d][tid=%d]", AppUtils.currentProcessName(),
74+
android.os.Process.myPid(), android.os.Process.myTid()));
75+
SingletonAImp.getInstance().invokeA(AppUtils.currentProcessName());
76+
Toast.makeText(App.getContext(), "调用A单例方法", Toast.LENGTH_SHORT).show();
77+
} catch (Exception e) {
78+
Log.e(TAG, "[invokeA][fail]", e);
79+
}
80+
}
81+
82+
@OnClick(R.id.button2)
83+
void invokeBInstance() {
84+
try {
85+
Log.i(TAG, String.format("[%s][invokeB][pid=%d][tid=%d]", AppUtils.currentProcessName(),
86+
android.os.Process.myPid(), android.os.Process.myTid()));
87+
SingletonBImp.getInstance().invokeB(AppUtils.currentProcessName());
88+
Toast.makeText(App.getContext(), "调用B单例方法", Toast.LENGTH_SHORT).show();
89+
} catch (Exception e) {
90+
Log.e(TAG, "[invokeB][fail]", e);
91+
}
92+
}
93+
94+
@OnClick(R.id.button3)
95+
void invokeCInstance() {
96+
try {
97+
Log.i(TAG, String.format("[%s][invokeC][pid=%d][tid=%d]", AppUtils.currentProcessName(),
98+
android.os.Process.myPid(), android.os.Process.myTid()));
99+
SingletonCImp.getInstance().invokeC(AppUtils.currentProcessName());
100+
Toast.makeText(App.getContext(), "调用单例C方法", Toast.LENGTH_SHORT).show();
101+
} catch (Exception e) {
102+
Log.e(TAG, "[invoke][fail]", e);
103+
}
104+
}
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package playground.android.me.sr1.androidplayground.sample.mutilprocess.processB;
2+
3+
import playground.android.me.sr1.androidplayground.toolbox.component.mutilprocess.singleton.BaseService;
4+
5+
/**
6+
* @author SR1s
7+
*/
8+
public class ServiceB extends BaseService {}

0 commit comments

Comments
 (0)
Please sign in to comment.