一个常见的场景:处于UI的View层点击了下载的Button按钮,然后转入到Presenter层,此时当然会在Presenter层里面触发Model层的下载任务代码模块。但是,View层UI控件需要实时显示下载进度怎么办?
要知道只有Model层才真正知道下载进度,Presenter层对进度一无所知。对于这种情况有两种方法把
需要在Presenter层的函数里面,当在调用Model层的下载请求时候实现一个回调函数(假设它叫做Callback),然后在Presenter层的匿名Callback内部类实现里面实时调用View的进度更新即可。如代码:
架构建模:
package zhangphil.demo;
public interface Model<T, R> {
R request(T t, Callback callback);
}
package zhangphil.demo;
public interface View<T> {
void progress(T t);
}
package zhangphil.demo;
public interface Presenter<T> {
void action(T t);
void progress(int i);
}
package zhangphil.demo;
public interface Callback<T,R> {
R call(T t);
}
模型实现:
package zhangphil.demo;
import android.os.SystemClock;
import java.util.concurrent.CompletableFuture;
public class LoadModel implements Model<String, Object> {
private Presenter presenter;
public LoadModel(Presenter presenter) {
this.presenter = presenter;
}
@Override
public Object request(String s, final Callback callback) {
CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
SystemClock.sleep(100);
if (callback != null)
callback.call(i);
}
}
});
return null;
}
}
package zhangphil.demo;
public interface LoadView<T> extends View<Integer> {
void status(T t);
}
package zhangphil.demo;
public class LoadPresenter implements Presenter<String> {
private LoadView view;
private Model model;
public LoadPresenter(LoadView view) {
this.view = view;
model = new LoadModel(this);
}
@Override
public void action(String s) {
model.request(s, new Callback<Integer, Object>() {
@Override
public Object call(Integer i) {
updateProgress(i);
return null;
}
});
}
@Override
public void progress(int i) {
}
private void updateProgress(int i) {
view.progress(i);
if (i > 0 && i < 100) {
view.status("下载中...");
}
if (i == 100) {
view.status("下载完成");
}
}
}
测试:
package zhangphil.demo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements LoadView<String> {
private TextView progress,status;
private Button button;
private Presenter presenter;
private AppCompatActivity activity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
setContentView(R.layout.activity_main);
progress = findViewById(R.id.progress);
button = findViewById(R.id.button);
status=findViewById(R.id.status);
presenter = new LoadPresenter(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.action("https://zhangphil.blog.csdn.net/");
}
});
}
@Override
public void status(final String s) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
status.setText(s);
}
});
}
@Override
public void progress(final Integer i) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
progress.setText(i + " %");
}
});
}
}
另外一种方案,不使用Callback回调,直接在Model层调用Presenter层预设的更新函数,在此函数里面进一步触发View的更新,如:
package zhangphil.demo;
public interface Model<T, R> {
R request(T t);
}
package zhangphil.demo;
public interface View<T> {
void progress(T t);
}
package zhangphil.demo;
public interface Presenter<T> {
void action(T t);
void progress(int i);
}
框架模型实现:
package zhangphil.demo;
import android.os.SystemClock;
import java.util.concurrent.CompletableFuture;
public class LoadModel implements Model<String, Object> {
private Presenter presenter;
public LoadModel(Presenter presenter) {
this.presenter = presenter;
}
/**
* 模拟下载。
*
* @param s
* @return
*/
@Override
public Object request(String s) {
CompletableFuture.runAsync(new Runnable() {
@Override
public void run() {
for (int i = 0; i <= 100; i++) {
SystemClock.sleep(100);
presenter.progress(i);
}
}
});
return null;
}
}
package zhangphil.demo;
public interface LoadView<T> extends View<Integer> {
void status(T t);
}
package zhangphil.demo;
public class LoadPresenter implements Presenter<String> {
private LoadView view;
private Model model;
public LoadPresenter(LoadView view) {
this.view = view;
model = new LoadModel(this);
}
@Override
public void action(String s) {
model.request(s);
}
@Override
public void progress(int i) {
updateProgress(i);
}
private void updateProgress(int i) {
view.progress(i);
if (i > 0 && i < 100) {
view.status("下载中...");
}
if (i == 100) {
view.status("下载完成");
}
}
}
测试:
package zhangphil.demo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity implements LoadView<String> {
private TextView progress, status;
private Button button;
private Presenter presenter;
private AppCompatActivity activity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
setContentView(R.layout.activity_main);
progress = findViewById(R.id.progress);
button = findViewById(R.id.button);
status = findViewById(R.id.status);
presenter = new LoadPresenter(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.action("https://zhangphil.blog.csdn.net/");
}
});
}
@Override
public void status(final String s) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
status.setText(s);
}
});
}
@Override
public void progress(final Integer i) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
progress.setText(i + " %");
}
});
}
}