从服务中的活动引用文本视图,反之亦然

Posted

技术标签:

【中文标题】从服务中的活动引用文本视图,反之亦然【英文标题】:Referencing TextViews from Activity in Service and Vice versa 【发布时间】:2021-03-29 05:12:42 【问题描述】:

我正在开发一个代码基础稳步增长的 android 应用;该应用程序的目的是扫描和处理手持设备(不是智能手机)上的二维码和条形码。它有两个包含程序逻辑主要部分的活动;因此,我想将包含用于处理扫描仪输入的功能的代码的主要部分存储在称为扫描仪服务的外部服务中,在那里实现方法并在其他活动中使用这些方法;

但是,我在使用 Context、getApplicationContext() 和服务中的 Activity 引用时遇到了一个主要问题,反之亦然;虽然我认为我已经从服务中的 Activity 中引用并初始化了 Textviews,但该应用程序继续崩溃并显示以下错误消息:

AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View android.app.Activity.findViewById(int)' on a null object reference
        at com.xxxx.ScanService.<clinit>(ScanService.java:16)

我知道这意味着什么,但我不知道如何访问视图

private static TextView content = (TextView) a.findViewById(R.id.content_detail);

以这样一种方式,我可以在服务和活动中使用它并且应用程序停止崩溃。

因此,任何提示或帮助将不胜感激,在此先感谢您。

MainDetailActivity:

package com.example.xxx_app;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.RecyclerView;
import android.view.MenuItem;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static com.xxx.ScanService.*;
import static com.xxx.SimpleItemRecyclerViewAdapter.TAGG;

/**
 * An activity representing a single Main detail screen. This
 * activity is only used on narrow width devices. On tablet-size devices,
 * item details are presented side-by-side with a list of items
 * in a @link MainListActivity.
 */
