欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

详解android webView独立进程通讯方式

程序员文章站 2023-12-15 15:26:46
为什么需要将webview放在独立进程 webview 加载网页的时候可能占用大量内存,导致应用程序oom。 webview 在访问结束的时候可以直接杀死该...

为什么需要将webview放在独立进程

  • webview 加载网页的时候可能占用大量内存,导致应用程序oom。
  • webview 在访问结束的时候可以直接杀死该进程,防止内存泄漏。
  • webview 在崩溃的时候不影响主进程。

webview独立进程需要注意什么

  • 由于进程之间内存是独立的,所以导致了appcation, 静态类需要在新的进程重新创建。
  • 内存中的数据不共享,需要跨进程通讯。

如何声明一个独立进程

在默认情况下,同一应用的所有组件都在相同的进程中运行。
在manifest中可以设置各组件 (<activity>、<service>、<receiver>、<provider>)的 android:process 属性来指定相应的进程。

跨进程的方式

在android当中提供了2种方式实现。

一种是messenger, 另一种是aidl.

  • messenger:实现相对简单,将所有请求放到消息队列中,不适合做并发处理,在大多数的场景用messenger就可以实现了。
  • aidl: 适合并发操作。直接方法调用,结构更清晰。

messenger

由于messenger是采用消息队列的方式实现,所有接受和发送的时候都需要handler协助。

服务端

public class messengerservice extends service {
  
  public static final int get_data = 1;
  public static final int set_data = 2;
  
  messenger messenger = new messenger(new servicehandler());
  messenger replymessenger; //向客服端返回信息
  public messengerservice() {
  }
  
  @override
  public ibinder onbind(intent intent) {
    return messenger.getbinder();
  }
  
  
  class servicehandler extends handler {
    @override
    public void handlemessage(message msg) {
      replymessenger = msg.replyto;
      switch (msg.what) {
        case get_data:
          //客服端向服务端请求数据
          if (replymessenger != null) {
            bundle bundle = new bundle();
            bundle.putstring("str", customdata.getinstance().getdata());
            message message = message.obtain(null, 1);
            message.setdata(bundle);
            try {
              replymessenger.send(message);
            } catch (remoteexception e) {
              e.printstacktrace();
            }
          }
          break;
        case set_data:
          //客服端向服务端请求更新数据
          customdata.getinstance().setdata(msg.getdata().getstring("str"));
          break;
      }
    }
  }
}

客服端:

public class messengerclientactivity extends appcompatactivity {
  
  private webview mwebview;
  private button mgetdatbtn;
  private button msetdatbtn;
  
