在单独的应用程序中将 worker 的意图发送到 activity
Sending intents from a worker to an activity in a separate app
我有一个应用程序可以根据用户操作写入其本地存储;说的内容需要
被转发到另一个应用程序。
我的做法:
- 使用指向本地存储的文件观察器创建工作线程
- 从主应用程序启动 worker activity
- 工作线程创建并发送具有更新内容的意图到单独的应用程序
我不确定(也许需要打开一个单独的问题),但是在 activity 中创建的所有内容都会在 activity 停止时被销毁,对吗?这意味着添加工人,文件观察者的生命周期与他们定义的 activity 相同,对吗?
代码:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String FILE_OBSERVER_WORK_NAME = "file_observer_work";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "Creating file observer worker");
WorkManager workManager = WorkManager.getInstance(getApplication());
WorkContinuation continuation = workManager
.beginUniqueWork(FILE_OBSERVER_WORK_NAME,
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.from(APIWorker.class));
Log.i(TAG, "Starting worker");
continuation.enqueue();
final Button button = findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i(TAG, "Button clicked!");
String stuffToWriteToFile = getStuff();
String cwd = getApplicationInfo().dataDir;
String stuffFilePath= cwd + File.separator + "stuff.json";
PrintWriter stuffFile= null;
try {
stuffFile = new PrintWriter(stuffFilePath, "UTF-8");
stuffFile.println(stuffToWriteToFile);
stuffFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
}
@Override
public void onResume(){
super.onResume();
// start worker here?
}
@Override
public void onStart() {
super.onStart();
// start worker here?
}
}
APIWorker.java:
public class APIWorker 扩展 Worker {
public APIWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
private static final String TAG = APIWorker.class.getSimpleName();
@NonNull
@Override
public Result doWork() {
Context applicationContext = getApplicationContext();
Log.d(TAG, "Observing stuff file");
FileObserver fileObserver = new FileObserver(cwd) {
@Override
public void onEvent(int event, @Nullable String path) {
if(event == FileObserver.CREATE ||
event == FileObserver.MODIFY) {
String cwd = applicationContext.getApplicationInfo().dataDir;
String stuffFilePath = cwd + File.separator + "stuff.json";
String fileContents;
File observedFile = new File(stuffFilePath);
long length = observedFile.length();
if (length < 1 || length > Integer.MAX_VALUE) {
fileContents = "";
Log.w(TAG, "Empty file: " + observedFile);
} else {
try (FileReader in = new FileReader(observedFile)) {
char[] content = new char[(int)length];
int numRead = in.read(content);
if (numRead != length) {
Log.e(TAG, "Incomplete read of " + observedFile +
". Read chars " + numRead + " of " + length);
}
fileContents = new String(content, 0, numRead);
Log.d(TAG, "Sending intent ");
String packageName = "com.cam.differentapp";
Intent sendIntent = applicationContext.getPackageManager().
getLaunchIntentForPackage(packageName);
if (sendIntent == null) {
// Bring user to the market or let them choose an app?
sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.setData(Uri.parse("market://details?id=" + packageName));
}
// sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, fileContents);
sendIntent.setType("application/json");
applicationContext.startActivity(sendIntent);
Log.d(TAG, "Intent sent ");
}
catch (Exception ex) {
Log.e(TAG, "Failed to read file " + path, ex);
fileContents = "";
}
}
}
}
};
fileObserver.startWatching();
return null;
}
}
查看文档:
https://developer.android.com/guide/components/activities/background-starts
对于何时可以从后台启动活动有限制,但也有例外,即:
The app has a visible window, such as an activity in the foreground.
意思是(我认为?)只要用户与应用程序 (MainActivity) 交互,后台工作程序就应该 运行,对吗?如果 activity 是 paused/destroyed 就停止了,对吗?
如果您有后台处理不需要用户交互(显示或用户输入),通常您会使用 Service
。如果您的应用程序在前台,那么您的 Service
可以使用 startActivity()
.
启动其他活动
我觉得你的架构很奇怪。您使用的是 Worker
,它的生命周期最长为 10 分钟。您正在启动 Worker
,然后创建一个 FileObserver
来检测 creation/modification 个文件。然后它读取文件并启动另一个 Activity
。这是一种非常复杂和迂回的做事方式。我怀疑你能否使它可靠地工作。
您的 Activity
正在将数据写入文件系统。它可以在写入文件后调用一个方法(在后台线程上),然后将数据转发到另一个 Activity
。这会更直接,并且移动部件更少。
我不知道 Activity
的生命周期如何影响 Worker
。我假设它们没有直接链接到 Activity
,因此不会在 Activity
暂停或销毁时停止。
我还注意到您正在主线程 (UI) 上写入文件(在您的 OnClickListener
中)。这不行,您应该在后台线程中执行文件 I/O,因为文件 I/O 可能会阻塞,而您不想阻塞主线程 (UI)。
我有一个应用程序可以根据用户操作写入其本地存储;说的内容需要 被转发到另一个应用程序。
我的做法:
- 使用指向本地存储的文件观察器创建工作线程
- 从主应用程序启动 worker activity
- 工作线程创建并发送具有更新内容的意图到单独的应用程序
我不确定(也许需要打开一个单独的问题),但是在 activity 中创建的所有内容都会在 activity 停止时被销毁,对吗?这意味着添加工人,文件观察者的生命周期与他们定义的 activity 相同,对吗?
代码:
MainActivity.java:
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final String FILE_OBSERVER_WORK_NAME = "file_observer_work";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "Creating file observer worker");
WorkManager workManager = WorkManager.getInstance(getApplication());
WorkContinuation continuation = workManager
.beginUniqueWork(FILE_OBSERVER_WORK_NAME,
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.from(APIWorker.class));
Log.i(TAG, "Starting worker");
continuation.enqueue();
final Button button = findViewById(R.id.button2);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Log.i(TAG, "Button clicked!");
String stuffToWriteToFile = getStuff();
String cwd = getApplicationInfo().dataDir;
String stuffFilePath= cwd + File.separator + "stuff.json";
PrintWriter stuffFile= null;
try {
stuffFile = new PrintWriter(stuffFilePath, "UTF-8");
stuffFile.println(stuffToWriteToFile);
stuffFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
});
}
@Override
public void onResume(){
super.onResume();
// start worker here?
}
@Override
public void onStart() {
super.onStart();
// start worker here?
}
}
APIWorker.java: public class APIWorker 扩展 Worker {
public APIWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
private static final String TAG = APIWorker.class.getSimpleName();
@NonNull
@Override
public Result doWork() {
Context applicationContext = getApplicationContext();
Log.d(TAG, "Observing stuff file");
FileObserver fileObserver = new FileObserver(cwd) {
@Override
public void onEvent(int event, @Nullable String path) {
if(event == FileObserver.CREATE ||
event == FileObserver.MODIFY) {
String cwd = applicationContext.getApplicationInfo().dataDir;
String stuffFilePath = cwd + File.separator + "stuff.json";
String fileContents;
File observedFile = new File(stuffFilePath);
long length = observedFile.length();
if (length < 1 || length > Integer.MAX_VALUE) {
fileContents = "";
Log.w(TAG, "Empty file: " + observedFile);
} else {
try (FileReader in = new FileReader(observedFile)) {
char[] content = new char[(int)length];
int numRead = in.read(content);
if (numRead != length) {
Log.e(TAG, "Incomplete read of " + observedFile +
". Read chars " + numRead + " of " + length);
}
fileContents = new String(content, 0, numRead);
Log.d(TAG, "Sending intent ");
String packageName = "com.cam.differentapp";
Intent sendIntent = applicationContext.getPackageManager().
getLaunchIntentForPackage(packageName);
if (sendIntent == null) {
// Bring user to the market or let them choose an app?
sendIntent = new Intent(Intent.ACTION_VIEW);
sendIntent.setData(Uri.parse("market://details?id=" + packageName));
}
// sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, fileContents);
sendIntent.setType("application/json");
applicationContext.startActivity(sendIntent);
Log.d(TAG, "Intent sent ");
}
catch (Exception ex) {
Log.e(TAG, "Failed to read file " + path, ex);
fileContents = "";
}
}
}
}
};
fileObserver.startWatching();
return null;
}
}
查看文档:
https://developer.android.com/guide/components/activities/background-starts
对于何时可以从后台启动活动有限制,但也有例外,即:
The app has a visible window, such as an activity in the foreground.
意思是(我认为?)只要用户与应用程序 (MainActivity) 交互,后台工作程序就应该 运行,对吗?如果 activity 是 paused/destroyed 就停止了,对吗?
如果您有后台处理不需要用户交互(显示或用户输入),通常您会使用 Service
。如果您的应用程序在前台,那么您的 Service
可以使用 startActivity()
.
我觉得你的架构很奇怪。您使用的是 Worker
,它的生命周期最长为 10 分钟。您正在启动 Worker
,然后创建一个 FileObserver
来检测 creation/modification 个文件。然后它读取文件并启动另一个 Activity
。这是一种非常复杂和迂回的做事方式。我怀疑你能否使它可靠地工作。
您的 Activity
正在将数据写入文件系统。它可以在写入文件后调用一个方法(在后台线程上),然后将数据转发到另一个 Activity
。这会更直接,并且移动部件更少。
我不知道 Activity
的生命周期如何影响 Worker
。我假设它们没有直接链接到 Activity
,因此不会在 Activity
暂停或销毁时停止。
我还注意到您正在主线程 (UI) 上写入文件(在您的 OnClickListener
中)。这不行,您应该在后台线程中执行文件 I/O,因为文件 I/O 可能会阻塞,而您不想阻塞主线程 (UI)。