ReactNative ReactContext#getCurrentActivity NullPointerException

版权声明:本文为博主原创文章,未经博主允许不得转载的哦=。= https://blog.csdn.net/qq_15602635/article/details/81572082

ReactNative ReactContext#getCurrentActivity解析

ReactNative与原生混合开发时,原生经常需要为ReactNative提供组件。提供组件时getCurrentActivity使用不当容易造成NullPointerException。

以下是一个简单的示例分析:

// 随便一个自定义view,继承自LinearLayout
class CustomView extends LinearLayout{

public CustomView(Context context) {
super(context);
}
}

// 提供给Rn的ViewManager
public class CustomViewManager extends SimpleViewManager<CustomView>{

@Override
public String getName() {
return "CustomView";
}

@Override
protected CustomView createViewInstance(ThemedReactContext reactContext) {
CustomView customView = new CustomView(reactContext.getCurrentActivity());
return customView;
}
}

测试发现会有偶现的Crash。
在LinearLayout中的context.obtainStyledAttributes()时出现NullPointerException。

public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);

final TypedArray a = context.obtainStyledAttributes(
attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes);
...
}

这个Context来自于reactContext.getCurrentActivity(),也就是CurrentActivity为空。

为什么getCurrentActivity会为空

查看ReactContext类

private @Nullable WeakReference<Activity> mCurrentActivity;
public @Nullable Activity getCurrentActivity() {
if (mCurrentActivity == null) {
return null;
}
return mCurrentActivity.get();
}
...

可以看到getCurrentActivity()从mCurrentActivity软引用获取Activity,如果软引用为空则为空。

那么mCurrentActivity什么时机赋值,继续看

public void onHostResume(@Nullable Activity activity) {
...
mCurrentActivity = new WeakReference(activity);
...
}

public void onNewIntent(@Nullable Activity activity, Intent intent) {
...
mCurrentActivity = new WeakReference(activity);
...
}

由此可见在Activity的OnCreate()生命周期mCurrentActivity可能为空。

获取Context和Activity的正确姿势

现在的问题就变成了自定义View需要Context或者Activity,而创建时mCurrentActivity可能为空。

再看创建ViewManager的过程,createViewInstance方法的参数ThemedReactContext就是一个Context。所以创建自定义View可以直接使用:

public class CustomViewManager extends SimpleViewManager<CustomView>{

@Override
protected CustomView createViewInstance(ThemedReactContext reactContext) {
CustomView customView = new CustomView(reactContext
return customView;
}
}

自定义组件如何获取Context?

直接调用View的getContext()方法即可,获取的Context就是ThemedReactContext。

自定义组件如何获取Activity?

先通过View的getContext()获取ThemedReactContext,然后获取Activity,工具方法如下:

@javax.annotation.Nullable
public static Activity getActivity(Context context) {
if (context instanceof Activity) {
return (Activity) context;
}

if (context instanceof ReactContext) {
ReactContext reactContext = ((ReactContext) context);
return reactContext.getCurrentActivity();
}
return null;
}

为什么设计getCurrentActivity()

1、ReactNative的package/module/viewmanager希望与Activity解耦,能在不同的Activity情况下使用。
2、getCurrentActivity()的返回值会随当前Activity变化而变化,因此不希望外部调用持有getCurrentActivity()的返回值,一旦持有就可能造成内存泄漏。

参考

ReactNative issues/8661
ReactNative issues/9310
ReactNative commit/96e412

阅读更多
换一批

NullPointerException??

09-17

import javax.swing.*;rnimport java.awt.*;rnimport java.awt.event.*;rnpublic class SimpleChatRoom extends JFrame implements ActionListenerrnrn JPanel chatPanel;rn rn JTextArea displayArea;rn rn JTextField inputText;rn rn JButton startButton,stopButton;rn rn JLabel statusLabel;rn rn public SimpleChatRoom()rn rn setGUIComponent();rn rn getContentPane().setLayout(new BorderLayout());rn rn rn getContentPane().add(chatPanel,BorderLayout.CENTER);rn rn rn getContentPane().add(statusLabel,BorderLayout.SOUTH);rn pack();rn setVisible(true);rn rn rn public void setGUIComponent()rn rn chatPanel=new JPanel();rn rn rn chatPanel.setLayout(new GridBagLayout());rn rn rn GridBagConstraints constraints=new GridBagConstraints();rn rn rn displayArea=new JTextArea(10,20);rn rn rn rn displayArea.setEditable(false);rn rn rn constraints.gridx=0;rn rn constraints.gridy=0;rn rn constraints.gridwidth=7;rn rn constraints.gridheight=4;rn rn chatPanel.add(new JScrollPane(displayArea),constraints);rn rn inputText=new JTextField(20);rn rn inputText.setEditable(false);rn rn rn inputText.addActionListener(this);rn rn rn rn constraints.gridwidth=7;rn rn constraints.gridheight=1;rn rn constraints.gridy=5;rn rn chatPanel.add(startButton,constraints);rn rn rn stopButton=new JButton("forbidden");rn rn stopButton.setEnabled(false);rn rn rn stopButton.addActionListener(this);rn rn constraints.gridwidth=3;rn rn constraints.gridheight=1;rn rn constraints.gridx=GridBagConstraints.RELATIVE;rn rn chatPanel.add(stopButton,constraints);rn rn statusLabel=new JLabel("the initive");rn rn rn public void actionPerformed(ActionEvent e)rn rn if(e.getSource()==startButton)rn rn startButton.setEnabled(true);rn rn stopButton.setEnabled(false);rn rn rn rn inputText.setEditable(true);rn rn statusLabel.setText("the beginer");rn rn else if(e.getSource()==stopButton)rn rn startButton.setEnabled(true);rn rn inputText.setEditable(false);rn rn statusLabel.setText("the forbidden");rn rn else if(e.getSource()==inputText)rn rn displayArea.append(inputText.getText()+"\n");rn rn inputText.setText("");rn rn rn rn rn public static void main (String args[])rn rn SimpleChatRoom scr=new SimpleChatRoom();rn rn scr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);rn rn rn rn rn

nullpointerexception

09-17

2007-9-17 11:46:53 org.apache.catalina.core.StandardWrapperValve invokern严重: Servlet.service() for servlet NewServlet threw exceptionrnjava.lang.NullPointerExceptionrn at DBConn.route(DBConn.java:66)rn at NewServlet.processRequest(NewServlet.java:51)rn at NewServlet.doGet(NewServlet.java:81)rn at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)rn at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)rn at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)rn at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)rn at org.netbeans.modules.web.monitor.server.MonitorFilter.doFilter(MonitorFilter.java:368)rn at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)rn at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)rn at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)rn at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)rn at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)rn at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)rn at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)rn at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)rn at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)rn at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)rn at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)rn at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)rn at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)rn at java.lang.Thread.run(Thread.java:595)rn

没有更多推荐了,返回首页