片段中的线程只调用一次
Thread in Fragment only called once
我正在尝试实现一个线程,该线程在 Fragment
中更改 UI 上的某些内容。因此我需要参考主线程。
根据我的研究,我发现以下代码应该可以解决问题:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(menuActivity, "HELLO", Toast.LENGTH_SHORT).show();
}
});
这只会执行一次,即使 Looper
通常应该保持线程活动。尝试在 Handler
中调用 Looper.prepare()
将导致 RuntimeException
,因为每个线程只允许一个 Looper
。
编辑:我的目标是每秒永久更新一个 TextView。
我也试过以下方法:
Thread t = new Thread() {
@Override
public void run() {
menuActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
System.out.println("-----------TEST");
}
});
}
};
t.start();
但这也只会执行一次。
我也读过 this article,但我想我的第一段代码只是文章中所示代码的较短版本。
这些代码片段中我的错误可能在哪里?
这个问题不是重复的,因为我提供了一个完全不同的代码片段,这是我遇到的问题的基础。此外,此线程中对 Looper 进行了更深入的解释。
This will execute only once though, even if the Looper
should normally
keep the thread alive.
您似乎对 Looper
的 purpose/functionality 感到困惑。 Looper
是 保持线程活动。如果主线程没有保持活动状态,您的应用程序将退出。 Looper
确实 而不是 ,但是,提供重复执行 Runnable
s posted 到 Handler
/Thread
它与之关联。每个 Runnable
只执行一次。如果要多次执行相同的Runnable
,则必须多次post。例如:
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
Runnable doToast = new Runnable() {
@Override
public void run() {
Toast.makeText(menuActivity, "HELLO", Toast.LENGTH_SHORT).show();
}
});
mainThreadHandler.post(doToast); // Queue the first execution of the code in the Runnable's run() method.
mainThreadHandler.post(doToast); // Queue the second execution of the code in the Runnable's run() method.
我了解到您想在 1 秒后重复更新文本视图。这是我刚写的一个简单的演示。
样机画面
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text_view_money"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:layout_marginTop="30dp"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="startUpdateTextViewMoney"
android:text="Start" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="stopUpdateTextViewMoney"
android:text="Stop" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<EditText
android:id="@+id/edit_text_money"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="setMoney"
android:text="SET MONEY" />
</LinearLayout>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_TEXT_MONEY_INTERVAL = 1000;
private Handler mMainHandler;
private TextView mTextViewMoney;
private TextView mEditTextMoney;
private String money;
private Runnable mUpdateTextViewMoneyTask = new Runnable() {
@Override
public void run() {
if (TextUtils.isEmpty(money)) {
mTextViewMoney.setText(String.valueOf(SystemClock.elapsedRealtime()));
} else {
mTextViewMoney.setText(money);
money = null;
}
mMainHandler.postDelayed(this, UPDATE_TEXT_MONEY_INTERVAL);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextViewMoney = findViewById(R.id.text_view_money);
mEditTextMoney = findViewById(R.id.edit_text_money);
mMainHandler = new Handler(Looper.getMainLooper());
}
@Override
protected void onStop() {
super.onStop();
stopUpdateTextViewMoney(null);
}
public void startUpdateTextViewMoney(View view) {
mMainHandler.post(mUpdateTextViewMoneyTask);
}
public void stopUpdateTextViewMoney(View view) {
mMainHandler.removeCallbacks(mUpdateTextViewMoneyTask);
}
public void setMoney(View view) {
String money = mEditTextMoney.getText().toString();
this.money = !TextUtils.isEmpty(money) ? money : "";
}
}
- 当用户按下“开始”按钮时,应用将每秒开始更新文本视图
- 当用户按下停止按钮时,应用将停止更新文本视图。
- 如果用户想设置一个新的货币以在下次显示,只需输入编辑文本然后按设置货币。
我正在尝试实现一个线程,该线程在 Fragment
中更改 UI 上的某些内容。因此我需要参考主线程。
根据我的研究,我发现以下代码应该可以解决问题:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
Toast.makeText(menuActivity, "HELLO", Toast.LENGTH_SHORT).show();
}
});
这只会执行一次,即使 Looper
通常应该保持线程活动。尝试在 Handler
中调用 Looper.prepare()
将导致 RuntimeException
,因为每个线程只允许一个 Looper
。
编辑:我的目标是每秒永久更新一个 TextView。
我也试过以下方法:
Thread t = new Thread() {
@Override
public void run() {
menuActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
System.out.println("-----------TEST");
}
});
}
};
t.start();
但这也只会执行一次。
我也读过 this article,但我想我的第一段代码只是文章中所示代码的较短版本。
这些代码片段中我的错误可能在哪里?
这个问题不是重复的,因为我提供了一个完全不同的代码片段,这是我遇到的问题的基础。此外,此线程中对 Looper 进行了更深入的解释。
This will execute only once though, even if the
Looper
should normally keep the thread alive.
您似乎对 Looper
的 purpose/functionality 感到困惑。 Looper
是 保持线程活动。如果主线程没有保持活动状态,您的应用程序将退出。 Looper
确实 而不是 ,但是,提供重复执行 Runnable
s posted 到 Handler
/Thread
它与之关联。每个 Runnable
只执行一次。如果要多次执行相同的Runnable
,则必须多次post。例如:
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
Runnable doToast = new Runnable() {
@Override
public void run() {
Toast.makeText(menuActivity, "HELLO", Toast.LENGTH_SHORT).show();
}
});
mainThreadHandler.post(doToast); // Queue the first execution of the code in the Runnable's run() method.
mainThreadHandler.post(doToast); // Queue the second execution of the code in the Runnable's run() method.
我了解到您想在 1 秒后重复更新文本视图。这是我刚写的一个简单的演示。
样机画面
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/text_view_money"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:textColor="@android:color/black"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:layout_marginTop="30dp"
android:orientation="horizontal">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="startUpdateTextViewMoney"
android:text="Start" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="stopUpdateTextViewMoney"
android:text="Stop" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<EditText
android:id="@+id/edit_text_money"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="setMoney"
android:text="SET MONEY" />
</LinearLayout>
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int UPDATE_TEXT_MONEY_INTERVAL = 1000;
private Handler mMainHandler;
private TextView mTextViewMoney;
private TextView mEditTextMoney;
private String money;
private Runnable mUpdateTextViewMoneyTask = new Runnable() {
@Override
public void run() {
if (TextUtils.isEmpty(money)) {
mTextViewMoney.setText(String.valueOf(SystemClock.elapsedRealtime()));
} else {
mTextViewMoney.setText(money);
money = null;
}
mMainHandler.postDelayed(this, UPDATE_TEXT_MONEY_INTERVAL);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextViewMoney = findViewById(R.id.text_view_money);
mEditTextMoney = findViewById(R.id.edit_text_money);
mMainHandler = new Handler(Looper.getMainLooper());
}
@Override
protected void onStop() {
super.onStop();
stopUpdateTextViewMoney(null);
}
public void startUpdateTextViewMoney(View view) {
mMainHandler.post(mUpdateTextViewMoneyTask);
}
public void stopUpdateTextViewMoney(View view) {
mMainHandler.removeCallbacks(mUpdateTextViewMoneyTask);
}
public void setMoney(View view) {
String money = mEditTextMoney.getText().toString();
this.money = !TextUtils.isEmpty(money) ? money : "";
}
}
- 当用户按下“开始”按钮时,应用将每秒开始更新文本视图
- 当用户按下停止按钮时,应用将停止更新文本视图。
- 如果用户想设置一个新的货币以在下次显示,只需输入编辑文本然后按设置货币。