在另一个活动中创建的对象在主活动中不可见

Posted

技术标签:

【中文标题】在另一个活动中创建的对象在主活动中不可见【英文标题】:Objects created in another activity are not visible in Main activity 【发布时间】:2017-12-06 18:36:19 【问题描述】:

我的代码中有两个基本类:机场和航班(出发和到达)。机场由到达航班对象列表和出发航班对象列表组成。 在我的主要活动中,我持有一个机场对象列表并在列表视图中表示它们。通过触摸列表视图对象,我启动了一个新活动,用于显示该机场对象的所有到达航班 (ActivityArrivalFlights),其中我将机场对象作为一个字段。在此活动中,有一个功能可以将到达航班添加到同一对象。我也在列表视图中表示航班,并通过数组适配器添加航班。

问题是这样的:当一个飞行对象被创建并添加到机场时,只要活动还活着,它就在那里。当 ActivityArrivalFlights 被销毁并且焦点位于主要活动上时,之前添加的航班对象不在该机场中。

这是两个活动的代码。如果我做错了什么,谁能告诉我?

public class MainActivity extends AppCompatActivity 

    private static final int FILL_AIRPORT_REQUEST = 1;
    private static final int EDIT_AIRPORT_REQUEST = 2;

    static final String EDIT_AIRPORT_OBJECT_KEY = "editable";
    static final String EDIT_AIRPORT_POSITION_KEY = "position";
    static final String SELECTED_AIRPORT_KEY = "selectedAirport";
    static final String ALL_FLIGHTS_LIST_KEY = "allFlights";

    private static final String AIRPORTS_STATE = "airportsState";

    private Button btnAddAirport;
    private ListView lvAirports;

    private ArrayList<Airport> airports;
    private ArrayAdapter<Airport> airportArrayAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        btnAddAirport = (Button) findViewById(R.id.btnAddAirport);
        lvAirports = (ListView) findViewById(R.id.lwAirports);
        btnAddAirport.setOnClickListener(this::onButtonAddAirportClick);
        lvAirports.setOnItemClickListener(this::onListViewItemClicked);


        if (savedInstanceState != null)
            airports = savedInstanceState.getParcelableArrayList(AIRPORTS_STATE);
        else
            airports = new ArrayList<>();

        airportArrayAdapter = new ArrayAdapter<>(getApplicationContext(), android.R.layout.simple_list_item_1, airports);
        lvAirports.setAdapter(airportArrayAdapter);
        lvAirports.invalidateViews();
        registerForContextMenu(lvAirports);
        if(savedInstanceState == null)
            addCodeForTesting();
    

    private void addCodeForTesting() 
         /* TEMPORARY CODE FOR TESTING*/
        Airport munich = new Airport("MunichAirport", "Munich", "MU", 1234);
        Airport skopje = new Airport("Aleksandar Veliki", "Skopje", "SK", 4321);
        skopje.addArrivalFlight(munich, new Date(), new Date());
        airportArrayAdapter.add(skopje);
        airportArrayAdapter.add(munich);
    

    private void onButtonAddAirportClick(View view)
        startActivityForResult(new Intent(this, ActivityAddAirport.class), FILL_AIRPORT_REQUEST);
    

    private void onListViewItemClicked(AdapterView parent, View view, int position, long id)
        Airport airport = airports.get(position);
        showFlightsActivity(airport);
    

    private void showFlightsActivity(Airport airport) 
        Intent intent = new Intent(this, ActivityArrivalFlights.class);
        ArrayList<Airport> filteredList = filterAirports(airports, airport);
        intent.putExtra(SELECTED_AIRPORT_KEY, airport);
        intent.putParcelableArrayListExtra(ALL_FLIGHTS_LIST_KEY, filteredList);
        startActivity(intent);
    

    private static ArrayList<Airport> filterAirports(List<Airport> original, Airport except)
        ArrayList<Airport> filtered = new ArrayList<>();
        for (Airport airport : original) 
            if(!airport.equals(except))
                filtered.add(airport);
        
        return filtered;
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
        if(requestCode == FILL_AIRPORT_REQUEST)
            if(resultCode == RESULT_OK)
                Airport airport = data.getParcelableExtra(ActivityAddAirport.AIRPORT_OBJECT_KEY);
                airportArrayAdapter.add(airport);
            
        
        else if(requestCode == EDIT_AIRPORT_REQUEST)
            if(resultCode == RESULT_OK)
                Airport editedAirport = data.getParcelableExtra(ActivityAddAirport.AIRPORT_OBJECT_KEY);
                int airportPosition = data.getIntExtra(ActivityAddAirport.AIRPORT_POSITION, 0);
                airports.remove(airportPosition);
                airports.add(airportPosition, editedAirport);
                airportArrayAdapter.notifyDataSetChanged();
                lvAirports.invalidateViews();
                Toast.makeText(this, "Airport changed", Toast.LENGTH_LONG).show();
            
        
    

    @Override
    protected void onSaveInstanceState(Bundle outState) 
        super.onSaveInstanceState(outState);
        outState.putParcelableArrayList(AIRPORTS_STATE, airports);
    

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) 
        super.onCreateContextMenu(menu, v, menuInfo);
        getMenuInflater().inflate(R.menu.main_menu_context_menu, menu);
    

    @Override
    public boolean onContextItemSelected(MenuItem item) 
        if(item.getItemId() == R.id.context_edit) 
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
            editListViewItem(info.position);
            return true;
        
        else if (item.getItemId() == R.id.context_delete)
            AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
            deleteListViewItem(info.position);
            return true;
        
        return super.onContextItemSelected(item);
    

    private void editListViewItem(int position) 
        Intent editIntent = new Intent(this, ActivityAddAirport.class);
        Airport changingAirport = (Airport) lvAirports.getItemAtPosition(position);
        editIntent.putExtra(EDIT_AIRPORT_OBJECT_KEY, changingAirport);
        editIntent.putExtra(EDIT_AIRPORT_POSITION_KEY, position);
        startActivityForResult(editIntent, EDIT_AIRPORT_REQUEST);
    

    private void deleteListViewItem(int position)
        airportArrayAdapter.remove(airports.get(position));
    


public class ActivityArrivalFlights extends AppCompatActivity 

    private static final int FILL_ARRIVAL_FLIGHT_REQUEST = 1;

    static final String AIRPORT_THIS_KEY = "thisAirport";
    static final String ALL_AIRPORTS_EXCEPT_THIS_KEY = "allExceptThis";

    private Airport airport;
    private ArrayList<Airport> allAirportsExceptThis;

    private ArrayAdapter<ArrivalFlight> lvArrivalsAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_arrival_flights);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbarAF);
        setSupportActionBar(toolbar);

        FloatingActionButton fabAddArrival = (FloatingActionButton) findViewById(R.id.fabAddArrival);
        fabAddArrival.setOnClickListener(this::onFabAddArrivalClick);

        Intent intent = getIntent();
        airport = intent.getParcelableExtra(MainActivity.SELECTED_AIRPORT_KEY);
        allAirportsExceptThis = intent.getParcelableArrayListExtra(MainActivity.ALL_FLIGHTS_LIST_KEY);

        setUpListView();
    

    private void setUpListView()
        ListView lvArrivals = (ListView) findViewById(R.id.lvArrivals);
        lvArrivalsAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, airport.getArrivals());
        lvArrivals.setAdapter(lvArrivalsAdapter);
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.menu_choose_flights, menu);
        return super.onCreateOptionsMenu(menu);
    

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) 
        MenuItem arrivals = menu.findItem(R.id.arrivals);
        MenuItem departures = menu.findItem(R.id.departures);
        if (arrivals.isEnabled())
            arrivals.setEnabled(false);
        if (!departures.isEnabled())
            departures.setEnabled(true);
        return super.onPrepareOptionsMenu(menu);
    



    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        if(item.getItemId() == R.id.departures)
            Intent intent = new Intent(this, ActivityDepartureFlights.class);
            intent.putExtra(MainActivity.SELECTED_AIRPORT_KEY, airport);
            startActivity(intent);
            return true;
        
        return super.onOptionsItemSelected(item);
    

    private void onFabAddArrivalClick(View view)
        Intent intent = new Intent(this, ActivityAddArrivalFlight.class);
        intent.putExtra(AIRPORT_THIS_KEY, airport);
        intent.putParcelableArrayListExtra(ALL_AIRPORTS_EXCEPT_THIS_KEY, allAirportsExceptThis);
        startActivityForResult(intent, FILL_ARRIVAL_FLIGHT_REQUEST);
    

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) 
        if(requestCode == FILL_ARRIVAL_FLIGHT_REQUEST)
            if(resultCode == RESULT_OK)
               ArrivalFlight flight = data.getParcelableExtra(ActivityAddArrivalFlight.FILLED_FLIGHT_ENTRY);
               lvArrivalsAdapter.add(flight);
               Toast.makeText(this, "Flight added!\n" + airport.getArrivals().size(), Toast.LENGTH_SHORT).show();
            
        
    

【问题讨论】:

【参考方案1】:

我认为没有理由在 ActivityArrivalFlights 销毁后 MainActivity 将使用新航班进行更新。

您没有向 MainActivity 返回任何结果(来自 ActivityArrivalFlights) 为了将数据返回到 MainActivity,在您返回已添加的航班的情况下,您需要执行以下操作:

在 MainActivity 中:

final int NEW_FLIGHT_RESULT = 5; // Just an identifier number / what ever you want;

// Start ActivityArrivalFlights for result (which you are not doing):

private void showFlightsActivity(Airport airport) 
    Intent intent = new Intent(this, ActivityArrivalFlights.class);
    ArrayList<Airport> filteredList = filterAirports(airports, airport);
    intent.putExtra(SELECTED_AIRPORT_KEY, airport);
    intent.putParcelableArrayListExtra(ALL_FLIGHTS_LIST_KEY, filteredList);
    startActivityForResult(intent, NEW_FLIGHT_RESULT);  // Here start for result



@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
    if(requestCode == NEW_FLIGHT_RESULT)
        if(resultCode == RESULT_OK) 
            Flight f = data.getParcelableExtra("NEW_FILGHT_DATA");
            // Here add the new flight to the airport object you are maintaining !!!
        
     

来自 ActivityArrivalFlights:

@Override
public void onBackPressed() 

    // You can wrap this with: If(newFlightsAdded())  ... :
    Intent output = new Intent();
    output.putExtra("NEW_FILGHT_DATA", newFlight);
    setResult(RESULT_OK, output);
    finish();

这就是我猜你错过的整个概念,我的代码又快又脏,所以清理它并按照你的意愿使用。

注意!!! : 使用意图在活动之间传递对象(intent.putExtra(...) 将传递一个对象的副本而不是同一个对象)。

【讨论】:

谢谢,但这不是我想要的。我知道这个概念。这个想法是,我将机场对象的引用传递给 ActivityArrivalFlights 活动。对同一个对象所做的任何更改都应该在任何地方可见,因为它是同一个对象,我只是传递它的引用。让我思考的是为什么这些变化在主要活动中不可见。 @DraganApostolski intent.putExtra 传递对象的副本而不是对象本身,这意味着更改 intent.getExtra 接收到的对象上的任何内容都会更改对象副本。您可以通过将机场设为静态(仅用于测试)来检查对象是否实际上是副本,并将 putExtra 中传递的对象与原始静态对象(在 MainActivity 中定义)进行比较,比较参考如下: airports == intentAirports 。因此,正如我上面提到的那样,好的做法是返回新航班。 我真的没有看这个方法的文档,我真的以为intent.putExtra传递了一个引用。谢谢,现在知道了,我会找到解决办法的。

以上是关于在另一个活动中创建的对象在主活动中不可见的主要内容,如果未能解决你的问题,请参考以下文章

ListView 在活动 onCreate 方法或按钮 onClickListener 方法中不更新

朋友不会被邀请参加 Facebook 中创建的活动

查看 Google 日历中创建的每个活动的会议链接

滚动视图中的最后一个视图在我的选项卡活动中不可见

允许在 UWP 中创建的 PWA 在最小化时不处于非活动状态

使用 xCode 7 的新构建在 iTunes Connect 的活动选项卡中不可见