public class MainDetailActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener,
        PopupMenu.OnMenuItemClickListener 
    Context context;
    private RecyclerView recyclerView;
    private RecyclerviewAdapter recyclerviewAdapter;
    private RecyclerTouchListener touchListener;
    private ListView listView;
    public TextView textView4;
    public String code;
    public static final String TAG = "Barcode ist:" ;


    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main_detail);
        context = this;
        //TextView headerView = findViewById(R.id.txt1);
        Spinner spinner = (Spinner) findViewById(R.id.spinner);
        EditText editBarcode = (EditText) findViewById(R.id.editText);
        TextView content = (TextView) findViewById(R.id.content_detail);
        TextView editTextNumber = findViewById(R.id.editTextNumber);
        Button addBooking = findViewById(R.id.button);
        Button removeBooking = findViewById(R.id.button2);
        removeBooking.setEnabled(false);
        spinner.setOnItemSelectedListener(this);

        //String selectedItem = spinner.getSelectedItem().toString();
        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
                R.array.mockdata, android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);
        String scannedCode = getIntent().getStringExtra("scannedCode");
        Log.d(TAG, "scannedCode" + scannedCode);
        if (scannedCode != null && (content.getText().toString().equals(""))) 
          content.setText(scannedCode);
        


        Button btn = findViewById(R.id.imageView4);
        btn.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                PopupMenu popup = new PopupMenu(MainDetailActivity.this, v);
                popup.setOnMenuItemClickListener(MainDetailActivity.this);
                popup.inflate(R.menu.popup_menu);
                popup.show();
            
        );

        editBarcode.setOnKeyListener(new View.OnKeyListener() 

            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) 

                // TODO Auto-generated method stub
                String code = editBarcode.getText().toString();
                if (code.matches("")) // if(code.trim().isEmpty())
                //|| editBarcode.getText().toString() > 100 )
                
                    Log.d(TAG, "Code ist leer");
                


                if (keyCode == KeyEvent.KEYCODE_ENTER && code.length() > 0) 
                    editBarcode.setText("");
                    ScanService.checkEnteredCode(code);
                    return true;
                
                return false;
            
        );

        recyclerView = findViewById(R.id.recyclerview);
        recyclerviewAdapter = new RecyclerviewAdapter(this);
        Intent newIntent = getIntent();
        String receivedPalNo =  newIntent.getStringExtra("palNo");
        String receivedNo =  newIntent.getStringExtra("no");
        String receivedType =  newIntent.getStringExtra("type");
        String receivedRack =  newIntent.getStringExtra("rack");
        String receivedCountItems =  newIntent.getStringExtra("count_items");
        content.setText(receivedCountItems);
        RestClient.getPaletteItems(getApplicationContext(),recyclerviewAdapter,receivedPalNo);

        Log.d(TAGG,"Intent 1" + receivedPalNo);
        Log.d(TAGG, "Intent 2" + receivedNo);
        Log.d(TAGG, "Intent 3" + receivedType);
        Log.d(TAGG,"Intent 4" + receivedRack);
        Log.d(TAGG, "Intent 5" + receivedCountItems);

        final ArrayList<Items> itemList = new ArrayList<>();
        /*
        Items[] items = new Items(12345,123456, 200, 500);
        itemList.add(items);*/


        recyclerviewAdapter.setItemList((ArrayList<Items>) itemList);
        recyclerView.setAdapter(recyclerviewAdapter);

        touchListener = new RecyclerTouchListener(this,recyclerView);
        RecyclerviewAdapter finalRecyclerviewAdapter = recyclerviewAdapter;
        touchListener
                .setClickable(new RecyclerTouchListener.OnRowClickListener() 
                    @Override
                    public void onRowClicked(int position) 
                        //Toast.makeText(getApplicationContext(),itemList.get(position), Toast.LENGTH_SHORT).show();
                    

                    @Override
                    public void onIndependentViewClicked(int independentViewID, int position) 

                    
                )
                .setSwipeOptionViews(R.id.delete_task,R.id.edit_task)
                .setSwipeable(R.id.rowFG, R.id.rowBG, new RecyclerTouchListener.OnSwipeOptionsClickListener() 
                    @Override
                    public void onSwipeOptionClicked(int viewID, int position) 
                        switch (viewID)
                            case R.id.delete_task:
                                itemList.remove(position);
                                finalRecyclerviewAdapter.setItemList(itemList);
                                break;
                            case R.id.edit_task:
                                Toast.makeText(getApplicationContext(),"Edit Not Available",Toast.LENGTH_SHORT).show();
                                break;

                        
                    
                );
        recyclerView.addOnItemTouchListener(touchListener);



        class StableArrayAdapter extends ArrayAdapter<String> 

            HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();

            public StableArrayAdapter(Context context, int textViewResourceId,
                                      List<String> objects) 
                super(context, textViewResourceId, objects);
                for (int i = 0; i < objects.size(); ++i) 
                    mIdMap.put(objects.get(i), i);
                
            

            @Override
            public long getItemId(int position) 
                String item = getItem(position);
                return mIdMap.get(item);
            

            @Override
            public boolean hasStableIds() 
                return true;
            

        

    // savedInstanceState is non-null when there is fragment state
        // saved from previous configurations of this activity
        // (e.g. when rotating the screen from portrait to landscape).
        // In this case, the fragment will automatically be re-added
        // to its container so we don"t need to manually add it.
        // For more information, see the Fragments API guide at:
        //
        // http://developer.android.com/guide/components/fragments.html
        //
        String text = getIntent().getStringExtra("palNo");
        //headerView.setText(text);

        if (receivedType != null && receivedType.equals("FE")) 
            ImageView mImgView = findViewById(R.id.id_col_code);
            mImgView.setBackgroundResource(R.drawable.backgroun_blue);
        
        if (receivedType != null && receivedType.equals("UFE")) 
            ImageView mImgView = findViewById(R.id.id_col_code);
            mImgView.setBackgroundResource(R.drawable.backgroun_yellow);
        

    

    public boolean onCreateOptionsMenu(Menu menu) 
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    


    public boolean onMenuItemClick(MenuItem item) 
        Toast.makeText(this, "Selected Item: " +item.getTitle(), Toast.LENGTH_SHORT).show();
        switch (item.getItemId()) 
            case R.id.search_item:
                // do your code
                return true;
            case R.id.upload_item:
                // do your code
                return true;
            case R.id.copy_item:
                // do your code
                return true;
           /* case R.id.print_item:
                // do your code
                return true;*/
            case R.id.share_item:
                // do your code
                return true;
            /*case R.id.bookmark_item:
                // do your code
                return true;*/
            default:
                return false;
        
    


        public void newDialog(Activity activity) 
            final Dialog dialog = new Dialog(activity);
            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            dialog.setCancelable(true);
            dialog.setContentView(R.layout.sortiment_layout);
            dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));

            Button okButton = dialog.findViewById(R.id.ok);
            okButton.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View v) 
                    //Toast.makeText(getApplicationContext(),"Ok" ,Toast.LENGTH_SHORT).show();
                    dialog.dismiss();
                
            );
            Button cancelButton = dialog.findViewById(R.id.cancel);
            cancelButton.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View v) 
                    //Toast.makeText(getApplicationContext(),"Abbrechen" ,Toast.LENGTH_SHORT).show();
                    dialog.cancel();
                
            );
            dialog.show();
        

        public void showDialog(Activity activity) 
            final Dialog dialog = new Dialog(activity);
            dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
            dialog.setCancelable(true);
            dialog.setContentView(R.layout.newcustom_layout);
            dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));


            Button okButton = dialog.findViewById(R.id.ok);
            okButton.setOnClickListener(new View.OnClickListener() 
                @Override
                public void onClick(View v) 
                    //Toast.makeText(getApplicationContext(),"Ok" ,Toast.LENGTH_SHORT).show();
                    dialog.dismiss();
                
            );
            dialog.show();
        


    public void onItemSelected(AdapterView<?> parent, View view,
                               int pos, long id) 
        // An item was selected. You can retrieve the selected item using
        // parent.getItemAtPosition(pos)
    

    public void onNothingSelected(AdapterView<?> parent) 
        // Another interface callback
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        int id = item.getItemId();
        if (id == android.R.id.home) 
            // This ID represents the Home or Up button. In the case of this
            // activity, the Up button is shown. For
            // more details, see the Navigation pattern on Android Design:
            //
            // http://developer.android.com/design/patterns/navigation.html#up-vs-back
            //
            navigateUpTo(new Intent(this, MainListActivity.class));
            return true;
        
        return super.onOptionsItemSelected(item);
    

    @Override
    public void onResume() 
        super.onResume();
        recyclerView.addOnItemTouchListener(touchListener);
    

    @Override
    public void onPointerCaptureChanged(boolean hasCapture) 

    