  public static void startthis(context context, string url) {
    intent intent = new intent(context, messengerclientactivity.class);
    intent.putextra("url", url);
    context.startactivity(intent);
  }
  
  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_messenger_client);
    mwebview = (webview) findviewbyid(r.id.webview);
    mgetdatbtn = (button) findviewbyid(r.id.get_data_btn);
    msetdatbtn = (button) findviewbyid(r.id.set_data_btn);
        
    websettings websettings = mwebview.getsettings();
    websettings.setjavascriptenabled(true);
    websettings.setjavascriptcanopenwindowsautomatically(true);
    websettings.setsupportzoom(false);
    websettings.setbuiltinzoomcontrols(false);
    websettings.setallowfileaccess(true);
    websettings.setdatabaseenabled(true);
    websettings.setdomstorageenabled(true);
    websettings.setgeolocationenabled(true);
    websettings.setappcacheenabled(true);
    websettings.setappcachepath(getapplicationcontext().getcachedir().getpath());
    websettings.setdefaulttextencodingname("utf-8");
    //屏幕自适应
    websettings.setusewideviewport(true);
    websettings.setloadwithoverviewmode(true);
    if (build.version.sdk_int >= build.version_codes.kitkat) {
      websettings.setcachemode(websettings.load_cache_else_network);
    } else {
      websettings.setcachemode(websettings.load_default);
    }
    if (build.version.sdk_int >= build.version_codes.honeycomb) {
      websettings.setdisplayzoomcontrols(false);
    }
    if (build.version.sdk_int >= build.version_codes.kitkat) {
      websettings.setloadsimagesautomatically(true);
    } else {
      websettings.setloadsimagesautomatically(false);
    }
    
    mwebview.setscrollbarstyle(webview.scrollbars_inside_overlay);
    mwebview.sethorizontalscrollbarenabled(false);
    mwebview.sethorizontalfadingedgeenabled(false);
    mwebview.setverticalfadingedgeenabled(false);
    
    string url = "http://www.jianshu.com/";
    mwebview.loadurl(url);

    mgetdatbtn.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view v) {
        getdata();
      }
    });
    
    msetdatbtn.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view v) {
        setdata();
      }
    });
  }
  
  messenger messenger;
  messenger messengerreply = new messenger(new handler() {
    @override
    public void handlemessage(message msg) {
      switch (msg.what) {
        case messengerservice.get_data:
          mgetdatbtn.settext("" + msg.getdata().get("str"));
          break;
      }
    }
  });
  boolean mbound;
  serviceconnection serviceconnection = new serviceconnection() {
    @override
    public void onserviceconnected(componentname name, ibinder service) {
      messenger = new messenger(service);
      mbound = true;
    }
  
    @override
    public void onservicedisconnected(componentname name) {
      messenger = null;
      mbound = false;
    }
    
  };
  
  private void getdata() {
    if (!mbound) return;
    message message = message.obtain(null, messengerservice.get_data, 0,0);
    //用于服务端应答
    message.replyto = messengerreply;
    sendmessage(message);
  }
  
  private void setdata() {
    if (!mbound) return;
    message message = message.obtain(null, messengerservice.set_data, 0,0);
    sendmessage(message);
  }
  
  private void sendmessage(message message) {
    try {
      messenger.send(message);
    } catch (remoteexception e) {
      e.printstacktrace();
    }
  }
  
  
  @override
  protected void onstart() {
    super.onstart();
    // bind to the service
    bindservice(new intent(this, testwebservice.class), serviceconnection,
        context.bind_auto_create);
  }
  
  @override
  protected void onstop() {
    super.onstop();
    // unbind from the service
    if (mbound) {
      unbindservice(serviceconnection);
      mbound = false;
    }
  }
  
  private void destroywebview(webview webview) {
    if (webview == null)
      return;
    webview.stoploading();
    viewparent viewparent = webview.getparent();
    if (viewparent != null && viewparent instanceof viewgroup)
      ((viewgroup) viewparent).removeview(webview);
    webview.removeallviews();
    webview.destroy();
    webview = null;
  }
  
  @override
  protected void ondestroy() {
    destroywebview(mwebview);
    super.ondestroy();
  }
}

aidl

第一步:创建.aidl文件

  • aidl默认支持以下的类型:
  • java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)
  • string
  • charsequence
  • list
  • map
  • 如果需要导入自己的类型需要加入一个 import 语句(注意:导入的类需要实现parcelabel接口)

aidl文件:

interface iaidlprocess {

  //默认支持原语类型(int、long、char等等)、string、charsequence、list、map
  //自定义类型需要导入 import eebochina.com.testtechniques.testwebview.xxxclass
  //自定义类型传输一定需要是序列化对象
  string getcustomdata();

  void setcustomdata(string str);
}

服务端

public class aidlservice extends service {
  public aidlservice() {
  }
  itestprocess.stub mbinder = new itestprocess.stub() {
    @override
    public string getcustomdata() throws remoteexception {
      return customdata.getinstance().getdata();
    }
  
    @override
    public void setcustomdata(string str) throws remoteexception {
      customdata.getinstance().setdata(str);
    }
  };
  @override
  public ibinder onbind(intent intent) {
    return mbinder;
  }
}

客服端获取绑定接口

  aidlservice maidlservice;
  private serviceconnection serviceconnection = new serviceconnection() {
    @override
    public void onserviceconnected(componentname name, ibinder service) {
      maidlservice = iaidlprocess.stub.asinterface(service);
      mbound = true;
    }
    
    @override
    public void onservicedisconnected(componentname name) {
      mbound = false;
      maidlservice = null;
    }
  };

在获取了绑定接口后就可以直接和服务端通讯了。

2种通讯方式都简单的介绍了下,后面的实际应用还需要根据不同的业务进行调整。

由于aidl是方法直接调用的,从代码扩展和阅读来说比messenger要强很多。

如果有写的不好和不对的地方,希望大家可以及时指出来。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

上一篇:

下一篇: