为啥我在android中放入MutableLiveData后会得到Null

Posted

技术标签:

【中文标题】为啥我在android中放入MutableLiveData后会得到Null【英文标题】:Why do I get Null after I put into MutableLiveData in android为什么我在android中放入MutableLiveData后会得到Null 【发布时间】:2021-10-25 23:53:46 【问题描述】:

我尝试使用 OpenWeatherAPI 获取天气信息。

所以我使用了 Retrofit 库。

API 连接成功。

但问题是我从 OpenWeatherAPI 获得的天气数据 将数据放入 MutableLiveData 后突然变为 null。

这是代码

package wook.co.weather.models.repository;

import android.util.Log;

import androidx.lifecycle.MutableLiveData;

import java.util.List;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import wook.co.weather.interfaces.OpenWeatherAPI;
import wook.co.weather.models.dto.OpenWeather;
import wook.co.weather.models.retrofit.RetrofitService;

public class OpenWeatherRepos 
    private final String TAG = "OpenWeatherRepository";
    private final static String BASE_URL = "https://api.openweathermap.org/data/2.5/"; 
    private static OpenWeatherRepos instance;
    private Retrofit retrofit;
    private OpenWeatherAPI opwAPI;
    private MutableLiveData<OpenWeather> data;

    public static OpenWeatherRepos getInStance() 
        if(instance == null)
            instance = new OpenWeatherRepos();
        
        return instance;
    

    public MutableLiveData<OpenWeather> getWeather() 

        retrofit = new RetrofitService().getRetroInstance(BASE_URL);

        opwAPI = retrofit.create(OpenWeatherAPI.class);

        data = new MutableLiveData<OpenWeather>();
        callWeatherAPI();
        Log.i(TAG,data.getValue().toString()); //error occurs here
        return data;
    

    private void callWeatherAPI() 

        Call<OpenWeather> call = opwAPI.getWeather("seoul","this is my id","kr");

        call.enqueue(new Callback<OpenWeather>() 
            @Override
            public void onResponse(Call<OpenWeather> call, Response<OpenWeather> response) 
                OpenWeather temp = response.body();
                Log.i(TAG,"API CONNECT SUCCESS");
                if(temp != null)
                    Log.i(TAG,temp.toString());
                    data.setValue(temp);
                
            

            @Override
            public void onFailure(Call<OpenWeather> call, Throwable t) 
                Log.d(TAG,"onFailure : "+t.getMessage());
            
        );
    


这是这段代码的结果

D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
    Process: wook.co.weather, PID: 10063
    java.lang.RuntimeException: Unable to start activity ComponentInfowook.co.weather/wook.co.weather.view.MainActivity: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String wook.co.weather.models.dto.OpenWeather.toString()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String wook.co.weather.models.dto.OpenWeather.toString()' on a null object reference
        at wook.co.weather.models.repository.OpenWeatherRepos.getWeather(OpenWeatherRepos.java:46)
        at wook.co.weather.viewmodels.MainActivityViewModel.init(MainActivityViewModel.java:25)
        at wook.co.weather.view.MainActivity.onCreate(MainActivity.java:26)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
I/Process: Sending signal. PID: 10063 SIG: 9

我该如何解决这个问题??

【问题讨论】:

假设opw是一个实例字段,call.enqueue(...)是做什么的?代码是否需要等待响应? 这能回答你的问题吗? Retrofit response returning null in Android 我确实做了一个 OpenWeather 的模型类,所以我认为这不能回答我的问题@Zain call.enqueue(..) 是与api连接并获取天气信息的部分。并且代码不需要等待@AndrewS 的响应。 我更正了我的问题。请再次检查我的问题@Zain 【参考方案1】:

我相信问题出在这里:

if(temp != null)
    Log.i(TAG,temp.toString());
    data.postValue(temp);
    Log.i(TAG,data.getValue().toString());

postValue() 方法不会立即更新 LiveData 的值;而是将任务发布到最终将更新值的主线程。此处的文档:https://developer.android.com/reference/androidx/lifecycle/MutableLiveData#postValue(T)

这意味着调用postValue() 然后立即调用getValue() 将导致您收到“旧”值(在您发布新值之前),因为任务尚未完成并更新值的 LiveData。

在您的情况下,解决方法是简单地删除第二个 Log.i() 调用。您可以对其进行修改以使其正常工作,如下所示:

data.postValue(temp);
OpenWeather value = data.getValue();
if (value != null) 
    Log.i(TAG, value.toString());

但这确实没有任何好处;您已经知道 data.getValue() 此时将过时。

【讨论】:

感谢您的回答。但是这次我有另一个空问题。我已将 data.postValue() 更改为 data.setValue()。所以在那之后我试图查看里面的数据,但我遇到了同样的空问题。我已经更正了我的问题,因此您可以查看有关我的问题的更多信息。谢谢。 这基本上是同一个问题。您现在正尝试在启动异步 api 调用后立即记录 getValue() 的结果。只需删除第二个日志调用;它没有任何好处。 onResponse() 方法中使用setValue() 可能是不正确的,因为此时您不太可能在主线程上。 感谢您的回答。 null 问题解决了!!

以上是关于为啥我在android中放入MutableLiveData后会得到Null的主要内容,如果未能解决你的问题,请参考以下文章

如何访问我在预发布中放入的即时应用?

为啥我在flutter中更新http包后不能在http.post方法中放一个字符串

如何在notification中放入一个圆形的进度条

如何在整个程序中调用我的游戏循环以及在 tick() 中放入啥

Power Shell:需要在文件内容中放入文件具体名称

Laravel 8:按嵌套列对分组数组进行排序 - 我应该在 sortBy 闭包中放入啥?