ScanService 类:

package com.example.xxx;

import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.widget.TextView;


public class ScanService 


    private static final String TAG = "Scan Service Tag";
    private static Context mContext;
    private static Activity a = (MainDetailActivity)mContext;
    private static TextView content = (TextView) 
    a.findViewById(R.id.content_detail);
    private static TextView editTextNumber = (TextView) 
    a.findViewById(R.id.editTextNumber);

    public ScanService (Context mContext) 
        this.mContext = mContext;
    

    public static void checkEnteredCode(String code, Activity a) 
        content.setText("");

        //PSP-H1-EA-F3
        if
        (code.matches("PSP-\\pUpper\\d\\pPunct\\pUpper\\" +
                "pUpper\\pPunct\\pUpper\\pDigit")) 
            content.setText("");
            content.setText(code);
            Log.d(TAG, "xxx");

        
        if (code.matches("LF-[0-9]*")) 
            ///LF-(\d+)/gi
            content.setText("");
            content.setText(code);
            Log.d(TAG, "xxx");
        
        if (code.matches("PAL-[0-9][0-9][0-9]")) 

            content.setText("");
            content.setText(code);
            Log.d(TAG, "xxx");
        
        if (code.matches("P-[0-9][0-9][0-9]")) 

            content.setText("");
            content.setText(code);
            Log.d(TAG, "Palette");
        
        if (code.matches("[0-9][0-9][0-9][0-9].[0-9][0-9].+DB")) 
           
            if(editTextNumber == null) 
                Log.d(TAG, "xxx");
            
            else 
                editTextNumber.setText(code);
                Log.d(TAG, "xxx");
            
            Log.d(TAG, "xxx");
        
        if (code.matches("[0-9A-Z]*[0-9]*")) 
            //editBarcode.setText("");
            //editBarcode.setText(keyCode);
            Log.d(TAG, "xxx");
        
        if (code.matches("\\d13")) 
            //newDialog(MainDetailActivity.this);
            //editBarcode.setText("");
            //editBarcode.setText(keyCode);
            if(editTextNumber == null) 
                Log.d(TAG, "xxx");
            
            else 
                editTextNumber.setText(code);
                Log.d(TAG, "xxx");
            
            Log.d(TAG, "xxx");
        
        else 
            Log.d(TAG, "xxx");

        ;
        //editBarcode.setText("");
        //editBarcode.setText(code);
            /* String code = editBarcode.getText().toString();
                if (code.matches("")) // if(code.trim().isEmpty())
                //|| editBarcode.getText().toString() > 100 )
                
                    Log.d(TAG, "xxx");
                
                //
                checkEnteredCode(code);
                //editBarcode.setText("");
             return Boolean.parseBoolean(code);*/
        Log.d(TAG, code);

    

    public static void checkEnteredCode(String code) 
    

【问题讨论】:

【参考方案1】:

您无法从Service 访问任何Views! Views 属于Activity。这是错误的应用程序架构。 Service 执行后台处理(文件 I/O、网络 I/O、计算等)。 Activity 负责与用户交互(输入、显示等)。如果你的Service想把数据放到屏幕上,你就打破了职责分工。当数据发生变化时,您的 Service 应该简单地通知您的 Activity(或任何其他感兴趣的组件),然后 Activity 可以更新 View 本身。您可以通过多种方式在Service 和您的其他组件之间共享数据,包括:事件总线、发布/订阅、共享首选项、广播Intents、SQLite 数据库等。

【讨论】:

以上是关于从服务中的活动引用文本视图,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章

当我单击列表视图的操作项时,将文本从列表视图传递到另一个活动

避免静态视图引用,但启用不同的活动来修改视图

iOS - 从外部类引用活动故事板视图控制器

在活动一中选择的微调项目上,必须更改第二个活动中的文本视图

从列表视图中检索数据并将其显示在文本视图/图像视图中

如何在视图绑定中的活动中获取回收者视图当前项目文本值