从服务中的活动引用文本视图,反之亦然
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
访问任何View
s! View
s 属于Activity
。这是错误的应用程序架构。 Service
执行后台处理(文件 I/O、网络 I/O、计算等)。 Activity
负责与用户交互(输入、显示等)。如果你的Service
想把数据放到屏幕上,你就打破了职责分工。当数据发生变化时,您的 Service
应该简单地通知您的 Activity
(或任何其他感兴趣的组件),然后 Activity
可以更新 View
本身。您可以通过多种方式在Service
和您的其他组件之间共享数据,包括:事件总线、发布/订阅、共享首选项、广播Intent
s、SQLite 数据库等。
【讨论】:
以上是关于从服务中的活动引用文本视图,反之亦然的主要内容,如果未能解决你的问题,请参考以下文章