Java平台原生Proxy代理把MVP中普通函数接口切换调度到Android UI主线程

Java平台原生Proxy代理把MVP中普通函数接口切换调度到Android UI主线程

在Android开发者,这种线程切换的需求场景很常见,比如在后台普通的Java线程展开了一项耗时的操作(比如下载一个大文件),下载时候需要实时更新下载进度。普通Java线程不能直接接触Android UI主线程的View,因此在后台获得下载进度后,需要切换到Android UI主线程把数值设置到Android View中。这次线程切换的场景在Android的MVP架构设计中必然成为一个问题,因为在MVP中,当M层数据完成后,经过P层设置到V层,在P层中更新V的状况,必须切换到Android UI主线程。

Java平台原生的Proxy支持这种操作。基本原理是把View层的函数,通过Java的Proxy,调度切换到Android UI主线程。

V层:

package zhangphil.demo;

import android.support.annotation.MainThread;
import android.support.annotation.UiThread;

public interface UiView<T> {
    @MainThread
    @UiThread
    void onProgress(T t);
}

 

Java Proxy的代理转换:

package zhangphil.demo;

import android.support.v7.app.AppCompatActivity;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UiHandler implements InvocationHandler {
    private Object object;
    private AppCompatActivity activity;

    public UiHandler(AppCompatActivity activity, Object obj) {
        this.object = obj;
        this.activity = activity;
    }

    /**
     * 把一个普通的函数包装成运行在Android UI主线程的函数。
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     */
    @Override
    public Object invoke(Object proxy, final Method method, final Object[] args) {
        activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    Object result = method.invoke(object, args);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        //唯一的不足,不支持包装后的UiView接口返回数据。
        return null;
    }
}

 

 

P层

package zhangphil.demo;

import android.support.v7.app.AppCompatActivity;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Presenter {
    private Model model;
    private UiView viewProxy;

    public Presenter(AppCompatActivity activity, UiView v) {
        this.model = new Model(this);
        this.viewProxy = getUiViewProxy(activity, v);
    }

    public void startDownload() {
        model.download();
    }

    public void progress(int n) {
        viewProxy.onProgress(n);
    }

    /**
     * 传入一个普通的UiView,然后把UiView的接口都转化为可直接在Android UI主线程运行的接口。
     *
     * @param activity
     * @param view
     * @return
     */
    private UiView getUiViewProxy(AppCompatActivity activity, UiView view) {
        InvocationHandler handler = new UiHandler(activity, view);
        UiView proxy = (UiView) Proxy.newProxyInstance(view.getClass().getClassLoader(), view.getClass().getInterfaces(), handler);
        return proxy;
    }
}

 

 

M层:

package zhangphil.demo;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class Model {
    private Presenter presenter;

    public Model(Presenter p) {
        this.presenter = p;
    }

    /**
     * 模拟一个在普通Java线程中的耗时下载任务。
     * 
     */
    public void download() {
        CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    presenter.progress(i);

                    try {
                        TimeUnit.SECONDS.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}

 

 

测试:

package zhangphil.demo;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements UiView<Integer> {
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.text);

        Presenter presenter = new Presenter(this, this);
        presenter.startDownload();
    }

    @Override
    public void onProgress(Integer integer) {
        textView.setText(String.valueOf(integer));
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangphil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值