6

別のプロセスで実行されているリモート サービスを持つアプリケーションがあります。

<service android:name=".MyService" android:process=":remote"/>

Application クラスも使用しています。

<application android:label="@string/app_name" android:name=".MyApplication" ...

このようなことはできますか?

public class MyApplication extends Application {

    public MyApplication() {
        if (isRemoteService()) {
            setupLog("remoteservice.log");
        } else {
            setupLog("application.log");
        }
    }

プロセス名を取得して、それを使用してリモート サービスにいるかメイン アプリにいるかを検出できると考えていますが、プロセス名を取得する方法がわかりません。から PID を取得できますが、android.os.Process.myPID()あまり役に立ちません。

4

4 に答える 4

7

たとえば、メイン プロセスにいるかどうかを確認する場合は、次のようにアプリケーションにコードを記述できます。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        //...code here will be execute in every process...
        if (isMainProcess()) {
            //...code here will be execute only in main process
        }
        super.onCreate();
    }

    // your package name is the same with your main process name
    private boolean isMainProcess() {
        return getPackageName().equals(getProcessName());
    }

    // you can use this method to get current process name, you will get
    // name like "com.package.name"(main process name) or "com.package.name:remote"
    private String getProcessName() {
        int mypid = android.os.Process.myPid();
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> infos = manager.getRunningAppProcesses();
        for(RunningAppProcessInfo info : infos) {
            if (info.pid == mypid) {
                return info.processName;
            }
        }
        // may never return null
        return null;
    }
}
于 2016-03-28T04:42:18.693 に答える
1

間接的な解決策を提供できます:

それぞれの StartUp メソッド内で、システム プロパティを設定します。

System.setProperty("PROCESS_TYPE","SERVICE");
System.setProperty("PROCESS_TYPE","RECEIVER");
System.setProperty("PROCESS_TYPE","ACTIVITY");

プロパティは静的で、プロセスから分離されており、どこからでもアクセスできます。追加の利点は、Logback などのロギング フレームワークで直接使用できることです。

于 2013-04-06T19:03:29.620 に答える
1

私は同様の問題を抱えていましたが、これが私がしたことです。

MyServiceMyActivityには共通部分MyEngineがありますが、これら 2 つのケースでは動作が少し異なるはずです。

異なる点の 1 つはセットアップですが、このセットアップはクラスMyServiceとで行われますMyActivity

アクティビティとサービスで異なるもう 1 つのことは、リスナーを介して行われます。インターフェイスをMyEngine定義し、そのインターフェイスのさまざまな実装をエンジンに提供します。MyEngine.ListenerMyServiceMyActivity

したがって、ブール値を渡したい場合は、次の 2 つの方法が可能です。

// Method 1: different initialization
class MyEngine {
    MyEngine(boolean isService) { ... }
}
class MyActivity extends Activity {
    private MyEngine = new MyEngine(false);
    ...
}
class MyService extends Service {
    private MyEngine = new MyEngine(true);
    ...
}

// Method 2: callbacks
class MyEngine {
    interface Listener {
        boolean isService();
    }
    private Listener mListener;
    MyEngine(Listener listener) { mListener = listener; }
}
class MyActivity extends Activity {
    private mListener = new MyEngine.Listener() {
        boolean isService() { return false; }
    }
    private MyEngine = new MyEngine(mListener);
    ...
}
class MyService extends Service {
    private mListener = new MyEngine.Listener() {
        boolean isService() { return true; }
    }
    private MyEngine = new MyEngine(mListener);
    ...
}

ノート。

  1. 上記の例で使用されているブール値は、実際には役に立ちません。たとえば、別のログ ファイル名を使用する場合は、ブール値ではなくファイル名を渡す方が適切です。2 つの異なるアクションを実行する場合は、2 つの実装を持つ 1 つのリスナー関数を使用することをお勧めします。

  2. もちろん、 a を渡してまたはContextの子であるかどうかを確認したり、現在のプロセスの名前を取得したりすることもできますが、これらは Android 固有の実装の詳細であり、絶対に必要でない限り依存しない方がよいでしょう。ActivityService

于 2013-05-28T11:50:27.593 に答える
1

Google のWorkManager lib から取得したコードを使用しています。これを書いている時点では、 にありGreedyScheduler.javaます。そのようにメソッドを定義getProcessName()した:

    @Nullable
    private String getProcessName() {
        if (SDK_INT >= 28) {
            return Application.getProcessName();
        }

        // Try using ActivityThread to determine the current process name.
        try {
            Class<?> activityThread = Class.forName(
                    "android.app.ActivityThread",
                    false,
                    GreedyScheduler.class.getClassLoader());
            final Object packageName;
            if (SDK_INT >= 18) {
                Method currentProcessName = activityThread.getDeclaredMethod("currentProcessName");
                currentProcessName.setAccessible(true);
                packageName = currentProcessName.invoke(null);
            } else {
                Method getActivityThread = activityThread.getDeclaredMethod(
                        "currentActivityThread");
                getActivityThread.setAccessible(true);
                Method getProcessName = activityThread.getDeclaredMethod("getProcessName");
                getProcessName.setAccessible(true);
                packageName = getProcessName.invoke(getActivityThread.invoke(null));
            }
            if (packageName instanceof String) {
                return (String) packageName;
            }
        } catch (Throwable exception) {
            Log.d("TAG", "Unable to check ActivityThread for processName", exception);
        }

        // Fallback to the most expensive way
        int pid = Process.myPid();
        ActivityManager am =
                (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);

        if (am != null) {
            List<ActivityManager.RunningAppProcessInfo> processes = am.getRunningAppProcesses();
            if (processes != null && !processes.isEmpty()) {
                for (ActivityManager.RunningAppProcessInfo process : processes) {
                    if (process.pid == pid) {
                        return process.processName;
                    }
                }
            }
        }

        return null;
    }

次に、呼び出し側で:

    boolean isMainProcess() {
        return TextUtils.equals(mContext.getPackageName(), getProcessName());
    }
于 2020-10-12T15:33:26.820 に答える